feat: 应用、投放、内容、工单

This commit is contained in:
uiuJun 2025-08-12 18:17:37 +08:00
parent 9ff7f84432
commit 66ab87094c
25 changed files with 1802 additions and 68 deletions

View File

@ -5,6 +5,7 @@
"build": "max build", "build": "max build",
"dev": "max dev", "dev": "max dev",
"format": "prettier --cache --write .", "format": "prettier --cache --write .",
"gencode": "node ./node_modules/.bin/gencode-ts",
"postinstall": "max setup", "postinstall": "max setup",
"setup": "max setup", "setup": "max setup",
"start": "npm run dev" "start": "npm run dev"

View File

@ -107,7 +107,7 @@ export const MyFormItems = {
return { return {
valueType: 'select', valueType: 'select',
proFieldProps: { proFieldProps: {
placeholder: `请选择${props.title}`, placeholder: `请选择`,
}, },
formItemProps: { formItemProps: {
...(props?.required ? rulesHelper.text : {}), ...(props?.required ? rulesHelper.text : {}),

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

@ -521,6 +521,32 @@ declare namespace ApiTypes {
"keywords"?: string; // 关键词 "keywords"?: string; // 关键词
}; };
} }
namespace CompanyApps {
type List = {
"name"?: string; // 模糊搜索:名称
};
type Store = {
"companies_id": number; // 机构id,[ref:companies]
"app_type": string; // 应用类型,[enum:CompanyAppsAppTypeEnum]
"module"?: string; // 模块,[enum:CompanyAppsModuleEnum]
"app_id": string; // 应用ID:微信AppID/企业微信CorpID
"app_secret": string; // 应用密钥
};
type Update = {
"id": number; // id
"companies_id": number; // 机构id,[ref:companies]
"app_type": string; // 应用类型,[enum:CompanyAppsAppTypeEnum]
"module"?: string; // 模块,[enum:CompanyAppsModuleEnum]
"app_id": string; // 应用ID:微信AppID/企业微信CorpID
"app_secret": string; // 应用密钥
};
type Show = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
namespace CompanyEmployees { namespace CompanyEmployees {
type List = { type List = {
"companies_id"?: number; // 机构ID "companies_id"?: number; // 机构ID
@ -751,6 +777,43 @@ declare namespace ApiTypes {
}; };
} }
} }
namespace HouseOrder {
namespace HouseOrderPayments {
type List = {
"house_orders_id": number; // 订单ID
"payment_no"?: string; // 模糊搜索:支付单号
"transaction_id"?: string; // 模糊搜索:交易号(微信、支付宝的单号
"third_trade_no"?: string; // 第三方交易号(如通联、乐刷)
};
type Show = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
namespace HouseOrders {
type List = {
"id"?: number; // id
"order_code"?: string; // 模糊搜索:名称
"payment_no"?: string; // 支付编号
"companies_id"?: number; // 机构ID
"full_name"?: string; // 模糊搜索:房屋名称
};
type Show = {
"id": number; // id
};
type SoftDelete = {
"id": number; // id
};
type Restore = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
}
namespace Permission { namespace Permission {
namespace SysPermissions { namespace SysPermissions {
type List = { type List = {
@ -815,4 +878,74 @@ declare namespace ApiTypes {
}; };
} }
} }
namespace WorkOrder {
namespace HouseWorkLogs {
type List = {
"house_work_orders_id": number; // 工单id,[ref:house_work_orders]
};
type Store = {
"house_work_orders_id": number; // 工单id,[ref:house_work_orders]
"status": string; // 工单状态,[enum:HouseWorkOrdersStatusEnum]
"description"?: string; // 进度描述
"attachments"?: string[]; // 附件
};
type Show = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
namespace HouseWorkOrders {
type List = {
"title"?: string; // 模糊搜索:名称
"house_name"?: string; // 模糊搜索:房屋名称
"type"?: string; // 工单类型,[enum:HouseWorkOrdersTypeEnum]
"level"?: string; // 工单优先级,[enum:HouseWorkOrdersLevelEnum]
"status"?: string; // 工单状态,[enum:HouseWorkOrdersStatusEnum]
"assign_status"?: string; // 工单分配状态,[enum:HouseWorkOrdersAssignStatusEnum]
"reporter_name"?: string; // 模糊搜索:上报人姓名
"reporter_phone"?: string; // 模糊搜索:上报人手机
};
type Store = {
"type": string; // 工单类型,[enum:HouseWorkOrdersTypeEnum]
"level": string; // 优先级,[enum:HouseWorkOrdersLevelEnum]
"title": string; // 工单标题
"content": string; // 工单内容
"reporter_name"?: string; // 上报人名称
"reporter_phone"?: string; // 上报人手机
"attachments"?: string[]; // 工单附件
"asset_houses_id": number; // 资产房屋id,[ref:asset_houses]
};
type Update = {
"id": number; // id
"type": string; // 工单类型,[enum:HouseWorkOrdersTypeEnum]
"level": string; // 优先级,[enum:HouseWorkOrdersLevelEnum]
"title": string; // 工单标题
"content": string; // 工单内容
"reporter_name"?: string; // 上报人名称
"reporter_phone"?: string; // 上报人手机
"attachments"?: string[]; // 工单附件
"asset_houses_id": number; // 资产房屋id,[ref:asset_houses]
};
type Show = {
"id": number; // id
};
type Assign = {
"id": number; // id
"assign_employees_id": number; // 处理人id,[ref:company_employees]
"assign_remark"?: string; // 分派说明
"predict_complete_at"?: Date; // 预计完成时间
};
type SoftDelete = {
"id": number; // id
};
type Restore = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
}
} }

View File

@ -280,6 +280,23 @@ export const Apis = {
return request('admin/company/companies/select', { data }); return request('admin/company/companies/select', { data });
}, },
}, },
CompanyApps: {
List(data?: ApiTypes.Company.CompanyApps.List): Promise<MyResponseType> {
return request('admin/company/company_apps/list', { data });
},
Store(data: ApiTypes.Company.CompanyApps.Store): Promise<MyResponseType> {
return request('admin/company/company_apps/store', { data });
},
Update(data: ApiTypes.Company.CompanyApps.Update): Promise<MyResponseType> {
return request('admin/company/company_apps/update', { data });
},
Show(data: ApiTypes.Company.CompanyApps.Show): Promise<MyResponseType> {
return request('admin/company/company_apps/show', { data });
},
Delete(data: ApiTypes.Company.CompanyApps.Delete): Promise<MyResponseType> {
return request('admin/company/company_apps/delete', { data });
},
},
CompanyEmployees: { CompanyEmployees: {
List(data?: ApiTypes.Company.CompanyEmployees.List): Promise<MyResponseType> { List(data?: ApiTypes.Company.CompanyEmployees.List): Promise<MyResponseType> {
return request('admin/company/company_employees/list', { data }); return request('admin/company/company_employees/list', { data });
@ -427,6 +444,36 @@ export const Apis = {
}, },
}, },
}, },
HouseOrder: {
HouseOrderPayments: {
List(data: ApiTypes.HouseOrder.HouseOrderPayments.List): Promise<MyResponseType> {
return request('admin/house_order/house_order_payments/list', { data });
},
Show(data: ApiTypes.HouseOrder.HouseOrderPayments.Show): Promise<MyResponseType> {
return request('admin/house_order/house_order_payments/show', { data });
},
Delete(data: ApiTypes.HouseOrder.HouseOrderPayments.Delete): Promise<MyResponseType> {
return request('admin/house_order/house_order_payments/delete', { data });
},
},
HouseOrders: {
List(data?: ApiTypes.HouseOrder.HouseOrders.List): Promise<MyResponseType> {
return request('admin/house_order/house_orders/list', { data });
},
Show(data: ApiTypes.HouseOrder.HouseOrders.Show): Promise<MyResponseType> {
return request('admin/house_order/house_orders/show', { data });
},
SoftDelete(data: ApiTypes.HouseOrder.HouseOrders.SoftDelete): Promise<MyResponseType> {
return request('admin/house_order/house_orders/soft_delete', { data });
},
Restore(data: ApiTypes.HouseOrder.HouseOrders.Restore): Promise<MyResponseType> {
return request('admin/house_order/house_orders/restore', { data });
},
Delete(data: ApiTypes.HouseOrder.HouseOrders.Delete): Promise<MyResponseType> {
return request('admin/house_order/house_orders/delete', { data });
},
},
},
Permission: { Permission: {
SysPermissions: { SysPermissions: {
List(data: ApiTypes.Permission.SysPermissions.List): Promise<MyResponseType> { List(data: ApiTypes.Permission.SysPermissions.List): Promise<MyResponseType> {
@ -475,4 +522,46 @@ export const Apis = {
}, },
}, },
}, },
WorkOrder: {
HouseWorkLogs: {
List(data: ApiTypes.WorkOrder.HouseWorkLogs.List): Promise<MyResponseType> {
return request('admin/work_order/house_work_logs/list', { data });
},
Store(data: ApiTypes.WorkOrder.HouseWorkLogs.Store): Promise<MyResponseType> {
return request('admin/work_order/house_work_logs/store', { data });
},
Show(data: ApiTypes.WorkOrder.HouseWorkLogs.Show): Promise<MyResponseType> {
return request('admin/work_order/house_work_logs/show', { data });
},
Delete(data: ApiTypes.WorkOrder.HouseWorkLogs.Delete): Promise<MyResponseType> {
return request('admin/work_order/house_work_logs/delete', { data });
},
},
HouseWorkOrders: {
List(data?: ApiTypes.WorkOrder.HouseWorkOrders.List): Promise<MyResponseType> {
return request('admin/work_order/house_work_orders/list', { data });
},
Store(data: ApiTypes.WorkOrder.HouseWorkOrders.Store): Promise<MyResponseType> {
return request('admin/work_order/house_work_orders/store', { data });
},
Update(data: ApiTypes.WorkOrder.HouseWorkOrders.Update): Promise<MyResponseType> {
return request('admin/work_order/house_work_orders/update', { data });
},
Show(data: ApiTypes.WorkOrder.HouseWorkOrders.Show): Promise<MyResponseType> {
return request('admin/work_order/house_work_orders/show', { data });
},
Assign(data: ApiTypes.WorkOrder.HouseWorkOrders.Assign): Promise<MyResponseType> {
return request('admin/work_order/house_work_orders/assign', { data });
},
SoftDelete(data: ApiTypes.WorkOrder.HouseWorkOrders.SoftDelete): Promise<MyResponseType> {
return request('admin/work_order/house_work_orders/soft_delete', { data });
},
Restore(data: ApiTypes.WorkOrder.HouseWorkOrders.Restore): Promise<MyResponseType> {
return request('admin/work_order/house_work_orders/restore', { data });
},
Delete(data: ApiTypes.WorkOrder.HouseWorkOrders.Delete): Promise<MyResponseType> {
return request('admin/work_order/house_work_orders/delete', { data });
},
},
},
} }

View File

@ -126,7 +126,7 @@ export const BannersTypeEnum= {
// 缓存类型 // 缓存类型
export const CacheTypeEnum= { export const CacheTypeEnum= {
'MobilePhoneVerificationCode': {"text":"手机验证码","color":"#581810","value":"MobilePhoneVerificationCode"}, 'MobilePhoneVerificationCode': {"text":"手机验证码","color":"#a6e8bc","value":"MobilePhoneVerificationCode"},
}; };
// CompaniesMerchantTypeEnum // CompaniesMerchantTypeEnum
@ -285,6 +285,37 @@ export const HouseRegistersUsagePlanEnum= {
'Commercial': {"text":"商用","color":"#f5222d","value":"Commercial"}, 'Commercial': {"text":"商用","color":"#f5222d","value":"Commercial"},
}; };
// HouseWorkOrdersAssignStatusEnum
export const HouseWorkOrdersAssignStatusEnum= {
'Unassigned': {"text":"未指派","color":"#ff0000","value":"Unassigned"},
'Assigned': {"text":"已指派","color":"#00ff00","value":"Assigned"},
};
// HouseWorkOrdersLevelEnum
export const HouseWorkOrdersLevelEnum= {
'Urgent': {"text":"紧急","color":"#ff0000","value":"Urgent"},
'High': {"text":"高","color":"#ff7f00","value":"High"},
'Normal': {"text":"普通","color":"#00cc00","value":"Normal"},
'Low': {"text":"低","color":"#999999","value":"Low"},
};
// HouseWorkOrdersStatusEnum
export const HouseWorkOrdersStatusEnum= {
'Pending': {"text":"待处理","color":"#FFA500","value":"Pending"},
'Processing': {"text":"处理中","color":"#1E90FF","value":"Processing"},
'Completed': {"text":"已完成","color":"#28A745","value":"Completed"},
'Closed': {"text":"已关闭","color":"#6C757D","value":"Closed"},
};
// HouseWorkOrdersTypeEnum
export const HouseWorkOrdersTypeEnum= {
'Maintenance': {"text":"维修","color":"#ff0000","value":"Maintenance"},
'Installation': {"text":"安装","color":"#00aaff","value":"Installation"},
'Consultation': {"text":"咨询","color":"#ffaa00","value":"Consultation"},
'Complaint': {"text":"投诉","color":"#aa00ff","value":"Complaint"},
'Other': {"text":"其它","color":"#00aa55","value":"Other"},
};
// OrganizationsTypeEnum // OrganizationsTypeEnum
export const OrganizationsTypeEnum= { export const OrganizationsTypeEnum= {
'Group': {"text":"集团","color":"#007bff","value":"Group"}, 'Group': {"text":"集团","color":"#007bff","value":"Group"},

View File

@ -2,7 +2,7 @@ import { MyPageContainer, usePageTabs } from '@/common';
import { Apis } from '@/gen/Apis'; import { Apis } from '@/gen/Apis';
import { ProCard } from '@ant-design/pro-components'; import { ProCard } from '@ant-design/pro-components';
import { useParams } from '@umijs/max'; import { useParams } from '@umijs/max';
import { Tabs } from 'antd'; import { Badge, Tabs } from 'antd';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import HouseInfo from './components/HouseInfo'; import HouseInfo from './components/HouseInfo';
import OccupantsHistory from './components/OccupantsHistory'; import OccupantsHistory from './components/OccupantsHistory';
@ -12,6 +12,7 @@ import RegistersList from './components/RegistersList';
export default function Show({ title = '房屋档案' }) { export default function Show({ title = '房屋档案' }) {
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const [data, setShow] = useState<any>({}); const [data, setShow] = useState<any>({});
const [pendingCount, setPendingCount] = useState<number>(0);
// 注册标签页 // 注册标签页
const { addTab } = usePageTabs({ const { addTab } = usePageTabs({
@ -34,8 +35,18 @@ export default function Show({ title = '房屋档案' }) {
}); });
}; };
const loadPendingCount = () => {
Apis.Archive.HouseRegisters.List({
asset_houses_id: Number(id),
status: 'Pending',
}).then((res) => {
setPendingCount(res?.meta?.total || 0);
});
};
useEffect(() => { useEffect(() => {
loadShow(); loadShow();
loadPendingCount();
}, [id]); }, [id]);
let items = [ let items = [
@ -57,10 +68,22 @@ export default function Show({ title = '房屋档案' }) {
children: <OccupantsHistory item={{ ...data, asset_houses_id: id }} />, children: <OccupantsHistory item={{ ...data, asset_houses_id: id }} />,
}, },
{ {
label: '操作记录', label: (
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<span></span>
{pendingCount > 0 && (
<Badge count={pendingCount} size="small" overflowCount={99} />
)}
</div>
),
key: '3', key: '3',
closable: false, closable: false,
children: <RegistersList item={{ ...data, asset_houses_id: id }} />, children: (
<RegistersList
item={{ ...data, asset_houses_id: id }}
reload={loadPendingCount}
/>
),
}, },
]; ];

View File

@ -12,6 +12,11 @@ export default function Index({ ...rest }) {
actionLooks?.current.reloadAndRest(); actionLooks?.current.reloadAndRest();
}, [rest.loadmore]); }, [rest.loadmore]);
const handleReload = () => {
actionLooks?.current.reload();
rest.reload?.(); // 调用父组件的reload函数更新Pending计数
};
return ( return (
<> <>
<ProTable<Record<any, any>> <ProTable<Record<any, any>>
@ -39,7 +44,6 @@ export default function Index({ ...rest }) {
); // 无数据时显示 - ); // 无数据时显示 -
}, },
search: false, search: false,
width: 200,
}, },
MyColumns.EnumTag({ MyColumns.EnumTag({
title: '类型', title: '类型',
@ -51,7 +55,6 @@ export default function Index({ ...rest }) {
dataIndex: 'status', dataIndex: 'status',
valueEnum: HouseRegistersStatusEnum, valueEnum: HouseRegistersStatusEnum,
}), }),
{ {
title: '登记时间', title: '登记时间',
dataIndex: 'created_at', dataIndex: 'created_at',
@ -69,7 +72,7 @@ export default function Index({ ...rest }) {
<Space key={index}> <Space key={index}>
<RegistersShow <RegistersShow
item={item} item={item}
reload={action?.reload} reload={handleReload}
title="查看详情" title="查看详情"
/> />
</Space> </Space>

View File

@ -14,7 +14,7 @@ import BannerCreate from './modals/BannerCreate';
import BannerShow from './modals/BannerShow'; import BannerShow from './modals/BannerShow';
import BannerUpdate from './modals/BannerUpdate'; import BannerUpdate from './modals/BannerUpdate';
export default function Index({ title = '广告内容' }) { export default function Index({ title = '投放内容' }) {
const navigate = useNavigate(); const navigate = useNavigate();
// 注册当前页面为标签页 // 注册当前页面为标签页

View File

@ -13,7 +13,7 @@ import { Space } from 'antd';
import BannerSpaceCreate from './modals/BannerSpaceCreate'; import BannerSpaceCreate from './modals/BannerSpaceCreate';
import BannerSpaceUpdate from './modals/BannerSpaceUpdate'; import BannerSpaceUpdate from './modals/BannerSpaceUpdate';
export default function Index({ title = '广告位' }) { export default function Index({ title = '投放位置' }) {
const navigate = useNavigate(); const navigate = useNavigate();
// 注册当前页面为标签页 // 注册当前页面为标签页

View File

@ -4,6 +4,7 @@ import { ProCard } from '@ant-design/pro-components';
import { useParams } from '@umijs/max'; import { useParams } from '@umijs/max';
import { Tabs } from 'antd'; import { Tabs } from 'antd';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import CompanyApps from './components/CompanyApps';
import ComponentsInfo from './components/ComponentsInfo'; import ComponentsInfo from './components/ComponentsInfo';
import Employees from './components/Employees'; import Employees from './components/Employees';
import Organizations from './components/Organizations'; import Organizations from './components/Organizations';
@ -69,6 +70,12 @@ export default function Show({ title }: { title?: string } = {}) {
closable: false, closable: false,
children: <ReceiptAccounts item={data} />, children: <ReceiptAccounts item={data} />,
}, },
{
label: '应用管理',
key: '6',
closable: false,
children: <CompanyApps item={data} />,
},
]; ];
return ( return (
<MyPageContainer title={title}> <MyPageContainer title={title}>

View File

@ -0,0 +1,88 @@
import {
MyBetaModalFormProps,
MyButtons,
MyColumns,
MyProTableProps,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { CompanyAppsAppTypeEnum, CompanyAppsModuleEnum } from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components';
import { Space } from 'antd';
import CompanyAppCreate from './modals/CompanyAppCreate';
import CompanyAppUpdate from './modals/CompanyAppUpdate';
export default function CompanyApps(props: MyBetaModalFormProps) {
return (
<>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(
{ ...params, companies_id: props?.item?.id },
sort,
Apis.Company.CompanyApps.List,
)
}
toolBarRender={(action) => [
<CompanyAppCreate
key="Create"
reload={action?.reload}
item={props?.item}
title="应用配置"
/>,
]}
search={false}
// options={false}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '应用类型',
dataIndex: 'app_type',
valueEnum: CompanyAppsAppTypeEnum,
}),
MyColumns.EnumTag({
title: '模块',
dataIndex: 'module',
valueEnum: CompanyAppsModuleEnum,
search: false,
}),
{
title: '应用ID',
dataIndex: 'app_id',
search: false,
ellipsis: true,
},
{
title: '应用密钥',
dataIndex: 'app_secret',
search: false,
ellipsis: true,
render: (text) => '***' + String(text).slice(-4),
},
MyColumns.UpdatedAt(),
// MyColumns.CreatedAt(),
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<CompanyAppUpdate
item={item}
reload={action?.reload}
title="应用配置"
/>
<MyButtons.Delete
onConfirm={() =>
Apis.Company.CompanyApps.Delete({
id: item.id,
}).then(() => action?.reload())
}
/>
</Space>
),
}),
]}
/>
</>
);
}

View File

@ -0,0 +1,90 @@
import {
MyBetaModalFormProps,
MyButtons,
MyFormItems,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { CompanyAppsAppTypeEnum, CompanyAppsModuleEnum } 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.Company.CompanyApps.Store>
{...MyModalFormProps.props}
title={`添加应用配置`}
wrapperCol={{ span: 24 }}
width="500px"
trigger={<MyButtons.Create title={`添加应用`} />}
form={form}
onOpenChange={(open: any) => {
if (open) {
form.resetFields(); // 清空表单数据
}
}}
onFinish={async (values) =>
Apis.Company.CompanyApps.Store({
...values,
companies_id: props?.item?.id,
})
.then(() => {
props.reload?.();
message.success(props.title + '成功');
return true;
})
.catch(() => false)
}
columns={[
MyFormItems.EnumRadio({
key: 'app_type',
title: '应用类型',
colProps: { span: 24 },
valueEnum: CompanyAppsAppTypeEnum,
required: true,
}),
{
name: ['app_type'],
valueType: 'dependency',
columns: ({ app_type }: any) => {
return app_type === 'MiniProgram'
? [
MyFormItems.EnumRadio({
key: 'module',
title: '模块',
colProps: { span: 24 },
valueEnum: CompanyAppsModuleEnum,
}),
]
: [];
},
},
{
key: 'app_id',
title: '应用ID',
tooltip: '微信AppID/企业微信CorpID',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
{
key: 'app_secret',
title: '应用密钥',
valueType: 'textarea',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
// {
// key: 'is_default',
// title: '是否设为默认账号',
// valueType: 'switch',
// colProps: { span: 24 },
// },
]}
/>
);
}

View File

@ -0,0 +1,83 @@
import {
MyBetaModalFormProps,
MyButtons,
MyFormItems,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { CompanyAppsAppTypeEnum, CompanyAppsModuleEnum } 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.Company.CompanyApps.Update>
{...MyModalFormProps.props}
title={`编辑应用配置`}
trigger={<MyButtons.Edit />}
wrapperCol={{ span: 24 }}
width="500px"
form={form}
key={new Date().getTime()}
onOpenChange={(open: any) => {
if (open && props.item) {
form.setFieldsValue(props.item);
}
}}
onFinish={async (values) =>
Apis.Company.CompanyApps.Update({
...values,
id: props?.item?.id,
companies_id: props?.item?.companies_id,
})
.then(() => {
props.reload?.();
message.success(props.title + '成功');
return true;
})
.catch(() => false)
}
columns={[
MyFormItems.EnumRadio({
key: 'app_type',
title: '应用类型',
colProps: { span: 24 },
valueEnum: CompanyAppsAppTypeEnum,
required: true,
}),
{
name: ['app_type'],
valueType: 'dependency',
columns: ({ app_type }: any) => {
return app_type === 'MiniProgram'
? [
MyFormItems.EnumRadio({
key: 'module',
title: '模块',
colProps: { span: 24 },
valueEnum: CompanyAppsModuleEnum,
}),
]
: [];
},
},
{
key: 'app_id',
title: '应用ID',
tooltip: '微信AppID/企业微信CorpID',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
{
key: 'app_secret',
title: '应用密钥',
valueType: 'textarea',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
]}
/>
);
}

View File

@ -1,4 +0,0 @@
export const AuditEnum = {
Approved: { text: '通过', color: '#007bff', value: 'Approved' },
Rejected: { text: '拒绝', color: '#28a745', value: 'Rejected' },
};

View File

@ -5,18 +5,12 @@ import {
usePageTabs, usePageTabs,
} from '@/common'; } from '@/common';
import { Apis } from '@/gen/Apis'; import { Apis } from '@/gen/Apis';
import { import { HouseRegistersStatusEnum, HouseRegistersTypeEnum } from '@/gen/Enums';
HouseRegistersCustomerTypeEnum,
HouseRegistersHouseStatusEnum,
HouseRegistersStatusEnum,
HouseRegistersTypeEnum,
HouseRegistersUsagePlanEnum,
} from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components';
import { Space } from 'antd'; import { Space } from 'antd';
import Audit from './modals/Audit'; import Audit from './modals/Audit';
export default function Index({ title = '房屋登记审核' }) { export default function Index({ title = '登记审核' }) {
// 注册当前页面为标签页 // 注册当前页面为标签页
usePageTabs({ usePageTabs({
tabKey: 'examine-house-registers-audit', tabKey: 'examine-house-registers-audit',
@ -36,8 +30,23 @@ export default function Index({ title = '房屋登记审核' }) {
columns={[ columns={[
MyColumns.ID(), MyColumns.ID(),
{ {
title: '房屋', title: '客户信息',
dataIndex: ['asset_house', 'full_name'], dataIndex: ['asset_house', 'full_name'],
search: {
transform: (value) => {
return { house_name: value };
},
},
},
{
title: '客户信息',
render(_, record) {
return (
record?.customer_info?.map((res: any) => res?.name).join(';') ||
'-'
); // 无数据时显示 -
},
search: false,
}, },
MyColumns.EnumTag({ MyColumns.EnumTag({
title: '类型', title: '类型',
@ -49,24 +58,6 @@ export default function Index({ title = '房屋登记审核' }) {
dataIndex: 'status', dataIndex: 'status',
valueEnum: HouseRegistersStatusEnum, valueEnum: HouseRegistersStatusEnum,
}), }),
MyColumns.EnumTag({
title: '房屋状态',
dataIndex: 'house_status',
valueEnum: HouseRegistersHouseStatusEnum,
search: false,
}),
MyColumns.EnumTag({
title: '使用计划',
dataIndex: 'usage_plan',
valueEnum: HouseRegistersUsagePlanEnum,
search: false,
}),
MyColumns.EnumTag({
title: '客户类型',
dataIndex: 'customer_type',
valueEnum: HouseRegistersCustomerTypeEnum,
search: false,
}),
MyColumns.CreatedAt(), MyColumns.CreatedAt(),
MyColumns.Option({ MyColumns.Option({
render: (_, item: any, index, action) => ( render: (_, item: any, index, action) => (

View File

@ -1,15 +1,29 @@
import { import {
MyBetaModalFormProps, MyBetaModalFormProps,
MyButtons, MyButtons,
MyColumns,
MyFormItems, MyFormItems,
MyModalFormProps, MyModalFormProps,
MyProTableProps,
renderTextHelper,
rulesHelper, rulesHelper,
} from '@/common'; } from '@/common';
import { Apis } from '@/gen/Apis'; import { Apis } from '@/gen/Apis';
import { BetaSchemaForm } from '@ant-design/pro-components'; import {
import { Form, message } from 'antd'; HouseOccupantsCardTypeEnum,
import { AuditEnum } from '../../AuditEnum'; HouseOccupantsHouseRelationEnum,
HouseRegistersHouseStatusEnum,
HouseRegistersStatusEnum,
HouseRegistersTypeEnum,
} from '@/gen/Enums';
import {
BetaSchemaForm,
ProCard,
ProDescriptions,
ProTable,
} from '@ant-design/pro-components';
import { Form, Image, message, Space } from 'antd';
export default function Update(props: MyBetaModalFormProps) { export default function Update(props: MyBetaModalFormProps) {
const [form] = Form.useForm(); const [form] = Form.useForm();
return ( return (
@ -18,7 +32,11 @@ export default function Update(props: MyBetaModalFormProps) {
title={props.title} title={props.title}
trigger={<MyButtons.Default title="审核" type="primary" />} trigger={<MyButtons.Default title="审核" type="primary" />}
wrapperCol={{ span: 24 }} wrapperCol={{ span: 24 }}
width="600px" width="1000px"
modalProps={{
bodyStyle: { maxHeight: '70vh', overflowY: 'auto' },
}}
key={new Date().getTime()}
form={form} form={form}
onFinish={async (values: any) => onFinish={async (values: any) =>
Apis.Archive.HouseRegisters.Audit({ Apis.Archive.HouseRegisters.Audit({
@ -33,11 +51,142 @@ export default function Update(props: MyBetaModalFormProps) {
.catch(() => false) .catch(() => false)
} }
columns={[ columns={[
{
// title: '登记信息',
dataIndex: 'info_display',
valueType: 'text',
renderFormItem: () => (
<Space direction="vertical" style={{ width: '100%' }}>
<ProCard title="基本信息" size="small">
<ProDescriptions bordered size="small" column={2}>
<ProDescriptions.Item label="房屋信息">
{props?.item?.asset_house?.full_name || '-'}
</ProDescriptions.Item>
<ProDescriptions.Item label="房屋状态">
<renderTextHelper.Tag
Enums={HouseRegistersHouseStatusEnum}
value={props?.item?.house_status}
/>
</ProDescriptions.Item>
<ProDescriptions.Item label="登记类型">
<renderTextHelper.Tag
Enums={HouseRegistersTypeEnum}
value={props?.item?.type}
/>
</ProDescriptions.Item>
<ProDescriptions.Item label="申请时间">
{props?.item?.created_at || '-'}
</ProDescriptions.Item>
</ProDescriptions>
</ProCard>
{props?.item?.customer_info &&
props?.item?.customer_info?.length > 0 && (
<ProCard title="客户信息" size="small">
<ProTable
{...MyProTableProps.props}
search={false}
toolBarRender={false}
pagination={false}
dataSource={props?.item?.customer_info}
rowKey={(record, index) => record?.id_card || index}
size="small"
columns={[
MyColumns.EnumTag({
title: '房客关系',
dataIndex: 'house_relation',
valueEnum: HouseOccupantsHouseRelationEnum,
width: 100,
}),
{
title: '姓名',
dataIndex: 'name',
width: 100,
},
{
title: '手机号',
dataIndex: 'phone',
width: 120,
},
MyColumns.EnumTag({
title: '证件类型',
dataIndex: 'card_type',
valueEnum: HouseOccupantsCardTypeEnum,
width: 120,
}),
{
title: '证件号码',
dataIndex: 'id_card',
width: 180,
},
{
title: '证件资料',
width: 120,
render: (_, item) => {
return (
<Space>
{item?.card_front_image?.[0] && (
<Image
height={30}
src={item?.card_front_image[0]?.url}
placeholder="正面"
/>
)}
{item?.card_back_image?.[0] && (
<Image
height={30}
src={item?.card_back_image[0]?.url}
placeholder="反面"
/>
)}
</Space>
);
},
},
]}
/>
</ProCard>
)}
{props?.item?.type === 'Delivery' &&
props?.item?.ownership_info &&
props?.item?.ownership_info?.length > 0 && (
<ProCard title="产证信息" size="small">
<Image.PreviewGroup>
<Space wrap>
{props?.item?.ownership_info?.map(
(res: any, index: number) => (
<Image
key={`${res?.name}_${index}`}
height={60}
src={res?.url || ''}
placeholder="产证资料"
/>
),
)}
</Space>
</Image.PreviewGroup>
</ProCard>
)}
</Space>
),
colProps: { span: 24 },
},
{
valueType: 'group',
// title: '审核操作',
columns: [
MyFormItems.EnumRadio({ MyFormItems.EnumRadio({
key: 'status', key: 'status',
title: '审核', title: '审核操作',
colProps: { span: 24 }, colProps: { span: 24 },
valueEnum: AuditEnum, valueEnum: () => {
let obj: any = JSON.parse(
JSON.stringify(HouseRegistersStatusEnum),
);
delete obj.Pending;
return obj;
},
required: true, required: true,
}), }),
{ {
@ -51,11 +200,14 @@ export default function Update(props: MyBetaModalFormProps) {
dataIndex: 'reason', dataIndex: 'reason',
valueType: 'textarea', valueType: 'textarea',
formItemProps: { ...rulesHelper.text }, formItemProps: { ...rulesHelper.text },
colProps: { span: 24 },
}, },
] ]
: []; : [];
}, },
}, },
],
},
]} ]}
/> />
); );

View File

@ -123,7 +123,7 @@ export default function Index({ title = '功能' }) {
}); });
}} }}
></Button> ></Button>
{/* <Create <Create
key="Create" key="Create"
reload={getData} reload={getData}
title={title} title={title}
@ -134,7 +134,7 @@ export default function Index({ title = '功能' }) {
title: '添加下级菜单', title: '添加下级菜单',
type: 'link', type: 'link',
}} }}
/> */} />
<Update <Update
item={item} item={item}
reload={getData} reload={getData}

View File

@ -15,6 +15,7 @@ export default function Create(
props: { props: {
buttonProps?: ButtonProps; buttonProps?: ButtonProps;
guardName: string; guardName: string;
item?: any;
} & MyBetaModalFormProps, } & MyBetaModalFormProps,
) { ) {
const [form] = Form.useForm(); const [form] = Form.useForm();
@ -33,6 +34,12 @@ export default function Create(
onOpenChange={(open: any) => { onOpenChange={(open: any) => {
if (open) { if (open) {
form.resetFields(); // 清空表单数据 form.resetFields(); // 清空表单数据
// 如果有传入的item设置为上级菜单
if (props.item?.id) {
form.setFieldsValue({
parent_id: props.item.id,
});
}
} }
}} }}
onFinish={async (values) => { onFinish={async (values) => {

View File

@ -0,0 +1,82 @@
import {
MyButtons,
MyFormItems,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { HouseWorkOrdersStatusEnum } from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd';
interface WorkLogsCreateProps {
workOrderId: number;
reload?: () => void;
}
export default function WorkLogsCreate({
workOrderId,
reload,
}: WorkLogsCreateProps) {
const [form] = Form.useForm();
return (
<BetaSchemaForm<ApiTypes.WorkOrder.HouseWorkLogs.Store>
{...MyModalFormProps.props}
title={`添加处理记录`}
wrapperCol={{ span: 24 }}
width="600px"
trigger={<MyButtons.Create title={`添加处理记录`} />}
onOpenChange={(open: any) => {
if (open) {
form.resetFields(); // 清空表单数据
}
}}
key={new Date().getTime()}
form={form}
onFinish={async (values) => {
try {
await Apis.WorkOrder.HouseWorkLogs.Store({
...values,
house_work_orders_id: workOrderId,
});
reload?.();
message.success('添加处理记录成功');
return true;
} catch (error) {
message.error('添加处理记录失败');
return false;
}
}}
columns={[
MyFormItems.EnumRadio({
key: 'status',
title: '工单状态',
colProps: { span: 24 },
valueEnum: HouseWorkOrdersStatusEnum,
required: true,
formItemProps: { ...rulesHelper.text },
}),
{
key: 'description',
title: '进度描述',
valueType: 'textarea',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
fieldProps: {
rows: 4,
placeholder: '请输入处理进度描述',
},
},
MyFormItems.UploadImages({
key: 'attachments',
title: '相关图片',
uploadType: 'file',
max: 5,
colProps: { span: 24 },
formItemProps: { required: false },
}),
]}
/>
);
}

View File

@ -0,0 +1,144 @@
import { MyButtons, MyColumns, MyProTableProps } from '@/common';
import { Apis } from '@/gen/Apis';
import { HouseWorkOrdersStatusEnum } from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components';
import { Image, Space } from 'antd';
import { useEffect, useRef } from 'react';
import WorkLogsCreate from './WorkLogsCreate';
interface WorkLogsListProps {
workOrderId: number;
reload?: () => void;
}
export default function WorkLogsList({
workOrderId,
reload,
}: WorkLogsListProps) {
const actionRef = useRef<any>();
useEffect(() => {
actionRef?.current?.reload();
}, [workOrderId]);
return (
<>
<ProTable<Record<any, any>>
{...MyProTableProps.props}
actionRef={actionRef}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
house_work_orders_id: workOrderId,
},
sort,
Apis.WorkOrder.HouseWorkLogs.List,
)
}
toolBarRender={(action) => [
<WorkLogsCreate
key="CreateWorkLog"
workOrderId={workOrderId}
reload={() => {
action?.reload();
reload?.();
}}
/>,
]}
search={false}
pagination={{
pageSize: 10,
showSizeChanger: false,
}}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '工单状态',
dataIndex: 'status',
valueEnum: HouseWorkOrdersStatusEnum,
search: false,
}),
{
title: '进度描述',
dataIndex: 'description',
search: false,
ellipsis: true,
},
{
title: '附件',
dataIndex: 'attachments',
search: false,
render: (_, record) => {
if (
!Array.isArray(record.attachments) ||
record.attachments.length === 0
) {
return '无附件';
}
return (
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
{record.attachments.map((item: any, index: number) => {
if (item.type && item.type.includes('image')) {
return (
<Image
key={index}
width={80}
height={60}
src={item.url}
style={{
marginRight: 8,
marginBottom: 8,
objectFit: 'cover',
}}
/>
);
} else if (item.type && item.type.includes('video')) {
return (
<video
key={index}
width={80}
height={60}
controls
style={{
marginRight: 8,
marginBottom: 8,
objectFit: 'cover',
}}
src={item.url}
/>
);
}
return null;
})}
</div>
);
},
},
{
title: '创建时间',
dataIndex: 'created_at',
valueType: 'dateTime',
search: false,
width: 160,
},
MyColumns.UpdatedAt(),
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<MyButtons.Delete
onConfirm={() =>
Apis.WorkOrder.HouseWorkLogs.Delete({
id: item.id,
}).then(() => action?.reload())
}
/>
</Space>
),
}),
]}
/>
</>
);
}

View File

@ -0,0 +1,137 @@
import {
MyButtons,
MyColumns,
MyPageContainer,
MyProTableProps,
usePageTabs,
} from '@/common';
import { Apis } from '@/gen/Apis';
import {
HouseWorkOrdersAssignStatusEnum,
HouseWorkOrdersLevelEnum,
HouseWorkOrdersStatusEnum,
HouseWorkOrdersTypeEnum,
} from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max';
import { Space } from 'antd';
import WorkOrderAssign from './modals/WorkOrderAssign';
import WorkOrderCreate from './modals/WorkOrderCreate';
import WorkOrderShow from './modals/WorkOrderShow';
import WorkOrderUpdate from './modals/WorkOrderUpdate';
export default function Index({ title = '工单管理' }) {
const navigate = useNavigate();
// 注册当前页面为标签页
usePageTabs({
tabKey: 'work_order',
tabLabel: title,
});
return (
<MyPageContainer
title={title}
enableTabs={true}
tabKey="work_order"
tabLabel={title}
>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(
params,
sort,
Apis.WorkOrder.HouseWorkOrders.List,
)
}
toolBarRender={(action) => [
<WorkOrderCreate
key="Create"
reload={action?.reload}
title={title}
/>,
]}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '工单状态',
dataIndex: 'status',
valueEnum: HouseWorkOrdersStatusEnum,
}),
{
title: '房屋信息',
dataIndex: ['asset_house', 'full_name'],
search: false,
ellipsis: true,
},
MyColumns.EnumTag({
title: '工单类型',
dataIndex: 'type',
valueEnum: HouseWorkOrdersTypeEnum,
}),
MyColumns.EnumTag({
title: '优先级',
dataIndex: 'level',
valueEnum: HouseWorkOrdersLevelEnum,
}),
MyColumns.EnumTag({
title: '分配状态',
dataIndex: 'assign_status',
valueEnum: HouseWorkOrdersAssignStatusEnum,
}),
{
title: '工单标题',
dataIndex: 'title',
ellipsis: true,
},
{
title: '处理人',
dataIndex: ['assign_employee', 'name'],
search: false,
render: (_, record) => {
return `${record?.assign_employee?.name || ''}-${
record?.assign_employee?.phone || ''
}`;
},
},
MyColumns.CreatedAt(),
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<WorkOrderShow
item={item}
title="详情"
reload={action?.reload}
/>
{item.status !== 'Completed' && (
<WorkOrderUpdate
item={item}
reload={action?.reload}
title={title}
/>
)}
{item.assign_status === 'Unassigned' && (
<WorkOrderAssign
item={item}
reload={action?.reload}
title="指派"
/>
)}
<MyButtons.Delete
onConfirm={() =>
Apis.WorkOrder.HouseWorkOrders.SoftDelete({
id: item.id,
}).then(() => action?.reload())
}
/>
</Space>
),
}),
]}
/>
</MyPageContainer>
);
}

View File

@ -0,0 +1,79 @@
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 WorkOrderAssign(
props: MyBetaModalFormProps & { item: any },
) {
const [form] = Form.useForm();
return (
<BetaSchemaForm<ApiTypes.WorkOrder.HouseWorkOrders.Assign>
{...MyModalFormProps.props}
title={`派发工单`}
wrapperCol={{ span: 24 }}
width="500px"
trigger={<MyButtons.Edit title={`派发`} />}
key={new Date().getTime()}
form={form}
request={async () => {
const res = await Apis.WorkOrder.HouseWorkOrders.Show({
id: props.item.id,
});
return {
title: res.data.title,
assign_employee_id: res.data.assign_employee_id,
};
}}
onFinish={async (values) =>
Apis.WorkOrder.HouseWorkOrders.Assign({
...values,
id: props.item.id,
})
.then(() => {
props.reload?.();
message.success('指派工单成功');
return true;
})
.catch(() => false)
}
columns={[
{
key: 'title',
title: '工单标题',
colProps: { span: 24 },
readonly: true,
fieldProps: {
disabled: true,
},
},
Selects?.Employees({
title: '选择处理人',
key: 'assign_employees_id',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
params: {
companies_id: props.item.companies_id,
},
required: true,
}),
{
key: 'assign_remark',
title: '指派备注',
valueType: 'textarea',
colProps: { span: 24 },
fieldProps: {
rows: 3,
placeholder: '请输入指派备注(可选)',
},
},
]}
/>
);
}

View File

@ -0,0 +1,161 @@
import {
MyBetaModalFormProps,
MyButtons,
MyFormItems,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis';
import { HouseWorkOrdersLevelEnum, HouseWorkOrdersTypeEnum } from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd';
export default function WorkOrderCreate(props: MyBetaModalFormProps) {
const [form] = Form.useForm();
return (
<BetaSchemaForm<ApiTypes.WorkOrder.HouseWorkOrders.Store>
{...MyModalFormProps.props}
title={`创建工单`}
wrapperCol={{ span: 24 }}
width="600px"
trigger={<MyButtons.Create title={`创建工单`} />}
onOpenChange={(open: any) => {
if (open) {
form.resetFields(); // 清空表单数据
}
}}
key={new Date().getTime()}
form={form}
onFinish={async (values) =>
Apis.WorkOrder.HouseWorkOrders.Store(values)
.then(() => {
props.reload?.();
message.success('创建工单成功');
return true;
})
.catch(() => false)
}
columns={[
MyFormItems.EnumRadio({
key: 'type',
title: '工单类型',
colProps: { span: 24 },
valueEnum: HouseWorkOrdersTypeEnum,
required: true,
}),
{
key: 'title',
title: '工单标题',
colProps: { span: 18 },
formItemProps: { ...rulesHelper.text },
},
MyFormItems.EnumSelect({
key: 'level',
title: '优先级',
colProps: { span: 6 },
valueEnum: HouseWorkOrdersLevelEnum,
required: true,
}),
{
key: 'content',
title: '工单描述',
valueType: 'textarea',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
fieldProps: {
placeholder: '请详细描述工单内容',
},
},
{
valueType: 'dependency',
name: ['asset_projects_id', 'asset_buildings_id', 'asset_units_id'],
columns: ({
asset_projects_id,
asset_buildings_id,
asset_units_id,
}) => {
return [
{
valueType: 'group',
columns: [
Selects?.AssetProjects({
title: '依次选择项目',
key: 'asset_projects_id',
colProps: { span: 6 },
formItemProps: { ...rulesHelper.text },
}),
Selects?.AssetBuildings({
key: 'asset_buildings_id',
title: '楼栋',
params: {
asset_projects_id: asset_projects_id,
},
colProps: { span: 6 },
formItemProps: { ...rulesHelper.number },
fieldProps: {
showSearch: true,
onChange: () => {
form.setFieldsValue({
asset_units_id: undefined,
asset_floors_id: undefined,
});
},
},
}),
Selects?.AssetUnits({
key: 'asset_units_id',
title: '单元',
params: {
asset_projects_id: asset_projects_id,
asset_buildings_id: asset_buildings_id,
},
colProps: { span: 6 },
formItemProps: { ...rulesHelper.number },
}),
Selects?.AssetHouses({
title: '房屋',
key: 'asset_houses_id',
params: {
asset_projects_id: asset_projects_id,
asset_buildings_id: asset_buildings_id,
asset_units_id: asset_units_id,
},
formItemProps: { ...rulesHelper.text },
colProps: { span: 6 },
}),
],
},
];
},
},
MyFormItems.UploadImages({
key: 'attachments',
title: '相关图片',
uploadType: 'file',
max: 5,
colProps: { span: 24 },
formItemProps: { required: false },
}),
{
key: 'reporter_name',
title: '上报人姓名',
colProps: { span: 12 },
},
{
key: 'reporter_phone',
title: '上报人手机',
formItemProps: { ...rulesHelper.phone },
colProps: { span: 12 },
fieldProps: {
placeholder: '请输入手机号码',
maxLength: 11,
minLength: 11,
},
},
]}
/>
);
}

View File

@ -0,0 +1,262 @@
import { MyButtons } from '@/common';
import { Apis } from '@/gen/Apis';
import {
HouseWorkOrdersAssignStatusEnum,
HouseWorkOrdersLevelEnum,
HouseWorkOrdersStatusEnum,
HouseWorkOrdersTypeEnum,
} from '@/gen/Enums';
import { ProDescriptions } from '@ant-design/pro-components';
import { Divider, Image, Modal, Space, Tag } from 'antd';
import { useState } from 'react';
import WorkLogsList from '../components/WorkLogsLIst';
import WorkOrderAssign from './WorkOrderAssign';
interface WorkOrderShowProps {
item: any;
title?: string;
reload?: () => void;
}
export default function WorkOrderShow({
item,
title = '工单详情',
reload,
}: WorkOrderShowProps) {
const [open, setOpen] = useState(false);
const [data, setData] = useState<any>(null);
const handleOpen = async () => {
try {
const res = await Apis.WorkOrder.HouseWorkOrders.Show({ id: item.id });
setData(res.data);
setOpen(true);
} catch (error) {
console.error('获取工单详情失败:', error);
}
};
return (
<>
<MyButtons.Default onClick={handleOpen} title={title} />
<Modal
title={title}
open={open}
onCancel={() => setOpen(false)}
footer={null}
width={800}
>
{data && (
<>
<ProDescriptions
column={2}
dataSource={data}
columns={[
{
title: '房屋名称',
dataIndex: ['asset_house', 'full_name'],
span: 2,
},
{
title: '工单标题',
dataIndex: 'title',
span: 1,
},
{
title: 'ID',
dataIndex: 'id',
span: 1,
},
{
title: '工单描述',
dataIndex: 'content',
span: 2,
},
{
title: '工单类型',
dataIndex: 'type',
span: 1,
render: (_, record) => (
<Tag color="blue">
{HouseWorkOrdersTypeEnum[
record.type as keyof typeof HouseWorkOrdersTypeEnum
]?.text || record.type}
</Tag>
),
},
{
title: '优先级',
dataIndex: 'level',
span: 1,
render: (_, record) => {
const levelConfig =
HouseWorkOrdersLevelEnum[
record.level as keyof typeof HouseWorkOrdersLevelEnum
];
const color =
record.level === 'High'
? 'red'
: record.level === 'Medium'
? 'orange'
: 'green';
return (
<Tag color={color}>
{levelConfig?.text || record.level}
</Tag>
);
},
},
{
title: '工单状态',
dataIndex: 'status',
span: 1,
render: (_, record) => {
const statusConfig =
HouseWorkOrdersStatusEnum[
record.status as keyof typeof HouseWorkOrdersStatusEnum
];
const color =
record.status === 'Completed'
? 'green'
: record.status === 'InProgress'
? 'blue'
: 'default';
return (
<Tag color={color}>
{statusConfig?.text || record.status}
</Tag>
);
},
},
{
title: '分配状态',
dataIndex: 'assign_status',
span: 1,
render: (_, record) => {
const assignConfig =
HouseWorkOrdersAssignStatusEnum[
record.assign_status as keyof typeof HouseWorkOrdersAssignStatusEnum
];
const color =
record.assign_status === 'Assigned' ? 'green' : 'orange';
return (
<Tag color={color}>
{assignConfig?.text || record.assign_status}
</Tag>
);
},
},
{
title: '上报人',
dataIndex: 'reporter_name',
span: 1,
render: (_, record) => {
return `${record?.reporter_name || ''}-${
record?.reporter_phone || ''
}`;
},
},
{
title: '处理人',
dataIndex: 'assign_employee_name',
span: 1,
render: (_, record) => {
const assigneeInfo = record?.assign_employee
? `${record.assign_employee.name || ''}-${
record.assign_employee.phone || ''
}`
: '未分配';
return (
<Space>
<span>{assigneeInfo}</span>
<WorkOrderAssign
item={item}
reload={handleOpen}
title="重新分配"
/>
</Space>
);
},
},
{
title: '创建时间',
dataIndex: 'created_at',
span: 1,
valueType: 'dateTime',
},
{
title: '更新时间',
dataIndex: 'updated_at',
span: 1,
valueType: 'dateTime',
},
{
title: '相关附件',
dataIndex: 'attachments',
span: 2,
render: (_, record) => {
// 检查attachments是否为数组且有数据
if (
!Array.isArray(record.attachments) ||
record.attachments.length === 0
) {
return '无附件';
}
return (
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
{record.attachments.map((item: any, index: number) => {
if (item.type && item.type.includes('image')) {
return (
<Image
key={index}
width={120}
height={90}
src={item.url}
style={{
marginRight: 8,
marginBottom: 8,
objectFit: 'cover',
}}
/>
);
} else if (item.type && item.type.includes('video')) {
return (
<video
key={index}
width={120}
height={90}
controls
style={{
marginRight: 8,
marginBottom: 8,
objectFit: 'cover',
}}
src={item.url}
/>
);
}
return null;
})}
</div>
);
},
},
]}
/>
<Divider orientation="left"></Divider>
<WorkLogsList
workOrderId={data.id}
reload={() => {
handleOpen();
reload?.();
}}
/>
</>
)}
</Modal>
</>
);
}

View File

@ -0,0 +1,175 @@
import {
MyBetaModalFormProps,
MyButtons,
MyFormItems,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis';
import { HouseWorkOrdersLevelEnum, HouseWorkOrdersTypeEnum } from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd';
export default function WorkOrderUpdate(
props: MyBetaModalFormProps & { item: any },
) {
const [form] = Form.useForm();
return (
<BetaSchemaForm<ApiTypes.WorkOrder.HouseWorkOrders.Update>
{...MyModalFormProps.props}
title={`编辑工单`}
wrapperCol={{ span: 24 }}
width="600px"
key={new Date().getTime()}
trigger={<MyButtons.Edit title={`编辑`} />}
onOpenChange={(open: any) => {
if (open && props.item) {
const formValues = {
...props.item,
};
form.setFieldsValue(formValues);
}
}}
form={form}
request={async () => {
const res = await Apis.WorkOrder.HouseWorkOrders.Show({
id: props.item.id,
});
return res.data;
}}
onFinish={async (values) =>
Apis.WorkOrder.HouseWorkOrders.Update({
...values,
id: props.item.id,
})
.then(() => {
props.reload?.();
message.success('更新工单成功');
return true;
})
.catch(() => false)
}
columns={[
MyFormItems.EnumRadio({
key: 'type',
title: '工单类型',
colProps: { span: 24 },
valueEnum: HouseWorkOrdersTypeEnum,
required: true,
}),
{
key: 'title',
title: '工单标题',
colProps: { span: 18 },
formItemProps: { ...rulesHelper.text },
},
MyFormItems.EnumSelect({
key: 'level',
title: '优先级',
colProps: { span: 6 },
valueEnum: HouseWorkOrdersLevelEnum,
required: true,
}),
{
key: 'content',
title: '工单描述',
valueType: 'textarea',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
fieldProps: {
placeholder: '请详细描述工单内容',
},
},
{
valueType: 'dependency',
name: ['asset_projects_id', 'asset_buildings_id', 'asset_units_id'],
columns: ({
asset_projects_id,
asset_buildings_id,
asset_units_id,
}) => {
return [
{
valueType: 'group',
columns: [
Selects?.AssetProjects({
title: '依次选择项目',
key: 'asset_projects_id',
colProps: { span: 6 },
formItemProps: { ...rulesHelper.text },
}),
Selects?.AssetBuildings({
key: 'asset_buildings_id',
title: '楼栋',
params: {
asset_projects_id: asset_projects_id,
},
colProps: { span: 6 },
formItemProps: { ...rulesHelper.number },
fieldProps: {
showSearch: true,
onChange: () => {
form.setFieldsValue({
asset_units_id: undefined,
asset_floors_id: undefined,
});
},
},
}),
Selects?.AssetUnits({
key: 'asset_units_id',
title: '单元',
params: {
asset_projects_id: asset_projects_id,
asset_buildings_id: asset_buildings_id,
},
colProps: { span: 6 },
formItemProps: { ...rulesHelper.number },
}),
Selects?.AssetHouses({
title: '房屋',
key: 'asset_houses_id',
params: {
asset_projects_id: asset_projects_id,
asset_buildings_id: asset_buildings_id,
asset_units_id: asset_units_id,
},
formItemProps: { ...rulesHelper.text },
colProps: { span: 6 },
}),
],
},
];
},
},
MyFormItems.UploadImages({
key: 'attachments',
title: '相关图片',
uploadType: 'file',
max: 5,
colProps: { span: 24 },
formItemProps: { required: false },
}),
{
key: 'reporter_name',
title: '上报人姓名',
colProps: { span: 12 },
},
{
key: 'reporter_phone',
title: '上报人手机',
colProps: { span: 12 },
formItemProps: { ...rulesHelper.phone },
fieldProps: {
placeholder: '请输入手机号码',
maxLength: 11,
minLength: 11,
},
},
]}
/>
);
}