Skip to content

zh..Page

meta-d edited this page Mar 8, 2024 · 3 revisions

English | 中文

新页面

🏗️ 应用结构

NGen 中的应用组织成了组。每个组都是一个包含多个应用页面和一个路由的文件夹。每个页面都是一个包含组件、HTML、样式以及任何特定于该页面的其他文件的文件夹。

如果要向现有组中创建新页面,只需在组文件夹下创建一个新文件夹,并添加页面组件和任何特定于该页面的其他文件即可。

如果要创建一个新组,可以在 src/app/pages/ 文件夹下创建一个新文件夹,并在该组文件夹中添加路由文件。

应用路径模式为 src/app/pages/<新组>/<新应用>

应用页面文件夹结构如下:

src/app/pages/
│
├───group1
├───├───routing.ts
│   ├───app1
│   └───app2
│       ├───app2.component.html
│       ├───app2.component.scss
│       └───app2.component.ts
└───group2
    ├───app2-1
    └───app2-2

新页面组件

您可以手动创建一个新的页面组件(例如,在 admin 组中的 products),也可以使用以下命令:

yarn nx g @nx/angular:component products --directory=apps/launchpad/src/app/pages/admin/products --nameAndDirectoryFormat=as-provided

将页面组件添加到路由文件中,请参阅 应用组件路由。然后,您可以通过 http://localhost:4200/admin/products URL 访问该页面,Admin 菜单组中将呈现 Products 菜单。

路由

应用组路由

如果创建了一个新组,您需要将组路由添加到 src/app/app.routes.ts 文件中:

import { environment } from '@/environments/environment'
import { Routes } from '@angular/router'

export const appRoutes: Routes = [
  ..., // 其他路由
  {
    path: 'admin',
    title: 'Admin',
    loadChildren: () => import('./pages/admin/admin-routing'),
    data: {
      icon: 'setting',
      key: 'admin',
      // authorization: {
      //   name: 'S_SERVICE',
      //   params: {
      //     SRV_NAME: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
      //     SRV_TYPE: 'HT'
      //   }
      // }
    }
  }
]

我们建议使用 loadChildren 来延迟加载组路由,以减少初始首页加载时间。

有关 authorization 字段的详细信息,请参阅 路由的授权配置

应用组件路由

将新组件添加到组路由文件 src/app/pages/admin/routing.ts

import { Routes } from '@angular/router'
import { ProductsComponent } from './products/products.component'

export default [
  ..., // 其他路由
  {
    path: 'products',
    title: 'Products',
    component: ProductsComponent
  }
] as Routes

您还可以为单个应用路由添加 authorization 检查配置,请参阅 路由的授权配置

组件

1. 添加基础布局模板

将基础布局模板添加到组件 HTML 文件 src/app/pages/admin/products/products.component.html 中:

<nz-page-header nzBackIcon [nzGhost]="false">
  <nz-page-header-title>Products</nz-page-header-title>
  <nz-page-header-subtitle></nz-page-header-subtitle>
  <nz-page-header-extra>
    <nz-space>
      <button *nzSpaceItem nz-button nzType="primary">
        {{ 'ZNG.Common.Query' | translate: {Default: 'Query'} }}
      </button>
    </nz-space>
  </nz-page-header-extra>
  <nz-page-header-content></nz-page-header-content>
</nz-page-header>
  
<div class="zng-page-body-ghost-wrapper">
  <div class="flex justify-between items-center p-2">
    <div>Products List</div>
  </div>
</div>

您还需要将两个模块 TranslateModule, ZngAntdModule 导入到组件中:

import { ZngAntdModule } from '@/app/core/shared.module'
import { CommonModule } from '@angular/common'
import { Component } from '@angular/core'
import { TranslateModule } from '@ngx-translate/core'

@Component({
  selector: 'zng-products',
  standalone: true,
  imports: [CommonModule, TranslateModule, ZngAntdModule],
  templateUrl: './products.component.html',
  styleUrl: './products.component.scss'
})
export class ProductsComponent {}

2. 调用 OData 服务

您可以创建一个名为 src/app/pages/admin/products/odata.service.ts 的 ts 文件来调用 OData 服务。

有关 OData 客户端的详细使用,请参阅 OData 服务

import { Keys, ODataQueryOptions, StoreStatus, defineODataStore } from '@metad/cap-odata'

const demoODataStore = defineODataStore('OData.svc', {
  base: '/odata.org/V3/OData/'
})

export const useDemoODataStore = () => {
  const { store, init } = demoODataStore
  if (store.value.status === StoreStatus.init || store.value.status === StoreStatus.error) {
    init()
  }

  return demoODataStore
}

export async function queryProducts(options?: ODataQueryOptions) {
  const { query } = useDemoODataStore()
  const result = await query<ProductType>('Products', {
    ...options
  })
  return result
}


export type ProductType = {
  ID: string
  Name: string
  Description: string
  ReleaseDate: Date
  DiscontinuedDate: Date
  Rating: number
  Price: number

  Categories: CategoryType[]
  Supplier: SupplierType
  ProductDetail: ProductDetailType
}

export type CategoryType = {
  ID: string
  Name: string
}

export type ProductDetailType = {
  ProductID: number
  Details: string

  Product?: ProductType
}

export type SupplierType = {
  ID: number
  Name: string
  Address: string
  Location: string
  Concurrency: string

  Products?: ProductType[]
}

然后在组件中调用函数:

import { queryProducts }

 from './odata.service'

...
export class ProductsComponent {
  constructor() {
    queryProducts().then((result) => console.log(result))
  }
}

您可以在浏览器控制台中获取产品列表日志。

3. 添加表格组件

将表格组件添加到组件 HTML 文件 src/app/pages/admin/products/products.component.html 中:

<div class="zng-page-body-ghost-wrapper p-4">
  <div class="flex justify-between items-center p-2">
    <div>Products List</div>
  </div>

  <nz-table #expandTable class="h-full w-full" [nzFrontPagination]="false" [nzLoading]="loading()" nzBordered nzOuterBordered
    [nzData]="items()" [nzScroll]="{ x: '1100px', y: '500px' }"
    nzShowPagination
    nzShowSizeChanger>
    <thead>
      <tr>
        @for (column of tableColumns(); track column.name) {
          <th [nzLeft]="column.freeze === 'left' || column.freeze === true" [nzRight]="column.freeze === 'right'" [nzAlign]="column.align!"
          >
            {{column.label}}
          </th>
        }
      </tr>
    </thead>
    <tbody>
      @for (row of items(); track row.ID) {
        <tr>
          @for (column of tableColumns(); track column.name) {
            <td [nzLeft]="column.freeze === 'left' || column.freeze === true" [nzRight]="column.freeze === 'right'">
              @switch (column.name) {
                @default {
                  <span>{{ row[column.name] }}</span>
                }
              }
            </td>
          }
        </tr>
      }
    </tbody>
  </nz-table>
</div>

逻辑如下:

export class ProductsComponent {
  readonly loading = signal(true)
  readonly tableColumns = signal<TableColumn<ProductType>[]>([
    {
      name: 'ID',
      label: 'ID'
    },
    {
      name: 'Name',
      label: 'Name'
    },
    {
      name: 'Description',
      label: 'Description'
    },
    {
      name: 'ReleaseDate',
      label: 'Release Date'
    },
    {
      name: 'DiscontinuedDate',
      label: 'Discontinued Date'
    },
    {
      name: 'Rating',
      label: 'Rating'
    },
    {
      name: 'Price',
      label: 'Price'
    }
  ])
  readonly items = signal<ProductType[]>([])

  constructor() {
    queryProducts().then((result) => {
      this.loading.set(false)
      this.items.set(result)
    })
  }
}
  1. loading 属性是一个用于控制表格加载状态的信号。
  2. tableColumns 是一个用于控制表格列的信号。
  3. items 是一个用于控制表格数据的信号。
  4. 当组件初始化时,调用 queryProducts 函数获取数据,然后将 loading 状态设置为 false,并将数据设置为 items 信号。
  5. 数据将显示在表格中。

4. 添加样式

将样式添加到组件 scss 文件 src/app/pages/admin/products/products.component.scss 中:

.ant-table-cell {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

样式用于控制表格单元格文本溢出。

5. 添加国际化

我们已将国际化添加到组件 HTML 文件中的按钮元素中:

<button *nzSpaceItem nz-button nzType="primary">
  {{ 'ZNG.Common.Query' | translate: {Default: 'Query'} }}
</button>

应用将使用键 ZNG.Common.Query 作为 JSON 路径,从 assets/i18n/ 中的国际化文件获取值。如果找不到键,则将使用默认值 Query

将键/值添加到国际化 JSON 文件 src/assets/i18n/<language>.json 中:

{
  "ZNG": {
    "Common: {
      "Query": "查询"
    }
  }
}

总结

在本页面中,我们学习了如何在应用中创建新页面,如何将页面添加到路由中。我们可以在表格中显示来自远程 OData 服务的数据,并为页面添加了国际化支持。