V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
zhoupeng199
V2EX  ›  问与答

面向对象编程真是太香了

  •  
  •   zhoupeng199 · 343 天前 · 1216 次点击
    这是一个创建于 343 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近需要编写一个后台管理系统,涉及到大量表格表单,本身这些内容如果直接用 Django 来做,可能就没我们前端什么事情了,但是后端是新来的 JAVA 团队,前后端分离开发模式,所以前端工作量非常大,于是抽象了一个接口类似于 django 的前端框架。

    基于 react class component 编写和使用了 ant design UI 库,通过配置的形式直接实现一个管理页面的增删改查以及分页功能,能够减少大量的逻辑代码,不由得感慨面向对象编程的伟大,以及 django 这个框架设计的精妙。

    一个页面的实现大致如下所示:

    import { RegisterRoute } from '@src/components/router'
    import { ModelForm } from '@src/core/model/form'
    import { RemoteDataChoiceWidget } from '@src/core/model/widget'
    import { Display, ModelAdmin } from '@src/core/template/model-admin'
    import { TemplateTablePagination } from '@src/core/template/template-table'
    import { UploadWidget } from '@src/core/widgets/upload-widget'
    import { $fetch } from '@src/utils/network'
    import { Switch } from 'antd'
    
    class SouceChoiceWidget extends RemoteDataChoiceWidget<any, any> {
        type = 1
        async getRemoteData(): Promise<{ label: string; value: string | number }[]> {
            const result = await $fetch.post<any, Business.SourceInfo[]>('investment/lead/way/list', {
                type: this.type
            })
    
            return result.map(val => {
                return {
                    label: val.name,
                    value: val.id
                }
            })
        }
    }
    
    class ClueSourceChoiceWidget extends SouceChoiceWidget {
        type = 0
    }
    
    
    class Form extends ModelForm {
        name = ModelForm.InputField({
            verboseName: '线索名称',
        })
        contactPerson = ModelForm.InputField({
            verboseName: '联系人',
        })
        contactTel = ModelForm.PhoneNumberField({
            verboseName: '联系电话',
        })
        fromType = ModelForm.InputField({
            verboseName: '线索来源',
            widget: ClueSourceChoiceWidget
        })
        wayType = ModelForm.InputField({
            verboseName: '渠道类型',
            widget: SouceChoiceWidget
        })
        file = ModelForm.InputField({
            verboseName: '附件',
            widget: UploadWidget
        })
    }
    
    
    interface AppInfo {
        id: number;
        parkId: number;
        appName: string;
        appCate: number;
        appUrl: string;
        isDisabled: number;
        createAt: string;
        createBy: string;
    }
    
    @RegisterRoute('clue/list')
    export default class App extends ModelAdmin<any, any> {
        filters: string[] = ['name']
        listDisplay: string[] = [
            'name',
            'type',
            'disabled',
            'action',
        ]
    
        getModel(): new () => ModelForm {
            return Form
        }
    
        async getTableDataSource(pagination: TemplateTablePagination, filters?: any) {
            const data = Object.assign({}, filters || {}, {
                pageSize: pagination.pageSize,
                pageNo: pagination.current,
            })
            const result = await $fetch.post<any, App.Pagination<AppInfo>>(
                '/smart-park-invest/investmentLead/page',
                data
            )
    
            return result
        }
    
        async onFormAddSubmit(
            composeValues: any,
            formValues: any
        ) {
            await $fetch.post('/smart-park-invest/investment/lead/way/add', {
                ...formValues
            })
        }
    
        async onFormUpdateSubmit(
            composeValues: any,
            formValues: any,
            initialValues: any
        ) {
            await $fetch.post('/smart-park-invest/investment/lead/way/update', {
                ...formValues,
                id: initialValues.id,
            })
        }
    
        getaddFormInitialValues() {
            return null
        }
    
        async getUpdateFormInitialValues(record: any) {
            return record
        }
    
        async onConfirmDeleteRow(record: any) {
            await $fetch.post(`/smart-park-invest/investment/lead/way/delete/${record.id}`)
        }
    
        @Display({
            name: 'disabled',
            title: '启用',
        })
        displayDisabled(_: any, record: any) {
            return (
                <Switch
                    size="small"
                    checked={record.enable}
                    onChange={(val) => this.setAppEnabel(record, val)}
          />
            )
        }
    
        @Display({
            name: 'action',
            title: '操作',
        })
        displayAction(_: any, record: any) {
            return (
                <div>
                    <span
                        className="ml-2 text-blue-400 cursor-pointer"
                        onClick={() => this.modifyRowData(record)}>
                        编辑
                    </span>
                    <span
                        className="ml-2 text-red-400 cursor-pointer"
                        onClick={() => this.deleteRowData(record)}>
                        删除
                    </span>
                </div>
            )
        }
    
        async setAppEnabel(record: any, bool: boolean) {
            await $fetch.post('/smart-park-invest/investment/lead/way/update', {
                id: record.id,
                enable: bool
            })
            this.notifyDataChange()
        }
    }
    
    
    

    虽然 react 现在都在推崇 hooks 编程,甚至官方文档都不再教学 class 组件,但 class component 在有些场景还是很好用的。

    wunonglin
        1
    wunonglin  
       343 天前
    首推 angular
    wanguorui123
        2
    wanguorui123  
       343 天前
    Class 组件大多数时候比较好,面向对象编程就是分离关注点,专注于做好每件小事,把大事化解掉,而不是面向过程写出无数个冗长且不可复用的代码。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4987 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 01:13 · PVG 09:13 · LAX 18:13 · JFK 21:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.