面向对象编程真是太香了

2023-04-20 20:29:01 +08:00
 zhoupeng199

最近需要编写一个后台管理系统,涉及到大量表格表单,本身这些内容如果直接用 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 在有些场景还是很好用的。

1226 次点击
所在节点    问与答
2 条回复
wunonglin
2023-04-20 21:02:40 +08:00
首推 angular
wanguorui123
2023-04-20 21:12:32 +08:00
Class 组件大多数时候比较好,面向对象编程就是分离关注点,专注于做好每件小事,把大事化解掉,而不是面向过程写出无数个冗长且不可复用的代码。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/934137

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX