乐趣区

Flutter-新闻客户端-15-strapi-数据建模-graphql-条件查询排序

本节指标

  • portainer 容器管理工具
  • 数据库设计过程
  • 数据库设计指标、标准、习惯
  • graphql 条件查问、排序
  • flutter 代码实现

视频

https://www.bilibili.com/vide…

代码

https://github.com/ducafecat/…

strapi 运行环境网盘下载

  • 网盘

链接:https://pan.baidu.com/s/13Ujy…
明码:yu82

  • 文件
名称 阐明
strapi-docker-compose-00.zip 洁净环境,已装置 graphql 插件
strapi-docker-compose-15.zip 15 课内容
  • 运行

须要用 docker-compose 启动
账号 admin
明码 123456

# 启动
docker-compose up -d --remove-orphans

# 敞开
docker-compose down

工具

  • https://www.portainer.io
  • https://www.draw.io
  • https://app.quicktype.io

注释

装置 portainer

  • https://www.portainer.io
docker run -d -p 9000:9000 \
    --restart=always \
    -v /var/run/docker.sock:/var/run/docker.sock \
    --name portainer-local \
    portainer/portainer

设计数据模型

  • https://www.draw.io
  • 规范数据库设计

ER 图 -> 设计范式 -> 数据库物理表

  • ER

  • 范式

https://zh.wikipedia.org/wiki…

  • 设计规范 表前缀

sys* 零碎、用户、权限
dict* 字典表
bus_ 业务

  • 设计数据 对象、属性、关系

创立 strapi 数据类型

  • 创立外键表 新闻分类

  • 创立外键表 新闻频道

  • 创立业务表 新闻内容

  • 创立链接外键 新闻内容、分类、频道

编写 graphql 查问

  • 新闻
query News($category_code: String) {busNews(where: { dict_categories: { code: $category_code} }) {
    title
    dict_channel {
      code
      title
      icon {url}
    }
    dict_categories {
      code
      title
    }
    author
    url
    addtime
    thumbnail {url}
  }
}
  • 首页
query pageIndex {
  # 分类
  dictCategories(sort: "sortNum:desc") {
    code
    title
  }
  # 频道
  dictChannels(sort: "sortNum:desc") {
    code
    title
    icon {url}
  }
  # 热点
  busNews(where: { dict_categories: { code: "news_hot"} }) {
    title
    dict_channel {
      code
      title
      icon {url}
    }
    dict_categories {
      code
      title
    }
    author
    url
    addtime
    thumbnail {url}
  }
}

编写 flutter 代码

  • 实例 entity

lib/common/entitys/gql_news.dart

// 首页
class GqlIndexResponseEntity {
  GqlIndexResponseEntity({
    this.dictCategories,
    this.dictChannels,
    this.busNews,
  });

  List<DictCategoryEntity> dictCategories;
  List<DictChannelEntity> dictChannels;
  List<GqlNewsResponseEntity> busNews;

  factory GqlIndexResponseEntity.fromJson(Map<String, dynamic> json) =>
      GqlIndexResponseEntity(
        dictCategories: List<DictCategoryEntity>.from(json["dictCategories"].map((x) => DictCategoryEntity.fromJson(x))),
        dictChannels: List<DictChannelEntity>.from(json["dictChannels"].map((x) => DictChannelEntity.fromJson(x))),
        busNews: List<GqlNewsResponseEntity>.from(json["busNews"].map((x) => GqlNewsResponseEntity.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "dictCategories":
            List<dynamic>.from(dictCategories.map((x) => x.toJson())),
        "dictChannels": List<dynamic>.from(dictChannels.map((x) => x.toJson())),
        "busNews": List<dynamic>.from(busNews.map((x) => x.toJson())),
      };
}

// 新闻
class GqlNewsResponseEntity {
  GqlNewsResponseEntity({
    this.title,
    this.dictChannel,
    this.dictCategories,
    this.author,
    this.url,
    this.addtime,
    this.thumbnail,
  });

  String title;
  DictChannelEntity dictChannel;
  List<DictCategoryEntity> dictCategories;
  String author;
  String url;
  DateTime addtime;
  ThumbnailEntity thumbnail;

  factory GqlNewsResponseEntity.fromJson(Map<String, dynamic> json) =>
      GqlNewsResponseEntity(title: json["title"],
        dictChannel: DictChannelEntity.fromJson(json["dict_channel"]),
        dictCategories: List<DictCategoryEntity>.from(json["dict_categories"].map((x) => DictCategoryEntity.fromJson(x))),
        author: json["author"],
        url: json["url"],
        addtime: DateTime.parse(json["addtime"]),
        thumbnail: ThumbnailEntity.fromJson(json["thumbnail"]),
      );

  Map<String, dynamic> toJson() => {
        "title": title,
        "dict_channel": dictChannel.toJson(),
        "dict_categories":
            List<dynamic>.from(dictCategories.map((x) => x.toJson())),
        "author": author,
        "url": url,
        "addtime":
            "${addtime.year.toString().padLeft(4,'0')}-${addtime.month.toString().padLeft(2,'0')}-${addtime.day.toString().padLeft(2,'0')}",
        "ThumbnailEntity": thumbnail.toJson(),};
}

// 分类
class DictCategoryEntity {
  DictCategoryEntity({
    this.code,
    this.title,
  });

  String code;
  String title;

  factory DictCategoryEntity.fromJson(Map<String, dynamic> json) =>
      DictCategoryEntity(code: json["code"],
        title: json["title"],
      );

  Map<String, dynamic> toJson() => {
        "code": code,
        "title": title,
      };
}

// 频道
class DictChannelEntity {
  DictChannelEntity({
    this.code,
    this.title,
    this.icon,
  });

  String code;
  String title;
  ThumbnailEntity icon;

  factory DictChannelEntity.fromJson(Map<String, dynamic> json) =>
      DictChannelEntity(code: json["code"],
        title: json["title"],
        icon: ThumbnailEntity.fromJson(json["icon"]),
      );

  Map<String, dynamic> toJson() => {
        "code": code,
        "title": title,
        "icon": icon.toJson(),};
}

// 图
class ThumbnailEntity {
  ThumbnailEntity({this.url,});

  String url;

  factory ThumbnailEntity.fromJson(Map<String, dynamic> json) =>
      ThumbnailEntity(url: json["url"],
      );

  Map<String, dynamic> toJson() => {"url": url,};
}
  • api

lib/common/apis/gql_news.dart

/// 新闻
class GqlNewsAPI {
  /// 首页
  static Future<GqlIndexResponseEntity> indexPageInfo({
    @required BuildContext context,
    Map<String, dynamic> params,
  }) async {
    QueryResult response =
        await GraphqlClientUtil.query(context: context, schema: GQL_INDEX_PAGE);

    return GqlIndexResponseEntity.fromJson(response.data);
  }

  /// 翻页
  static Future<List<GqlNewsResponseEntity>> newsPageList({
    @required BuildContext context,
    Map<String, dynamic> params,
  }) async {
    QueryResult response = await GraphqlClientUtil.query(context: context, schema: GQL_NEWS_LIST, variables: params);

    return response.data['busNews']
        .map<GqlNewsResponseEntity>((item) => GqlNewsResponseEntity.fromJson(item))
        .toList();}
}
  • 界面业务代码

lib/pages/main/main.dart

  GqlIndexResponseEntity _indexPageData; // 首页数据

  // 读取所有数据
  _loadAllData() async {_indexPageData = await GqlNewsAPI.indexPageInfo(context: context);
    ...

    if (mounted) {setState(() {});
    }
  }

  // 拉取举荐、新闻
  _loadNewsData(
    categoryCode, {bool refresh = false,}) async {
    _selCategoryCode = categoryCode;
    _newsPageList = await GqlNewsAPI.newsPageList(context: context, params: {"category_code": categoryCode});

    if (mounted) {setState(() {});
    }
  }

  ...

详见 git

资源

设计稿蓝湖预览

https://lanhuapp.com/url/lYuz1
明码: gSKl

蓝湖当初免费了,所以查看标记还请本人上传 xd 设计稿
商业设计稿文件不好间接分享, 能够加微信分割 ducafecat


© 猫哥

https://ducafecat.tech

退出移动版