项目描述

在信息技术飞速发展的今天,网购已经成为了现代人生活当中无法分割的一部分。网购在给千家万户带来遍历的同时,也极大地推动了物流产业的发展。在这样的时代背景之下,许许多多的小型快递包裹运输的物流公司如雨后春笋般冒出。而在物流公司的背后除了强大和货运团队,快递包裹运输的数据库管理系统也是必不可少的,用户寄件、查询包裹状态,以及公司进行数据统计分析都离不开一个好的数据库管理系统。所以这次的项目就是聚焦于包裹运输的数据库这一需求,对数据库进行设计分析和测试,并使用 $Uni-app$ 为其进行前端设计开发,使之成为一个切实可用的 $APP$,供在一个小型关系数据库的概念设计、 逻辑设计、 实现、 操作和维护方面的现实经验。

数据库设计

需求分析

主要功能

本系统主要是用于查询和管理快递包裹运输数据库,这次的应用场景的主要角色主要有货物、顾客、货运团队和管理员,其需求分别如下。

货物需求
  1. 记录货物的编号、类型、重量、始发地目的地信息、发货人收货人信息等基础信息;
  2. 记录货物从出发到到达的完整运输流程;
  3. 能通过重量和始发地目的地信息自动计算运费。
顾客需求
  1. 不需要登陆即可以使用相关功能;
  2. 能通过货物编号、寄件人信息或者收件人信息查询包裹状态;
  3. 能自主创建物流订单,递交寄件需求。
货运团队需求
  1. 需要登陆才能使用相关功能;
  2. 能修对自己团队运输的货物的运输流程进行添加操作;
  3. 能通过编号确认货物的目的地信息,确认有没有上错车发错线路。
管理员需求
  1. 需要登陆才能使用相关功能;
  2. 对某段时间的物流数据进行统计;
  3. 导出某个用户的个人清单;
  4. 对任意包裹进行统计分析和管理。

系统数据字典

数据字典通常包括数据项、数据结构、数据流、数据存储和处理过程5个部分。下面以数据字典卡片的形式来举例说明本系统的数据字典(以下所有参照完整性都具有级联删除和更新,所有主码均为编号且为自增形式)。

数据结构
实体集
  1. 包裹

    名字:Package;

    描述:记录包裹物理数据;

    定义:包裹=包裹编号+类型+重量+始发地+目的地+发货人+收货人+价格+发货时间+预计收货时间+最新物流编号,其中包裹编号唯一标识不同的包裹;

    完整性约束:所有信息要求非空,包裹编号要求不重复;

    参照完整性:最新物流编号参照物流信息。

  2. 物流信息

    名字:Transport;

    描述:记录包裹的每一次物流信息;

    定义:物流信息=当次物流编号+本轮物流始发地+本轮物流终点站+发出时间+物流状态(到达或在路上)+上一次物流的编号信息;

    完整性约束:除一次物流的编号信息外其他要求非空,当成物流编号要求不重复;

    参照完整性:上一次物流的编号信息参照本身也就是物流信息。

  3. 用户信息

    名字:User;

    描述:记录用户个人信息;

    定义:用户信息=会员编号+姓名+地址+电话号码;

    完整性约束:电话号码和姓名非空,身份证号要求不重复。

  4. 货运团队信息

    名字:Worker;

    描述:记录货运团队信息;

    定义:货运团队信息=账号(编号)+密码+员工姓名+电话号码;

    完整性约束:账号和密码要求非空,账号要求不重复。

  5. 管理员信息

    名字:Admin;

    描述:记录管理员信息;

    定义:管理员信息=账号(编号)+密码+管理员姓名+电话号码;

    完整性约束:账号和密码要求非空,账号要求不重复。

关系集
  1. 最新物流信息

    名字:NewInfo;

    描述:记录每一个包裹最新的物流信息,是联系包裹和物流信息的关系集;

    定义:最新物流信息=包裹编号+物流编号,其中我们包裹编号指定是哪一个包裹;

    完整性约束:包裹编号,物流编号要求非空且唯一标识一个包裹的最新物流信息。

  2. 上一条物流信息

    名字:LastInfo;

    描述:记录一条物流信息的上一条物流信息,也就是货物上一站的物流信息,是联系物流信息和物流信息自身的关系集;

    定义:上一条物流信息=这一条的物流编号+上一条物流编号,其中我们包裹编号指定是哪一个包裹。

    完整性约束:这一条的物流编号,上一条物流编号要求非空,类似于链表的一个结构。

  3. 寄件人与包裹

    名字:Send;

    描述:记录每个包裹的寄件人的详细信息,是关联用户和包裹的关系集;

    定义:寄件人与包裹=包裹编号+会员编号;

    完整性约束:包裹编号,身份证号非空且唯一标识一个包裹的寄件人信息。

  4. 收件人与包裹

    名字:Receive;

    描述:记录每个包裹的收件人的详细信息,是关联用户和包裹的关系集;

    定义:收件人与包裹=包裹编号+会员编号;

    完整性约束:包裹编号,身份证号非空且唯一标识一个包裹的寄件人信息。

  5. 货运团队与包裹

    名字:Traffic;

    描述:记录每个包裹所属的货运团队,是关联货运团队和包裹的关系集;

    定义:货运团队与包裹=包裹编号+员工编号;

    完整性约束:包裹编号,员工编号非空且唯一标识一个包裹。

  6. 管理员与管理的货运团队

    名字:Manage;

    描述:记录每个管理员所管理的货运团队,是关联货运团队和管理员的关系集;

    定义:管理员与管理的货运团队=管理员编号+货运团队编号;

    完整性约束:管理员编号,货运团队非空且唯一标识一个货运团队。

数据项

所有关系中,一共有多达43个数据项。这里仅给出不同意义下的数据项说明,其余定义仿照类似。

类型 定义
编号类 可变长字符串,最大长度为50
名称类 可变长字符串,最大长度为50
价格类 浮点型小数,总长度为10,小数点后保留两位
时间类 整数类型,形容20220121,
账号密码类 可变长字符串,最大长度为50

E-R模型

初步模型

我们根据上面的需求分析画出我们的E-R图。

1.png

消除冗余

我们发现 $Package$ 中的发货人 $fromerson$ 和收货人 $toperson$ 这一姓名信息在 $User$ 实体集中均以 $name$ 的形式时出现可以从 $Package$ 中移除,而对于发货地址和收货地址不一定和用户的住址一样,故不能移除,我们进行改进。

而对于物流信息 $ Transport$ 中的 $fromsite$ 和 $tosite$ 表达的是一段的运输旅程,与 $Package$ 中表达整段的运输旅程有区别,故也不可以省去。所以我们消除冗余后的 $E-R$ 图如下。

2.png

生成关系模型

初步生成

实体集

由于我们的实体集都是强实体集,所以我们可以将其生成如下:

  • Package:包含属性(PID,type, weight, fromsite, tosite, fromtime, totime, price);
  • Transport:包括属性(TID, fromsite, tosite, starttime, state);
  • User:包括属性(UID, name, site, telephone);
  • Worker:包括属性(ID, password, name, telephone);
  • Admin:包括属性(ID, password, name, telephone)。
关系集

我们的根据关系集的对应关系得到下列关系集:

  • NewInfo:包括属性(PID, TID);
  • LastInfo:包括属性(TID, lastTID);
  • Send:包括属性(PID, UID);
  • Receive:包括属性(PID, UID);
  • Traffic:包括属性(PID, ID);
  • Manage:包括属性(ID, AID)。

模式合并

我们的关系集有许多都是一对一或者一对多且大多的参与是全部的,所以我们可以考虑进行模式的合并。

  • NewInfo:对应实体集 $Package$ 和 $Transport$,由于 $Package$ 全部参与且为一对一的形式所以我们可以把 $NewInfo$ 合并到 $Package$ 当中。结果是 $Package$ 由属性 (PID,type, weight, fromsite, tosite, fromtime, totime, price, newTID) 组成;
  • LastInfo:对应实体集 $Transport$ 和 $Transport$ 自身,由于 $Transport$ 全部参与且为一对一的形式所以我们可以把 $LastInfo$ 合并到 $Transport$ 当中。结果是 $Transport$ 由属性 (TID, fromsite, tosite, starttime, state, lastTID) 组成;
  • Manage:对应属性集 $Worker$ 和 $Admin$,由于 $Worker$ 全部参与且每个 $Worker$ 只有一个 $Admin$,所以可以把 $Manage$ 合并到 $Worker$ 中。结果是 $Worker$ 由属性 (ID, password, name, telephone,adminID) 组成。

范式检测

在上一步中,我们完成了对关系的模式合并得到了现在的关系模型如下:

  • Package:包含属性(PID,type, weight, fromsite, tosite, fromtime, totime, price, newTID);
  • Transport:包括属性(TID, fromsite, tosite, starttime, state, lastTID);
  • User:包括属性(UID, name, site, telephone);
  • Worker:包括属性(ID, password, name, telephone, adminID);
  • Admin:包括属性(ID, password, name, telephone);
  • Send:包括属性(PID, UID);
  • Receive:包括属性(PID, UID);
  • Traffic:包括属性(PID, ID);

下面我们进行范式检测。

第一范式

我们第一范式的定义是:“一个域是原子的,如果该域的元素被认为是不可分的单元。我们称一个关系模式R属于第一范式,如果R的所有属性的域都是原子的”。我们按照这一标准对我们的所有属性进行检查。

我们之前已经将我们的属性分成了编号、名称、时间、价格和账号密码类。很明显,这其中的所有属性都是原子的,也就是不可分的,所以我们的关系符合第一范式。

第二范式

我们对第二范式的定义是:“第二范式是指每个表必须有主关键字(Primary key),其他数据元素与主关键字一一对应。”我们观察我们的每一个表,都有唯一的主关键字,且都是编号类的主关键字。

所以我们的关系无疑也是满足第二范式的。

BC范式

如果我们的关系模式满足BC范式,那么就是说对于关系模式R有函数依赖集F和其闭包 $F^{+}$,对 $F^{+}$ 中所有形如 $\alpha \to \beta$ ($\alpha,\beta \subseteq R$)的函数依赖,下面至少一项成立:

  1. $\alpha \to \beta$ 是平凡的函数依赖;
  2. $\alpha$ 是模式 $R$ 的一个超码。

我们发现,对于我们的所有关系模式,除了主码以外,其他属性都是可以重复的,所以 $\alpha$ 只能是包含了主码的一个集合。而包含了主码的集合一定是超码,所以我们的关系模式也满足BC范式。另外一提,分解不属于BC范式的方法,若有 $\alpha \to \beta$ 不满足上面条件,我们用 $(\alpha \cup \beta)$ 和 $(R - (\beta - \alpha))$ 替代 $R$ 即可。

第三范式

如果我们的关系模式满足第三范式,那么就是说对于 $F^{+}$ 中所有形如 $\alpha \to \beta$ ($\alpha,\beta \subseteq R$)的函数依赖,下面至少一项成立:

  1. $\alpha \to \beta$ 是平凡的函数依赖;
  2. $\alpha$ 是模式 $R$ 的一个超码;
  3. $\beta - \alpha$ 中的每个属性 $A$ 都包含于 $R$ 的一个候选码中。

我们知道,第三范式是比BC范式更加宽松的,我们的关系模式既然都已经满足了BC范式,自然也就满足了第三范式。

所以我们的关系模式是满足第一范式第二范式第三范式BC范式的。

生成数据

创建表

我们按照上面定义好的关系模型,使用下列 $SQL$ 语句完成对上述表的创建。

create table Transport (
    TID          varchar(50) NOT NULL,
    lastTID      varchar(50),
    starttime    varchar(50) NOT NULL,
    fromsite     varchar(50) NOT NULL,
    tosite       varchar(50) NOT NULL,
    state        varchar(50) NOT NULL,

    primary key (TID) ,
    foreign key (lastTID) references  Transport(TID)
);

create table Package (
    PID          varchar(50) NOT NULL,
    newTID       varchar(50) NOT NULL,
    type         varchar(50) NOT NULL,
    weight       float NOT NULL,
    fromsite     varchar(50) NOT NULL,
    tosite       varchar(50) NOT NULL,
    fromtime     int NOT NULL, 
    totime       int NOT NULL, 
    price        float,

    primary key (PID) ,
    foreign key (newTID) references  Transport(TID) on delete cascade
);

create table Userr (
    UID          varchar(50) NOT NULL,
    name         varchar(50) NOT NULL,
    site         varchar(50),
    telephone    varchar(50),

    primary key (UID)
);

create table Admin (
    ID           varchar(50) NOT NULL,
    password     varchar(50) NOT NULL,
    name         varchar(50) NOT NULL,
    telephone    varchar(50),

    primary key (ID)
);

create table Worker (
    ID           varchar(50) NOT NULL,
    password     varchar(50) NOT NULL,
    name         varchar(50) NOT NULL,
    telephone    varchar(50),
    AdminID      varchar(50) NOT NULL,

    primary key (ID),
    foreign key (AdminID) references  Admin(ID) on delete cascade
);

create table Send (
    PID          varchar(50) NOT NULL,
    UID          varchar(50) NOT NULL,

    primary key (PID),
    foreign key (PID) references  Package on delete cascade,
    foreign key (UID) references  Userr on delete cascade
);

create table Receive (
    PID          varchar(50) NOT NULL,
    UID          varchar(50) NOT NULL,

    primary key (PID),
    foreign key (PID) references  Package on delete cascade,
    foreign key (UID) references  Userr on delete cascade
);

create table Traffic (
    PID          varchar(50) NOT NULL,
    ID           varchar(50) NOT NULL,

    primary key (PID),
    foreign key (PID) references  Package on delete cascade,
    foreign key (ID)  references  Worker on delete cascade
);

我们可以看到运行成功。

3.png

插入数据

我们分别对每个表插入我们的数据。

用户

我们插入 $15$ 位用户的信息。

insert into Userr values ('19334001', 'Amateur', 'Guangzhou', '10001');
insert into Userr values ('19334002', 'Boycott', 'Shanghai', '10002');
insert into Userr values ('19334003', 'Cuba', 'Beijing', '10003');
insert into Userr values ('19334004', 'Diamond', 'Guangzhou', '10004');
insert into Userr values ('19334005', 'Electric', 'Shanghai', '10005');
insert into Userr values ('19334006', 'Function', 'Beijing', '10006');
insert into Userr values ('19334007', 'Gallery', 'Guangzhou', '10007');
insert into Userr values ('19334008', 'History', 'Shanghai', '10008');
insert into Userr values ('19334009', 'Icecream', 'Beijing', '10009');
insert into Userr values ('19334010', 'Joker', 'Guangzhou', '10010');
insert into Userr values ('19334011', 'Kate', 'Shanghai', '10011');
insert into Userr values ('19334012', 'Logic', 'Beijing', '10012');
insert into Userr values ('19334013', 'Monster', 'Guangzhou', '10013');
insert into Userr values ('19334014', 'Nightmare', 'Shanghai', '10014');
insert into Userr values ('19334015', 'Orange', 'Beijing', '10015');
管理员

我们插入 $2$ 位管理员的信息。

insert into Admin values ('0001', 'Jvruo233', 'Jvruo', '10086');
insert into Admin values ('0002', 'Mushu233', 'Mushu', '10068');
货运团队

我们插入 $3$ 支货运团队的信息。

insert into Worker values ('1000', 'Wuren', '123456', '23456', '0001');
insert into Worker values ('2000', 'Brohao', '123456', '34567', '0001');
insert into Worker values ('3000', 'Junyi', '123456', '45678', '0002');
物流信息

我们插入 $32$ 条物流信息。

insert into Transport values ('00001', NULL, '20200507', 'Guangzhou', 'Guangzhou', 'get');
insert into Transport values ('00002', '00001', '20200508', 'Guangzhou', 'Shanghai', 'wait');
insert into Transport values ('00003', '00002', '20200512', 'Shanghai', 'Shanghai', 'get');

insert into Transport values ('00004', NULL, '20200507', 'Guangzhou', 'Guangzhou', 'get');
insert into Transport values ('00005', '00004', '20200508', 'Guangzhou', 'Shanghai', 'wait');
insert into Transport values ('00006', '00005', '20200512', 'Shanghai', 'Shanghai', 'get');
insert into Transport values ('00007', '00006', '20200512', 'Shanghai', 'Beijing', 'wait');
insert into Transport values ('00008', '00007', '20200516', 'Beijing', 'Beijing', 'get');

insert into Transport values ('00009', NULL, '20200510', 'Shanghai', 'Shanghai', 'get');

insert into Transport values ('00010', NULL, '20200510', 'Shanghai', 'Shanghai', 'get');
insert into Transport values ('00011', '00010', '20200511', 'Shanghai', 'Beijing', 'wait');

insert into Transport values ('00012', NULL, '20200505', 'Beijing', 'Beijing', 'get');
insert into Transport values ('00013', '00012', '20200505', 'Beijing', 'Shanghai', 'wait');
insert into Transport values ('00014', '00013', '20200508', 'Shanghai', 'Shanghai', 'get');
insert into Transport values ('00015', '00014', '20200509', 'Shanghai', 'Guangzhou', 'wait');

insert into Transport values ('00016', NULL, '20200505', 'Beijing', 'Beijing', 'get');

insert into Transport values ('00017', NULL, '20200507', 'Guangzhou', 'Guangzhou', 'get');
insert into Transport values ('00018', '00017', '20200508', 'Guangzhou', 'Shanghai', 'wait');
insert into Transport values ('00019', '00018', '20200512', 'Shanghai', 'Shanghai', 'get');

insert into Transport values ('00020', NULL, '20200507', 'Guangzhou', 'Guangzhou', 'get');
insert into Transport values ('00021', '00020', '20200508', 'Guangzhou', 'Shanghai', 'wait');
insert into Transport values ('00022', '00021', '20200512', 'Shanghai', 'Shanghai', 'get');
insert into Transport values ('00023', '00022', '20200512', 'Shanghai', 'Beijing', 'wait');
insert into Transport values ('00024', '00023', '20200516', 'Beijing', 'Beijing', 'get');

insert into Transport values ('00025', NULL, '20200510', 'Shanghai', 'Shanghai', 'get');

insert into Transport values ('00026', NULL, '20200510', 'Shanghai', 'Shanghai', 'get');
insert into Transport values ('00027', '00026', '20200511', 'Shanghai', 'Beijing', 'wait');

insert into Transport values ('00028', NULL, '20200505', 'Beijing', 'Beijing', 'get');
insert into Transport values ('00029', '00028', '20200505', 'Beijing', 'Shanghai', 'wait');
insert into Transport values ('00030', '00029', '20200508', 'Shanghai', 'Shanghai', 'get');
insert into Transport values ('00031', '00030', '20200509', 'Shanghai', 'Guangzhou', 'wait');

insert into Transport values ('00032', NULL, '20200505', 'Beijing', 'Beijing', 'get');
包裹

我们插入 $12$ 条包裹信息。

insert into Package values ('00001', '00001', 'cloth', 3.7, 'Guangzhou', 'Shanghai', '20200507', '20200514', 3.7);
insert into Package values ('00002', '00004', 'toys', 5.4, 'Guangzhou', 'Beijing', '20200507', '20200514', 10.8);
insert into Package values ('00003', '00009', 'toys', 1.3, 'Shanghai', 'Guangzhou', '20200510', '20200517', 1.3);
insert into Package values ('00004', '00010', 'gun', 11.3, 'Shanghai', 'Beijing', '20200510', '20200517', 11.3);
insert into Package values ('00005', '00012', 'toys', 1.3, 'Beijing', 'Guangzhou', '20200505', '20200512', 2.6);
insert into Package values ('00006', '00016', 'gun', 11.3, 'Beijing', 'Shanghai', '20200505', '20200512', 11.3);

insert into Package values ('00007', '00017', 'cloth', 3.7, 'Guangzhou', 'Shanghai', '20200507', '20200514', 3.7);
insert into Package values ('00008', '00020', 'toys', 5.4, 'Guangzhou', 'Beijing', '20200507', '20200514', 10.8);
insert into Package values ('00009', '00025', 'toys', 1.3, 'Shanghai', 'Guangzhou', '20200510', '20200517', 1.3);
insert into Package values ('000010', '00026', 'gun', 11.3, 'Shanghai', 'Beijing', '20200510', '20200517', 11.3);
insert into Package values ('000011', '00028', 'toys', 1.3, 'Beijing', 'Guangzhou', '20200505', '20200512', 2.6);
insert into Package values ('000012', '00032', 'gun', 11.3, 'Beijing', 'Shanghai', '20200505', '20200512', 11.3);
寄件与收件人

我们插入 $12$ 条寄件人与包裹关系以及 $12$ 条收件人与包裹关系。

insert into Send values ('00001', '19334001');
insert into Send values ('00002', '19334001');
insert into Send values ('00003', '19334005');
insert into Send values ('00004', '19334005');
insert into Send values ('00005', '19334009');
insert into Send values ('00006', '19334009');
insert into Send values ('00007', '19334007');
insert into Send values ('00008', '19334007');
insert into Send values ('00009', '19334011');
insert into Send values ('00010', '19334011');
insert into Send values ('00011', '19334015');
insert into Send values ('00012', '19334015');

insert into Receive values ('00001', '19334002');
insert into Receive values ('00002', '19334003');
insert into Receive values ('00003', '19334004');
insert into Receive values ('00004', '19334006');
insert into Receive values ('00005', '19334007');
insert into Receive values ('00006', '19334008');
insert into Receive values ('00007', '19334008');
insert into Receive values ('00008', '19334009');
insert into Receive values ('00009', '19334010');
insert into Receive values ('00010', '19334012');
insert into Receive values ('00011', '19334013');
insert into Receive values ('00012', '19334014');
货运团队与包裹

我们插入货运团队和负责包裹的 $12$ 条记录信息。

insert into Traffic values ('00001', '1000');
insert into Traffic values ('00002', '1000');
insert into Traffic values ('00003', '1000');
insert into Traffic values ('00004', '1000');
insert into Traffic values ('00005', '2000');
insert into Traffic values ('00006', '2000');
insert into Traffic values ('00007', '2000');
insert into Traffic values ('00008', '2000');
insert into Traffic values ('00009', '3000');
insert into Traffic values ('00010', '3000');
insert into Traffic values ('00011', '3000');
insert into Traffic values ('00012', '3000');

我们可以看到运行成功。

4.png

相关任务实现

用户功能

查询和自己相关的所有包裹

要实现查询某个顾客的所有包裹,就要查询他发出的件和收到的件,假如我们要查询 $Amateur$ 的相关物流信息,我们首先要从用户信息中找到 $Amateur$ 的编号或者说是身份证号,然后查找到所有寄件人或者收件人是这个编号的包裹的编号,最后我们展示这些包裹编号下包裹的完整信息就可以了。我们就可以写出下列查询语句。

select *
from Package
where PID in (select PID
              from Send
              where UID in (select UID
                            from Userr
                            where name = 'Amateur')
              Union
              select PID
              from Receive
              where UID in (select UID
                            from Userr
                            where name = 'Amateur'))

5.png

查询给定单号包裹的完整物流信息

要查询给定包裹的完整物流信息,就要使用到递归的方法去遍历整一条物流链,假如我们要查询 $00002$ 的完整物流信息。具体来说,我们需要用到 $with$ 语句来完成我们的递归,我们从最近的物流信息开始,不断寻找上一条该货物的物流信息,直到所有信息都被发掘展示为止。

with find
as
(
  select * from Transport
  where TID = (select newTID
               from Package
               where PID = '00002')
  union all
  select temp.TID, temp.lastTID, temp.starttime, temp.fromsite, temp.tosite, temp.state
  from Transport temp
  inner join find on temp.[TID] = find.[lastTID]
)
select * from find

6.png

创建一个新的物流订单

要创建一个新的物流订单,我们只需要填写相关物流信息并创建一个新的揽货物流状态就好了,然后我们还需要绑定我们的寄件人和收货人信息,最后别忘了把我们最新的物流状态指向我们新开的揽货的物流状态。假如我们想让 $19334001$ 发给 $19334009$ 一个包裹,我们可以这么写。

insert into Transport values ('00033', NULL, '20200505', 'Guangzhou', 'Guangzhou', 'get');
insert into Package values ('00013', '00033', 'cloth', 5.4, 'Guangzhou', 'Beijing', '20200507', '20200514', 10.8);

insert into Send values ('00013', '19334001');
insert into Receive values ('00013', '19334009');

7.png

货运团队功能

查询一个货运团队下货物的信息

要实现查询一个货运团队下货物的信息,就只要通过 $Traffic$ 关系找到这个团队负责的货物的 $PID$,再展示出来就可以了。比如假如我们想查询 $1000$ 团队下的货物信息,我们就可以写出下面这段代码。

select *
from Package
where PID in (select PID
              from Traffic
              where ID = '1000')

8.png

添加一段物流信息

添加一段物流信息要做的事情有两件,首先是我们要新建一段物流信息,并且上一物流信息指向之前这个包裹最新的物流信息;其次我们要更改一下我们这个包裹最新的物流信息指向我们新建的这一段物流信息,这和链表的插入是非常类似的。

insert into Transport values ('00033', '00009', '20200511', 'Shanghai', 'Guangzhou', 'wait');
update Package
    set newTID = '00033'
    where newTID = '00009'

9.png

管理者功能

统计寄件最多的客户

要统计寄件最多的顾客,我们只要先计算出所有顾客的寄件数,然后找到寄件数等于寄件数当中最大值的顾客就可以了。

select *
from (select UID as ID, count(PID) as num
      from Send
      group by UID)temp
where num = (select max(now.op)
             from (select count(PID) as op
                   from Send
                   group by UID)now
             )

10.png

统计运费总计最高的客户

和统计寄件最多的顾客是一样的,要统计运费总计最高的客户,我们只要先计算出所有顾客的运费数量,然后找到运费总额等于运费总额当中最大值的顾客就可以了。

select *
from (select UID as ID, sum(price) as total
      from Send inner join Package on Send.PID = Package.PID
      group by Send.UID) temp
where temp.total = (select max(op)
                    from (select sum(price) as op
                          from Send inner join Package on Send.PID = Package.PID
                          group by Send.UID) now
                   )

11.png

统计没有按时送达的快递

要统计没有按时送达的快递也非常简单,我们只需要将快递预计送达时间和现在最新的物流时间对比,如果现在的最新物流时间已经超过了预计时间,那就是铁定超时了;反之则不一定超时。我们输出那些铁定超时了的就好了。

select *
from Package
where totime < (select starttime
                from Transport
                where TID = newTID)

12.png

APP开发

框架部分

这次的开发我们采取 $Uniapp$ 进行开发,历时近一个星期,共产生代码近 $20k$,设计了带底部导航栏的物流仓储 $APP$ 系统。大致效果如下图所示,下面我将一个一个页面介绍我们的实现框架。

Q1.png

首先是全局的一些设置,我们要在 $pages$ 里定义一些全局的东西。比如我们要在 $pages$ 里定义一下我们用到的页面,在 $globalStyle$ 中定义一些全局的风格设置,再在 $tabBar$ 定义我们最下一行的导航栏。

{
    "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
        {
            "path": "pages/index/index"
        },
        {
            "path": "pages/message/message",
            "style": {
                "navigationBarTitleText":"信息页"
            }
        },
        ……//用到的页面
    ],
    "globalStyle": {
        "navigationBarTextStyle": "black",
        "navigationBarTitleText": "快递包裹运输",
        "navigationBarBackgroundColor": "#F8F8F8",
        "backgroundColor": "#F8F8F8",
        "enablePullDownRefresh": true
    },
    "tabBar": {
        "list": [
            {
                "text": "首页",
                "pagePath": "pages/index/index",
                "iconPath": "static/tab/A0.png",
                "selectedIconPath":"static/tab/A.png"
            },
            {
                "text": "包裹查询",
                "pagePath": "pages/message/message",
                "iconPath": "static/tab/C0.png",
                "selectedIconPath":"static/tab/C.png"
            },
            {
                "text": "新建包裹",
                "pagePath": "pages/contact/contact",
                "iconPath": "static/tab/B0.png",
                "selectedIconPath":"static/tab/B.png"
            },
            {
                "text": "管理功能",
                "pagePath": "pages/manage/manage",
                "iconPath": "static/tab/D0.png",
                "selectedIconPath":"static/tab/D.png"
            }
        ]
    }
}

接着是对于每个页面的实现,首先是对于查询快递信息的页面实现。由于我们的包裹不多,所以我使用了按钮的方式来选择包裹而不是输入的方式。不过在实验之后细细想来,这样虽然更加便捷但是对于用户的隐私性就完全没有保障了,这样就可以让任意一个用户看到任意一个快递的情况,这显然不是我们想要的,我们的框架也很简单,就是点击按钮跳转到我们的页面。页面则对应我们下面说到的数据库操作中的查询操作。当然这里的对每一个包裹是要相较于遍历数据库而言的,这里就先用伪代码来标注。

<template>
    <div>
        <view v-for 对于每一个包裹>
            <navigator url="/pages/package/package" open-type="navigate">
                <view class="struct">
                    <button type="primary">查询包裹的物流信息</button>
                </view>
            </navigator>
        </view>

    </div>

</template>

<script>

</script>

<style>

</style>

然后是添加新包裹的界面,我们要做的就是获取信息并插入到我们的数据库当中,我们关于数据库的部分还是先用伪代码的形式来代替。

<template>
    <view>
        <view><input type="text" placeholder="请输入寄件人姓名" @confirm="save1" /></view>
        <view><input type="text" placeholder="请输入收货人姓名" @confirm="save2" /></view>
        <view><input type="text" placeholder="请输入发货地" @confirm="save3" /></view>
        <view><input type="text" placeholder="请输入收货地" @confirm="save4" /></view>
        <view><input type="text" placeholder="请输入货物类型" @confirm="save5" /></view>
        <view><input type="text" placeholder="请输入货物重量" @confirm="save6" /></view>
        <view><input type="text" placeholder="请输入货物价格" @confirm="save7" /></view>
        <navigator url="/pages/succeedorfailed" open-type="navigate">
            <view class="struct">
                <button type="primary">提交</button>
            </view>
        </navigator>
    </view>
</template>

<script>
    let id = 0
    export default {
        data() {
            return {
                list: [],
            }
        },
        computed: {
            一些计算函数
        },
        methods: {
            保存到缓存并插入到数据库的操作
        }
    }
</script>

<style>

</style>

管理员界面也是比较简单的我们只要把按钮做出来,剩下的交给跳转页面中的数据库操作就可以了。

<template>
    <div>
        <navigator url="/pages/function/function1" open-type="navigate">
            <view class="struct">
                <button type="primary">查询寄件最多的人</button>
            </view>
        </navigator>

        <navigator url="/pages/function/function2" open-type="navigate">
            <view class="struct">
                <button type="primary">查询寄件金额最大的人</button>
            </view>
        </navigator>

        <navigator url="/pages/function/function3" open-type="navigate">
            <view class="struct">
                <button type="primary">查询超时快递</button>
            </view>
        </navigator>
    </div>

</template>

<script>

</script>

<style>

</style>

SQLite

由于我们的物流信息可能很庞大,如果直接用 $uniapp$ 自带的缓存就不行了,所以我们要使用数据库我们一般使用 $sqlite$ 的方法来进行数据库的调用,并且把 $sqlite$ 的使用方法封装在 $js$ 文件里了,这样就可以根据自己的需求来封装。
首先我们要在先在manifest.json里的App模块权限配置里勾选SQLite(数据库)!!!

13.png

连接SQL

openDB(){
    plus.sqlite.openDatabase({
        name:'pop',  //数据库名称
        path:'_doc/pop.db',   //数据库地址,没有文件自动创建
        success(){
            console.log("打开成功"); //成功回调
        },
        fail(e){
            console.log(e); //失败回调
        }
    })
}

创建表

creatDB(){
    plus.sqlite.executeSql({
        name:'pop',
        //表格创建或者打开,后面为表格结构
        sql:'create table ……', 
        success(res){
            console.log("创建成功")
        },
        fail(e){
            console.log(e)
        }
    })
}

添加数据

insertDB(){
    plus.sqlite.executeSql({
        name:'pop',
        sql:'insert into ……',//正常sql语句
        success(){
            console.log("新增成功");
        },
        fail(e){
            reject(e);
        }
    })
}

查询数据

selectDB(){
    plus.sqlite.selectSql({
        name:'pop',
        sql:"select * from ……",//正常sql语句
        success(res){
            console.log(res);
        },
        fail(e){
            console.log(e);
        }
    })
},

更改数据

updateDB(){
    plus.sqlite.executeSql({
        name:'pop',
        sql:"update ……",//正常sql语句
        success(res){
            console.log(res);
        },
        fail(e){
            console.log(e);
        }
    })
}

删除数据

deleteDB(){
    plus.sqlite.executeSql({
        name:'pop',
        sql:"delete from …… ",//正常sql语句
        success(res){
            console.log(res);
        },
        fail(e){
            console.log(e);
        }
    })
}

我们将之前的设计数据库的部分调用这些函数就和 $ODBC$ 非常类似了。但是可惜的是这个 $sqlite$ 似乎只能在 $APP$ 中使用,在小程序中使用会有奇怪的问题。

结果展示

首页展示

我们的首页就是简单的项目图标和作者介绍。

Q1.png

运单信息

我们查询订单物流情况采取的是点击按钮的形式。

Q2.png

点击按钮就能进入相应的物流情况,可以看到路线图和完整的物流情况:

Q3.png

Q4.png

添加运单

我们可以在添加订单中填写信息进行提交。

Q5.png

但是如果遇到不合法情况会返回不合法信息。

Q6.png

管理员功能

管理员的查询功能如下。

Q7.png

点击按钮就可以进入相关查询。

Q8.png

Q9.png

Q10.png

实验总结

在这次实验中,我从零开始搭建了属于自己的数据库 $APP$。虽然过程中遇到了非常多的问题,但是最后能一一解决还是非常开心的。最后希望你喜欢这篇$BLOG$!

Last modification:March 21st, 2022 at 10:49 am
If you think my article is useful to you, please feel free to appreciate