用 AirPower4T,我们来写个前端管理后台吧:)

271 天前
 Hamm

一、写在前面

前一篇文章《用 AirPower4J ,我们来写个后端服务吧》 是来水一篇,主要是顺带给前端项目写个后端的 api 服务, 略简单,入门级。后续再丰富吧:)

前端主要使用的是 Vue3 TypeScript Element Plus 等技术栈,行,开整。

二、初始化项目

老规矩,先新建个目录 frontend,再把宿主项目和依赖项目都拉下来,还是在 Github :)

我们直接使用 宿主项目 提供的一键脚本吧:)

我不知道你是不是习惯 ssh 方式,反正我挺喜欢:)

git clone git@github.com:HammCn/AirPowerWebDemo.git &&
cd AirPowerWebDemo/src && 
git clone git@github.com:HammCn/AirPower4T.git airpower && cd ../ &&
yarn && cp .env.dev .env && yarn s

不出意外应该会装完依赖启动项目,直接跑起来了。

这一套前后端是配套设计的,所以环境变量默认配置的就是上一篇后端服务文章里的本地服务。

三、开始写代码

先创建个菜单吧:)

好,依然是先来创建一下 Service Entity View 部分:

SupplierEntity 实体

@ClassName('供应商')
export class SupplierEntity extends BaseEntity {
  @TableField({
    copyField: true,
    forceShow: true,
  })
  @FormField({
    requiredString: true,
  })
  @FieldName('供应商编码') code!: string

  @TableField()
  @FormField({
    requiredString: true,
  })
  @FieldName('供应商名称') name!: string

  @Dictionary(SupplierLevelDictionary)
  @TableField({
    showColor: true,
  })
  @FormField({
    requiredNumber: true,
    defaultValue: SupplierLevel.GOLD,
  })
  @FieldName('供应商级别') level!: SupplierLevel

  @TableField()
  @FormField({
    mobilePhone: true,
  })
  @FieldName('联系电话') phone!: string
}

SupplierLevel 枚举

export enum SupplierLevel {
  GOLD = 1,
  SILVER = 2,
  COPPER = 3
}

SupplierLevelDictionary 枚举翻译字典

export const SupplierLevelDictionary = AirDictionaryArray.create([
  {
    key: SupplierLevel.GOLD, label: '金牌', color: AirColor.SUCCESS,
  }, {
    key: SupplierLevel.SILVER, label: '银牌', color: AirColor.WARNING,
  }, {
    key: SupplierLevel.COPPER, label: '铜牌', color: AirColor.NORMAL,
  },
])

上面我们按需求配置了一些表单、表格以及一些验证,还提供了一个供应商级别的枚举以及字典。

SupplierService 接口请求服务

export class SupplierService extends AbstractBaseService<SupplierEntity> {
  entityClass = SupplierEntity

  baseUrl = 'supplier'
}

View 层

我们创建了 edit.vue list.vue 这些视图:)

list.vue

<template>
  <APanel>
    <AToolBar
      :loading="isLoading"
      :entity="SupplierEntity"
      :service="SupplierService"
      @on-add="onAdd"
      @on-search="onSearch"
    >
      <template #afterButton>
        <AButton
          v-if="selectList.length>0"
          type="DELETE_LIST"
          danger
          @click="AirNotification.warning('就是玩');selectList=[]"
        >
          批量删除
        </AButton>
      </template>
    </AToolBar>
    <ATable
      v-loading="isLoading"
      :data-list="response.list"
      :entity="SupplierEntity"
      :select-list="selectList"
      show-select
      @on-edit="onEdit"
      @on-delete="onDelete"
      @on-sort-change="onSortChanged"
      @on-select="onSelected"
    />
    <template #footerLeft>
      <APage
        :response="response"
        @on-change="onPageChanged"
      />
    </template>
  </APanel>
</template>

<script lang="ts" setup>
import {
  APanel, APage, ATable, AToolBar, AButton,
} from '@/airpower/component'
import { useAirTable } from '@/airpower/hook/useAirTable'
import { SupplierEntity } from '@/model/supplier/SupplierEntity'
import { SupplierService } from '@/model/supplier/SupplierService'
import { SupplierEditor } from './component'
import { AirRequest } from '@/airpower/model/AirRequest'
import { AirNotification } from '@/airpower/feedback/AirNotification'

const {
  isLoading,
  response,
  selectList,
  onSearch, onAdd, onDelete, onEdit, onPageChanged, onSortChanged, onSelected,
} = useAirTable(SupplierEntity, SupplierService, {
  editor: SupplierEditor,
})
</script>

实现的效果如下图

关键词搜索、高级筛选,这些基本都可以直接在装饰器中配置,后续再讲。

edit.vue

<template>
  <ADialog
    :title="title"
    :form-ref="formRef"
    :loading="isLoading"
    @on-confirm="onSubmit()"
    @on-cancel="onCancel()"
  >
    <el-form
      ref="formRef"
      :model="formData"
      label-width="120px"
      :rules="rules"
      @submit.prevent
    >
      <el-form-item
        :label="SupplierEntity.getFormFieldLabel('code')"
        prop="code"
      >
        <AInput
          v-model.code="formData.code"
          :entity="SupplierEntity"
        />
      </el-form-item>
      <el-form-item
        :label="SupplierEntity.getFormFieldLabel('name')"
        prop="name"
      >
        <AInput
          v-model.name="formData.name"
          :entity="SupplierEntity"
        />
      </el-form-item>
      <el-form-item
        :label="SupplierEntity.getFormFieldLabel('level')"
        prop="level"
      >
        <AInput
          v-model.level="formData.level"
          :entity="SupplierEntity"
        />
      </el-form-item>
      <el-form-item
        :label="SupplierEntity.getFormFieldLabel('phone')"
        prop="phone"
      >
        <AInput
          v-model.phone="formData.phone"
          :entity="SupplierEntity"
        />
      </el-form-item>
    </el-form>
  </ADialog>
</template>

<script lang="ts" setup>
import { ADialog, AInput } from '@/airpower/component'
import { airPropsParam } from '@/airpower/config/AirProps'
import { useAirEditor } from '@/airpower/hook/useAirEditor'
import { SupplierEntity } from '@/model/supplier/SupplierEntity'
import { SupplierService } from '@/model/supplier/SupplierService'

const props = defineProps(airPropsParam(new SupplierEntity()))

const {
  title,
  formData,
  rules,
  onSubmit,
  formRef,
  isLoading,
} = useAirEditor(props, SupplierEntity, SupplierService)

</script>

实现了创建和修改两个需求,接下来试试配置的验证是否生效:)

好,搞定,看起来没什么问题。

四、就这样

That's all ,今天的水文又有了。

上面所有的代码都在 Github 欢迎食用。

文中提到几个开源地址:

依赖仓库: https://github.com/HammCn/AirPower4T

宿主项目: https://github.com/HammCn/AirPowerWebDemo

806 次点击
所在节点    TypeScript
0 条回复

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

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

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

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

© 2021 V2EX