粥里有勺糖

vuePress-theme-reco 粥里有勺糖    2018 - 2023
粥里有勺糖 粥里有勺糖

Choose mode

  • dark
  • auto
  • light
关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
author-avatar

粥里有勺糖

285

文章

40

标签

关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
  • wheel

    • 个人作品
    • 时间管理CLI工具
    • 组装个支持记笔记的CodePen
    • ESCheck工具原理解析及增强实现
    • 一款检测代码中TODO的eslint插件
    • 实现一个Web UI检测(视觉走查)工具ing
    • 从0-1实现文件下载CLI工具
    • 内联JS处理(ES语法降级&内容压缩)
    • Node CLI工具原理解析
    • 我打造的在线简历生成应用
    • 助你轻松编写与分享snippet的VsCode插件
    • SourceMap解析CLI工具实现
    • 一个通过NPM包共(分)享代码块的解决方案
    • 实践:给女朋友个性化定制应用-体重记录(一)
    • 实践:给女朋友个性化定制应用-体重记录(二)
    • 实践:给女朋友个性化定制应用-体重记录(三)

实践:给女朋友个性化定制应用-体重记录(二)

vuePress-theme-reco 粥里有勺糖    2018 - 2023

实践:给女朋友个性化定制应用-体重记录(二)

粥里有勺糖 2021-06-15 技术笔记个人作品

# 实践:给女朋友个性化定制应用-体重记录(二)

此系列的目的是帮助前端新人,熟悉现代前端工程化开发方式与相关技术的使用,普及一些通识内容

# 前景回顾

上一篇文章,主要阐述了应用前端工程的搭建与部分页面开发

本文简单介绍一下一期剩余的页面(体重记录页)开发,着重阐述后端部分的必要设计

# 本文涉及内容

  • 体重记录页的开发
  • 初始化后端Node+TypeScript项目
  • 数据库设计
  • 接口设计
  • 云数据库初始化

# 体重记录页开发

  • 完整源码 (opens new window)

页面整体上由导航,最近一次的记录,对比描述,历史记录,添加数据弹窗等5部分组成

# 导航

直接使用vant-nav-bar (opens new window)

左按钮返回上一页,右按钮(icon) 唤起添加添加成员的弹窗: van-dialog (opens new window)

<van-nav-bar
  title="体重记录"
  @click-left="handleBack"
  @click-right="handleAddPeople"
  left-text="返回"
  left-arrow
>
  <template #right>
    <van-icon name="plus" size="18" />
  </template>
</van-nav-bar>
1
2
3
4
5
6
7
8
9
10
11

效果

图片

引入Dialog组件注意: 由于Dialog支持直接当作方法使用Dialog(options),再当作组件注册时与其它组件不太一样:

src/utils/vantUI.ts

import { Button, Dialog } from 'vant'

const conponents = [Button]
export default function mountVantUI(app: App<Element>) {
  conponents.forEach((c) => {
    app.component(c.name, c)
  })
  // 特别对待
  app.component(Dialog.Component.name, Dialog.Component)
}
1
2
3
4
5
6
7
8
9
10

# 最近一次的记录

展示一下时间与体重即可

<h2 class="current-time">2021-06-15 12:00:00</h2>
<h1 class="current-weight">48.12<span>公斤</span></h1>
1
2

效果

图片

# 对比描述

包含最新的一次记录与

  • 上一次比较
  • 与今天第一次比较
  • 与本月第一次比较

展示间隔的时间,并反应上升/下降的体重

页面结构

<p class="rank" v-for="(t, idx) in overviewData" :key="idx">
  {{ t.text }}
  <span :class="t.symbol"></span>
  <span class="res">{{ t.res }}</span>
</p>

<!-- 渲染结果示例 -->
<p class="rank">
  与上一次比较(5小时前)
  <span class="add"></span>
  <span class="res">5 公斤</span>
</p>
1
2
3
4
5
6
7
8
9
10
11
12

效果

图片

其中↑与↓的表示采用伪元素::after表示

  .dec::after {
    content: '🠐';
    color: green;
    transform: rotate(-90deg);
  }
  .inc::after {
    content: '🠖';
    color: #ff6034;
    transform: rotate(-90deg);
  }
1
2
3
4
5
6
7
8
9
10

日期差值计算的工具方法 (opens new window)

const ONE_SECONDS = 1000
const ONE_MINUTE = ONE_SECONDS * 60
const ONE_HOUR = ONE_MINUTE * 60
const ONE_DAY = ONE_HOUR * 24
function getTimeDiffDes(d1: Date, d2: Date) {
  const diff = d1.getTime() - d2.getTime()
  //   天
  if (diff / ONE_DAY >= 1) {
    return `${Math.round(diff / ONE_DAY)}天前`
  }

  // 小时
  if (diff / ONE_HOUR >= 1) {
    return `${Math.round(diff / ONE_HOUR)}小时前`
  }
  // 分钟
  if (diff / ONE_MINUTE >= 1) {
    return `${Math.round(diff / ONE_MINUTE)}分钟前`
  }
  // 秒
  return `${Math.round(diff / ONE_SECONDS)}秒前`
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 历史数据展示

直接套用Vant的 van-swipe-cell (opens new window)与 van-cell (opens new window)

<van-swipe-cell v-for="(t, idx) in weights" :key="idx">
  <van-cell :border="false" :title="formatDate(t.date)">
    {{ t.weight }}
  </van-cell>
  <template #right>
    <van-button @click="hadnleDeleteWeight(idx)" square type="danger" text="删除" />
  </template>
</van-swipe-cell>
1
2
3
4
5
6
7
8

效果

图片

# 页面最终效果

图片

  • 线上预览 (opens new window)

# 初始化后端工程

直接使用搭建的ATQQ/node-server (opens new window)模板初始化项目 (opens new window)

图片

# 模板工程简介

图片

# 数据库设计

使用: 腾讯云开发CloudBase提供的云数据库 (opens new window) (文档型数据库)

这样从头到尾都不需要买云服务器

# 相关需求简单回顾

  • 短信验证码登录
  • 支持同时记录多个人的数据
  • 每个数据包含 日期与体重两部分内容

简单捋一下思路,使用三张表用户表(user),成员表(family),记录表(record),具体设计如下

# 用户表-user

字段 类型 描述
userId String 唯一标识
phone String 手机号
joinTime Date 注册时间

# 成员表-family

字段 类型 描述
familyId String 唯一标识
userId String 关联创建用户
name String 成员名称

# 记录表-record

字段 类型 描述
recordId String 唯一标识
familyId String 关联成员
userId String 关联创建用户
weight Number 体重
date Date 日期

# 初始化云数据库

服务端使用Node.js开发,使用云开发提供的Node SDK初始化集合(表)

安装依赖

yarn add @cloudbase/node-sdk
1

# 初始化集合

const cloudbase = require('@cloudbase/node-sdk')
const app = cloudbase.init({
    secretId:process.env.secretId,
    secretKey:process.env.secretKey,
    env:process.env.envId
})

const db = app.database();
db.createCollection('user')
db.createCollection('family')
db.createCollection('record')
1
2
3
4
5
6
7
8
9
10
11

可以在CloudBase-数据库面板看到结果:

图片

# 接口设计

按数据库对接口进行分类,这里只阐述请求方法与路径

使用Eolinker管理与测试接口:此处查看完整接口设计 (opens new window)

# User

方法 路径 描述
POST /user/login 用户登录
GET /user/code 获取登录验证码

# Family

方法 路径 描述
POST /family/add 添加成员

# Record

方法 路径 描述
POST /record/:familyId 添加记录
DELETE /record/:recordId 删除记录

# 后端开发

# 数据库操作方法封装

根据文档云开发 CloudBase > 开发指南 > 数据库 (opens new window)编写

# JS版本

const cloudbase = require('@cloudbase/node-sdk')
const app = cloudbase.init({
    secretId:process.env.secretId,
    secretKey:process.env.secretKey,
    env:process.env.envId
})

const db = app.database();
function insertDocument(collection, data) {
    return db.collection(collection).add(data)
}

function deleteDocument(collection, query) {
    return db.collection(collection).where(query).remove()
}

function findDocument(collection, query) {
    return db.collection(collection).where(query).get()
}

function updateDocument(collection, query, data) {
    return db.collection(collection).where(query).update(data)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# TS版本

import cloudbase from '@cloudbase/node-sdk'
const app = cloudbase.init({
    secretId: process.env.secretId,
    secretKey: process.env.secretKey,
    env: process.env.envId
})

export const db = app.database()
export function insertDocument<T>(collection: string, data: T | T[]) {
    return db.collection(collection).add(data)
}

export function deleteDocument(collection: string, query: any) {
    return db.collection(collection).where(query).remove()
}

export function findDocument(collection: string, query: any) {
    return db.collection(collection).where(query).get()
}

export function updateDocument<T>(collection: string, query: any, data:T) {
    return db.collection(collection).where(query).update(data)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 未完待续

篇幅有限,下一章节再介绍后端部分的详细实现与前后端对接(/(ㄒoㄒ)/~~,主要还是没码完)

# 资料汇总

  • 前端项目源代码 (opens new window)
  • 后端项目源代码 (opens new window)
  • 后端项目模板 (opens new window)
  • 数据库设计 (opens new window)
  • 详细接口设计 (opens new window)
  • 腾讯云数据库地址 (opens new window)
  • 项目线上预览地址 (opens new window)
Edit this page (opens new window)
Last Updated: 2022/5/15 12:46:34