diff --git a/Api/Ewide.Application/Entity/BsHouseCompany.cs b/Api/Ewide.Application/Entity/BsHouseCompany.cs new file mode 100644 index 0000000..0849cdc --- /dev/null +++ b/Api/Ewide.Application/Entity/BsHouseCompany.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ewide.Application +{ + [Table("bs_house_company")] + [Comment("房屋相关单位表")] + public class BsHouseCompany : Core.DEntityBase + { + /// + /// 单位类型,多选 + /// + [Comment("单位类型,多选")] + [MaxLength(20)] + public string Type { get; set; } + + /// + /// 单位名称 + /// + [Comment("单位名称")] + [MaxLength(200)] + public string Name { get; set; } + + /// + /// 信息 + /// + [Comment("信息")] + public string Info { get; set; } + } +} diff --git a/Api/Ewide.Application/Entity/BsHouseUnitInfo.cs b/Api/Ewide.Application/Entity/BsHouseUnitInfo.cs deleted file mode 100644 index ae2363b..0000000 --- a/Api/Ewide.Application/Entity/BsHouseUnitInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Ewide.Application.Entity -{ - public class BsHouseCompany : Core.DEntityBase - { - /// - /// 单位类型,多选 - /// - [Comment("单位类型,多选")] - [MaxLength(20)] - public string Type { get; set; } - - /// - /// 单位名称 - /// - [Comment("单位名称")] - [MaxLength(200)] - public string CompanyName { get; set; } - - /// - /// 单位负责人 - /// - [Comment("单位负责人")] - [MaxLength(100)] - public string ChargePerson { get; set; } - - /// - /// 单位负责人电话 - /// - [Comment("单位负责人电话")] - [MaxLength(50)] - public string ChargePersonTel { get; set; } - - /// - /// 单位联系人 - /// - [Comment("单位联系人")] - [MaxLength(100)] - public string ContactPerson { get; set; } - - /// - /// 单位联系人电话 - /// - [Comment("单位联系人电话")] - [MaxLength(50)] - public string ContactPersonTel { get; set; } - } -} diff --git a/Api/Ewide.Application/Ewide.Application.xml b/Api/Ewide.Application/Ewide.Application.xml index 5b8cd8b..38cf1b7 100644 --- a/Api/Ewide.Application/Ewide.Application.xml +++ b/Api/Ewide.Application/Ewide.Application.xml @@ -4,6 +4,21 @@ Ewide.Application + + + 单位类型,多选 + + + + + 单位名称 + + + + + 信息 + + HouseCode主键ID @@ -329,36 +344,6 @@ 主管部门 - - - 单位类型,多选 - - - - - 单位名称 - - - - - 单位负责人 - - - - - 单位负责人电话 - - - - - 单位联系人 - - - - - 单位联系人电话 - - bs_house_code主键Id diff --git a/Api/Ewide.Application/Service/HouseSafety/HouseCompany/Dto/HouseCompanyInput.cs b/Api/Ewide.Application/Service/HouseSafety/HouseCompany/Dto/HouseCompanyInput.cs new file mode 100644 index 0000000..95fcd6e --- /dev/null +++ b/Api/Ewide.Application/Service/HouseSafety/HouseCompany/Dto/HouseCompanyInput.cs @@ -0,0 +1,61 @@ +using Ewide.Core; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ewide.Application +{ + public class HouseCompanyInput + { + [Required(ErrorMessage = "Id不能为空")] + public string Id { get; set; } + } + + public class HouseCompanyInfoInput + { + [Required(ErrorMessage = "信息名称不能为空")] + public string Name { get; set; } + [Required(ErrorMessage = "信息内容不能为空")] + public string Value { get; set; } + } + + public class HouseCompanyPageInput : PageInputBase {} + + public class HouseCompanyAddInput + { + [Required(ErrorMessage = "名称不能为空")] + public virtual string Name { get; set; } + + private string _Type { get; set; } + + [Required(ErrorMessage = "类型不能为空")] + public virtual string Type + { + get + { + return _Type; + } + set + { + _Type = String.Join(",", value.Split(',').Select(p => $"[{p}]")); + } + } + + public virtual List Info { get; set; } + } + + public class HouseCompanyEditInput : HouseCompanyAddInput + { + [Required(ErrorMessage = "Id不能为空")] + public string Id { get; set; } + } + + public class HouseCompanyListInput + { + [Required(ErrorMessage = "类型不能为空")] + public string Type { get; set; } + } +} diff --git a/Api/Ewide.Application/Service/HouseSafety/HouseCompany/Dto/HouseCompanyOutput.cs b/Api/Ewide.Application/Service/HouseSafety/HouseCompany/Dto/HouseCompanyOutput.cs new file mode 100644 index 0000000..8692722 --- /dev/null +++ b/Api/Ewide.Application/Service/HouseSafety/HouseCompany/Dto/HouseCompanyOutput.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ewide.Application +{ + public class HouseCompanyInfoOutput + { + public string Name { get; set; } + public string Value { get; set; } + } + + public class HouseCompanyDetailOutput + { + public string Id { get; set; } + public string Name { get; set; } + private string _Type { get; set; } + public string Type + { + get + { + return _Type; + } + set + { + _Type = String.Join(",", value.Split(',').Select(p => p.Replace("[", "").Replace("]", ""))); + } + } + public List Info { get; set; } + } +} diff --git a/Api/Ewide.Application/Service/HouseSafety/HouseCompany/HouseCompanyService.cs b/Api/Ewide.Application/Service/HouseSafety/HouseCompany/HouseCompanyService.cs new file mode 100644 index 0000000..dc99898 --- /dev/null +++ b/Api/Ewide.Application/Service/HouseSafety/HouseCompany/HouseCompanyService.cs @@ -0,0 +1,101 @@ +using Ewide.Core.Extension; +using Furion.DatabaseAccessor; +using Furion.DatabaseAccessor.Extensions; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ewide.Application.Service +{ + [ApiDescriptionSettings(Name = "HouseCompany")] + public class HouseCompanyService : IHouseCompanyService, IDynamicApiController, ITransient + { + private readonly IRepository _bsHouseCompanyRep; + + public HouseCompanyService(IRepository bsHouseCompanyRep) + { + _bsHouseCompanyRep = bsHouseCompanyRep; + } + + [HttpPost("/houseCompany/page")] + public async Task Page([FromBody] HouseCompanyPageInput input) + { + var config = new TypeAdapterConfig().ForType() + .Map(target => target.Info, src => JsonConvert.DeserializeObject>(src.Info)) + .Config; + return await _bsHouseCompanyRep.DetachedEntities.ToPageData(input, config); + } + + [HttpPost("/houseCompany/add")] + public async Task Add([FromBody] HouseCompanyAddInput input) + { + var info = JsonConvert.SerializeObject(input.Info); + var config = new TypeAdapterConfig().ForType() + .Map(target => target.Info, src => JsonConvert.SerializeObject(src.Info)) + .Config; + var company = input.Adapt(config); + await company.InsertAsync(); + } + + [HttpPost("/houseCompany/edit")] + public async Task Edit([FromBody] HouseCompanyEditInput input) + { + var config = new TypeAdapterConfig().ForType() + .Map(target => target.Info, src => JsonConvert.SerializeObject(src.Info)) + .Config; + var company = input.Adapt(config); + await company.UpdateAsync(); + } + + [HttpPost("/houseCompany/delete")] + public async Task Delete([FromBody] HouseCompanyInput input) + { + var company = await _bsHouseCompanyRep.FirstOrDefaultAsync(p => p.Id.Equals(input.Id)); + await company.DeleteAsync(); + } + + [HttpGet("/houseCompany/detail")] + public async Task Detail([FromQuery] HouseCompanyInput input) + { + var company = await _bsHouseCompanyRep.FirstOrDefaultAsync(p => p.Id.Equals(input.Id)); + var config = new TypeAdapterConfig().ForType() + .Map(target => target.Info, src => JsonConvert.DeserializeObject>(src.Info)) + .Config; + var output = company.Adapt(config); + return output; + } + + [HttpGet("/houseCompany/list")] + public async Task List([FromQuery] HouseCompanyListInput input) + { + var types = input.Type.Split(','); + var result = new List(); + var config = new TypeAdapterConfig().ForType() + .Map(target => target.Info, src => JsonConvert.DeserializeObject>(src.Info)) + .Config; + foreach (var type in types) + { + var list = (await _bsHouseCompanyRep.DetachedEntities + .Where(p => EF.Functions.Like(p.Type, $"%[{type.Trim()}]%")) + .OrderBy(p => p.Name) + .ToListAsync()) + .Select(p => + { + var output = p.Adapt(config); + return output; + }); + result.AddRange(list); + } + + return result.Distinct(); + } + } +} diff --git a/Api/Ewide.Application/Service/HouseSafety/HouseCompany/IHouseCompanyService.cs b/Api/Ewide.Application/Service/HouseSafety/HouseCompany/IHouseCompanyService.cs new file mode 100644 index 0000000..94eac4e --- /dev/null +++ b/Api/Ewide.Application/Service/HouseSafety/HouseCompany/IHouseCompanyService.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ewide.Application.Service +{ + public interface IHouseCompanyService + { + Task Page([FromBody] HouseCompanyPageInput input); + Task Add([FromBody] HouseCompanyAddInput input); + Task Edit([FromBody] HouseCompanyEditInput input); + Task Delete([FromBody] HouseCompanyInput input); + Task Detail([FromQuery] HouseCompanyInput input); + Task List([FromQuery] HouseCompanyListInput input); + } +} diff --git a/Api/Ewide.Core/Extension/PageExtensions.cs b/Api/Ewide.Core/Extension/PageExtensions.cs index a47f185..e84f1af 100644 --- a/Api/Ewide.Core/Extension/PageExtensions.cs +++ b/Api/Ewide.Core/Extension/PageExtensions.cs @@ -125,6 +125,11 @@ namespace Ewide.Core.Extension return source.OrderBy(OrderBuilder(input)).Select(u => u.Adapt()).ToPagedListAsync(input.PageIndex, input.PageSize); } + public static Task> ToPageData(this IQueryable source, PageInputBase input, TypeAdapterConfig config) where O : new() + { + return source.OrderBy(OrderBuilder(input)).Select(u => u.Adapt(config)).ToPagedListAsync(input.PageIndex, input.PageSize); + } + #region DAPPER public async static Task QueryPageDataDynamic(this IDapperRepository source, string baseSql, PageInputBase input, object param = null, IEnumerable filterFields = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) { diff --git a/web-react/src/common/api/requests/business/houseSafety/houseCompany.js b/web-react/src/common/api/requests/business/houseSafety/houseCompany.js new file mode 100644 index 0000000..c8dee9c --- /dev/null +++ b/web-react/src/common/api/requests/business/houseSafety/houseCompany.js @@ -0,0 +1,10 @@ +const urls = { + houseCompanyPage: ['/houseCompany/page', 'post'], + houseCompanyAdd: ['/houseCompany/add', 'post'], + houseCompanyEdit: ['/houseCompany/edit', 'post'], + houseCompanyDelete: ['/houseCompany/delete', 'post'], + houseCompanyDetail: '/houseCompany/detail', + houseCompanyList: '/houseCompany/list' +} + +export default urls \ No newline at end of file diff --git a/web-react/src/common/api/requests/business/houseSafety/index.js b/web-react/src/common/api/requests/business/houseSafety/index.js index 6732039..fa768a1 100644 --- a/web-react/src/common/api/requests/business/houseSafety/index.js +++ b/web-react/src/common/api/requests/business/houseSafety/index.js @@ -6,6 +6,7 @@ import houseSelector from './houseSelector' import houseTask from './houseTask' import houseInfo from './houseInfo' import houseQuery from './houseQuery' +import houseCompany from './houseCompany' const urls = { ...houseProjectInfo, @@ -15,7 +16,8 @@ const urls = { ...houseSelector, ...houseTask, ...houseInfo, - ...houseQuery + ...houseQuery, + ...houseCompany } export default urls \ No newline at end of file diff --git a/web-react/src/components/modal-form/index.jsx b/web-react/src/components/modal-form/index.jsx index ff78981..89ce8f6 100644 --- a/web-react/src/components/modal-form/index.jsx +++ b/web-react/src/components/modal-form/index.jsx @@ -18,7 +18,7 @@ function renderModal(props, on, childWithProps) { const { buttons } = this.props const _buttons = [ - , + , , diff --git a/web-react/src/pages/business/house/company/form.jsx b/web-react/src/pages/business/house/company/form.jsx new file mode 100644 index 0000000..80646d0 --- /dev/null +++ b/web-react/src/pages/business/house/company/form.jsx @@ -0,0 +1,180 @@ +import React, { Component } from 'react' +import { Button, Col, Form, Input, Row, Select, Spin } from 'antd' +import { AntIcon } from 'components' +import { api } from 'common/api' +import getDictData from 'util/dic' + +const initialValues = {} + +export default class form extends Component { + state = { + // 加载状态 + loading: true, + + codes: { + houseCompanyType: [], + }, + } + + // 表单实例 + form = React.createRef() + + // 初始化数据 + record = {} + + /** + * mount后回调 + */ + componentDidMount() { + this.props.created && this.props.created(this) + } + + /** + * 填充数据 + * 可以在设置this.record之后对其作出数据结构调整 + * [异步,必要] + * @param {*} params + */ + async fillData(params) { + const state = { loading: false } + //#region 从后端转换成前段所需格式,也可以在此处调用获取详细数据接口 + state.codes = await getDictData('house_company_type') + if (params.id) { + this.record = (await api.houseCompanyDetail({ id: params.id })).data + const { type, info } = this.record + if (type) { + this.record.type = type.split(',') + } + } + //#endregion + this.form.current.setFieldsValue(this.record) + + this.setState(state) + } + + /** + * 获取数据 + * 可以对postData进行数据结构调整 + * [异步,必要] + * @returns + */ + async getData() { + const form = this.form.current + + const valid = await form.validateFields() + if (valid) { + const postData = form.getFieldsValue() + if (this.record) { + postData.id = this.record.id + } + //#region 从前段转换后端所需格式 + const { type, info } = postData + if (Array.isArray(type)) { + postData.type = type.join(',') + } + //#endregion + return postData + } + } + + //#region 自定义方法 + //#endregion + + render() { + const { codes } = this.state + + return ( +
+ }> +
+ + + + + + +
+ + {(fields, { add, remove }) => ( + <> + {fields.map(({ key, name, fieldKey, ...restField }) => ( + + + remove(name)} + /> + + + + + + + + + + + + + ))} + + + + + )} + +
+
+
+
+ ) + } +} diff --git a/web-react/src/pages/business/house/company/index.jsx b/web-react/src/pages/business/house/company/index.jsx new file mode 100644 index 0000000..c49000a --- /dev/null +++ b/web-react/src/pages/business/house/company/index.jsx @@ -0,0 +1,295 @@ +import React, { Component } from 'react' +import { + Button, + Card, + Descriptions, + Form, + Input, + message as Message, + Popconfirm, + Select, +} from 'antd' +import { AntIcon, Auth, Container, ModalForm, QueryTable, QueryTableActions } from 'components' +import { api } from 'common/api' +import auth from 'components/authorized/handler' +import { isEqual } from 'lodash' +import getDictData from 'util/dic' +import { toCamelCase } from 'util/format' +import FormBody from './form' + +/** + * 注释段[\/**\/]为必须要改 + */ + +/** + * 配置页面所需接口函数 + */ +const apiAction = { + page: api.houseCompanyPage, + add: api.houseCompanyAdd, + edit: api.houseCompanyEdit, + delete: api.houseCompanyDelete, +} + +/** + * 用于弹窗标题 + * [必要] + */ +const name = '单位' + +/** + * 统一配置权限标识 + * [必要] + */ +const authName = 'houseCompany' + +export default class index extends Component { + state = { + codes: { + houseCompanyType: [], + }, + } + + // 表格实例 + table = React.createRef() + + // 新增窗口实例 + addForm = React.createRef() + // 编辑窗口实例 + editForm = React.createRef() + + columns = [ + { + title: '名称', + width: 300, + dataIndex: 'name', + }, + { + title: '类型', + width: 300, + dataIndex: 'type', + render: text => + text + .split(',') + .map(p => this.bindCodeValue(p, 'house_company_type')) + .join(' / '), + }, + ] + + /** + * 构造函数,在渲染前动态添加操作字段等 + * @param {*} props + */ + constructor(props) { + super(props) + + const flag = auth({ [authName]: [['edit'], ['delete']] }) + + if (flag) { + this.columns.push({ + title: '操作', + width: 150, + dataIndex: 'actions', + render: (text, { id }) => ( + + + this.onOpen(this.editForm, id)}>编辑 + + + this.onDelete(id)} + > + 删除 + + + + ), + }) + } + } + + /** + * 阻止外部组件引发的渲染,提升性能 + * 可自行添加渲染条件 + * [必要] + * @param {*} props + * @param {*} state + * @returns + */ + shouldComponentUpdate(props, state) { + return !isEqual(this.state, state) + } + + /** + * 加载字典数据,之后开始加载表格数据 + * 如果必须要加载字典数据,可直接对表格设置autoLoad=true + */ + componentDidMount() { + const { onLoading, onLoadData } = this.table.current + onLoading() + api.houseCompanyList({ type: '1' }) + getDictData('house_company_type').then(codes => { + this.setState({ codes }, () => { + onLoadData() + }) + }) + } + + /** + * 调用加载数据接口,可在调用前对query进行处理 + * [异步,必要] + * @param {*} params + * @param {*} query + * @returns + */ + loadData = async (params, query) => { + const { data } = await apiAction.page({ + ...params, + ...query, + }) + return data + } + + /** + * 绑定字典数据 + * @param {*} code + * @param {*} name + * @returns + */ + bindCodeValue(code, name) { + name = toCamelCase(name) + const codes = this.state.codes[name] + if (codes) { + const c = codes.find(p => p.code == code) + if (c) { + return c.value + } + } + return null + } + + /** + * 打开新增/编辑弹窗 + * @param {*} modal + * @param {*} id + */ + onOpen(modal, id) { + modal.current.open({ id }) + } + + /** + * 对表格上的操作进行统一处理 + * [异步] + * @param {*} action + * @param {*} successMessage + */ + async onAction(action, successMessage) { + const { onLoading, onLoaded, onReloadData } = this.table.current + onLoading() + try { + if (action) { + await action + } + if (successMessage) { + Message.success(successMessage) + } + onReloadData() + } catch { + onLoaded() + } + } + + /** + * 删除 + * @param {*} id + */ + onDelete(id) { + this.onAction(apiAction.delete({ id }), '删除成功') + } + + //#region 自定义方法 + //#endregion + + render() { + const { codes } = this.state + + return ( + +
+ + + + + + + + + + } + operator={ + + + + } + expandedRowRender={record => ( + + {record.info.map((item, i) => ( + + {item.value} + + ))} + + )} + /> + + + + this.table.current.onReloadData()} + > + + + + + + this.table.current.onReloadData()} + > + + + +
+ ) + } +}