DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • BBS

  • 订单平台

  • CRM

  • flask+layui

  • django+layui

  • 供应链

    • 供应链开发第一天
    • 供应链开发第二天
    • 供应链开发第三天
    • 供应链开发第四天
    • 供应链开发第五天
      • 发布运单-页面
        • 大致布局
        • 抽屉展示
      • 抽屉数据加载
      • 选择实现
      • 后端视图扩展 res
      • 运单发布
        • 数据表的设计
        • CreateModelMixin
      • 运单管理
      • 电子签
    • 供应链开发第六天
    • 供应链开发第七天
  • 实战
  • 供应链
DC
2023-12-26
目录

供应链开发第五天

# 发布运单-页面

相较之前的页面,需要掌握的新的知识是element-plus里的 抽屉, 用于实现历史地址!!

# 大致布局

代码都写过了,此处关键在于分析页面的布局.

image-20240202205959320

Ps: 货物类型处的下拉框内容,本应该在进入发布运单页面时onMounted里向后端发送请求获得,这里简化了,直接在前端写死了,Hhhh.

快捷日期的选择,关键代码如下: (钱包功能那的日期是日期段,运单这里是某个日期)

<template>
<el-form label-width="80px" style="max-width: 500px;">
    <el-form-item label="发货时间" :error="state.formError.from_date">
        <el-date-picker
            v-model="state.form.from_date"
            type="date"
            placeholder="计划发货时间"
            :disabled-date="disabledDate"
            :shortcuts="shortcuts"
            format="YYYY-MM-DD"
            value-format="YYYY-MM-DD"
            style="width: 100%"
        />
</el-form>
</template>

<script setup>
const shortcuts = [
    {
        text: '今天',
        value: new Date(),
    },
    {
        text: '明天',
        value: () => {
            const date = new Date()
            date.setTime(date.getTime() + 3600 * 1000 * 24)
            return date
        },
    }
]
const state = reactive({
    form: {
        from_date: "",
    },
    formError: {
        from_date: "",
    },
})
// 这样设置后,今日以前的日期都选不了!! (当然,没有该需求的话,可以不设置:disabled-date="disabledDate"
function disabledDate(time) {
    return time.getTime() < Date.now()
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 抽屉展示

点击地址库, 出现抽屉, 用于展示历史地址.

抽屉区域,默认隐藏; 点击地址库,展示抽屉!!

image-20240202220508252


# 抽屉数据加载

点击地址库按钮,会出现抽屉,里面是应是地址列表!
即弹出抽屉时, 会向后端发送请求获取当前登陆用户的地址库!!

先来看看效果!

29

准备工作:后端有关地址库的模型迁移生成数据表后,为了方便测试,我们手动在数据表中添加了几行数据!!

你可以发现,我点击了“地址库”按钮后,发送了一个请求;当我关闭抽屉,再次点击“地址库”,抽屉中也会有数据,不会再次发送请求啦!
你不经要问,why?
因为地址库中的数据,不会经常更新,就没必要点一次“地址库”按钮就从后端获取一次,
即取一次有了,后需的点击该按钮对应的方法中就不会再发送请求啦!
在前端代码中的体现在于showAddressTable方法中的return!注:state.addressLoaded一开始我们设置的值为false.
1
2
3
4
5
6
7

关键代码如下:

image-20240204134714398

PS: 针对该功能,为了优化用户体验,我们还会在数据表中加一个代表使用频率的字段,返回给前端时根据该字段来进行排序. 暂略.


# 选择实现

当我们选中某个地址库中的一行数据, 会自动在表单对应的位置赋值上数据!!

先来看看效果!!

30

为了区分选中后,是给发货地址、还是收获地址自动赋值, 我们需要给点击事件showAddressTable添加参数"from"、"to" !!
关键代码如下: (只需要写点前端代码就可以实现啦!!)

image-20240204142150897


# 后端视图扩展 res

钩子有返回值就直接返回返回值给前端!!

image-20240204170043564


# 运单发布

ψ(`∇´)ψ

# 数据表的设计

为了完成该需求, 新增了4张表.

image-20240205085232854

看上面这张截图,针对截图中新增的这四张表, 结合业务场景作一点说明:

[Order运单表]
- status运单状态: 
  已发布-后台管理人员审核通过后变为待接单-等待司机接单,司机接单后变为待提货
  -提货后变为运输中-运输到目的地后变为待结算-给了司机钱后,变为已结算. 另外,发布后可取消,哪怕司机已接单,也可协商下取消.
  只不过,在这里为了方便测试,其默认值为1,即待接单,默认发布后后台管理人员已经审核通过了.
- goods_type货物类型: 理论上前端应发送一个请求来获取它,但我犯懒了,在前端直接写死了,就是为了少发一个请求来获取货物类型Hhhh
- title货物名称
- cost货物价值:即一车货值多少钱
- oid订单号:
  这里准确点来说,是运单号!!跟交易记录里的充值、提现时,我们自己生成的订单号是两码事哦!!
  当然运单发布成功后,也会产生一条交易记录,其类型是“下单”,So,还得改一下交易记录表的ORM模型,哈哈哈
  tran_type_choices = ((-2, "下单"), (-1, "提现"), (1, "充值"), (2, "取消"))
  tran_type = models.SmallIntegerField(verbose_name="转账类型", choices=tran_type_choices)
  order_id = models.CharField(verbose_name="运单号", max_length=64, null=True, blank=True, db_index=True)
- weight货物重量:运单发布时需要预估货物重量 
- settle_weight货物结算重量:司机装货后会称重,是准确的,所以在发布运单时该值可以为空
- unit_price运单单价
- 发货地址相关字段 from_addr  from_name  from_mobile  from_date
- 收获地址相关字段 to_addr  to_name  to_mobile  to_date
- ctime创建时间:会自动生成
- company供应商:需指明哪个供应商提供的
- driver接单司机:哪个司机接单的 (一开始是空的,接单后才会关联上!)
  
[Driver司机表]
参考着供应商表来实现 与供应商表相比,就多了个字段plate_number
注意:我们简化了一下,每个司机只绑定了一个车牌,事实上可绑定多辆车,绑定过程需要认证,上传行驶证之类的!

[DriverAuth司机认证表]
和供应商认证表一样,还有个供应商认证表,两者倒差不差

[OrderRecord订单运输记录表]
还要考虑一些变化,比如司机接了单,临时有事去不了了等.所以会加上一个订单的运输记录表! 
比如A司机在什么时候接单了,A司机又在什么时候取消订单了,B司机又在什么时候接单了.具体的事情都会写在remark描述里.
- order哪个订单
- ctime时间
- remark描述
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# CreateModelMixin

运单发布, 就是CURD中的增, 但会在此的基础上根据业务需求加上一些逻辑!!

31

先在交易记录表中修改和新增点东西.
运单发布后会添加一条下单记录,在下单记录的表格里可看到运单号,点击运单号可查看运单详情信息; 当然发布的运单也可以取消!

tran_type_choices = ((-2, "下单"), (-1, "提现"), (1, "充值"), (2, "取消"))
tran_type = models.SmallIntegerField(verbose_name="交易类型", choices=tran_type_choices)
order_id = models.CharField(verbose_name="运单号", max_length=64, null=True, blank=True, db_index=True)
1
2
3

关键代码如下: (请结合着 运单发布-数据表的设计 这一小节进行分析)

image-20240205142232827

你观察视图函数,在新增逻辑的基础上根据业务需求加上一些逻辑!!
需要注意的是,在生成一条运单数据时,使用地址表中的id是不合适的!!
你试想,后续一旦地址库中的地址发送变动,那么与其关联的运单就会同步进行变动.
比如原本是成都到重庆,改成了成都到北京,距离变长了,佣金没变,该种情况是不允许出现的.

----

注意同类型的比较!!
unit_price*weight 单价*重量 与 当前登陆的供应商自己的可用余额balance 进行比较.
这三个字段都是DecimalField类型的数据!!注:前端传递过来的对应字段值是字符串,但提交过来后,其值在内部会转化成ORM表中字段的类型!!

----

在save时,ORM表中的绝大部分都用,零星几个不用,编写代码时用exclude!!

----

?突然犯病卡壳了,driver在ORM表中,是可为空的.So,运单发布是新增,这里不写driver字段也没事!!
紧接着,我想了一些问题 (这些都是老生常谈的问题了..无语子,说了很多遍了
1> 如果我写了,用APIFOX模拟前端发送请求,该请求携带的json数据中,包含了driver字段,会怎么样?
2> driver字段是外键字段,回想下ORM语句,可以是driver,也可以是driver_id,又是怎么一个场景?
我进行了一系列的实践,比如
- driver是外键,不为空
  - exclude = ["company", "oid"] 前端传了driver,后端会自动检验外键字段在关联表中是否存在
  - driver_id = serializers.IntegerField()  exclude = ["company", "driver", "oid"] 
    前端传了driver_id, 若关联表中不存在该值,在save时会报错FOREIGN KEY constraint failed
- ◇ driver是外键,可为空
  - exclude = ["company", "driver", "oid"]  ◇ 前端传driver,传driver_id 都不起任何作用,当没传
  - exclude = ["company", "oid"]  前端传了driver,后端会自动检验外键字段在关联表中是否存在
还有其他的搭配方案.话说回来,这些实践看似很复杂,实则记住下面这个逻辑就行:
  [0] 要清楚的意识到前端传递的json,就是为序列化器类服务的,哪些要哪些不要,一切还得序列化器说的算Hhh
  [1] 拿捏序列化器类中所有字段对象,进行分类 可验证的字段对象/可写、可序列化的字段对象/可读
  [2] 可验证的字段对象 --> 进行验证 --> 验证通过validated_data --> 进行save存储,save时候还可额外传递一些数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 运单管理

运单管理页面, 很多功能的具体实现都跟"我的钱包"那的"交易记录"是类似的, 所以在这里我们将会省略具体的步骤!!

页面长这样哦!!

image-20240205183054918

来品一品新知识,哈哈哈

image-20240205182857620

可以发现,页面可以分为几个区域 面板标题、按钮组(运单状态相关)、搜索条件、功能区、表格+分页
1> 按钮组和搜索条件功能的实现:参考"我的钱包"里"交易记录"的搜索
   若运单运单状态以下拉框的形式放在表单里,一切都一样啦,此处是放到按钮组里的,问题不大!!依旧是url参数的形式传递过去.
2> 表格和分页和前面的差不多,多的新知识是 在表格里加了个多选, 选中后触发的方法可以拿到选中的那些行!!
   @selection-change="handleSelectionChange"
   <el-table-column type="selection" width="55"/>
3> 功能区有个下拉菜单,这是个新知识!点击某个选项,同样会触发某个方法,拿到特定的值
   你可以进行if判断,当是某个值的时候执行某个操作.
4> 在这个业务场景中,获取列表数据和新增数据,序列化器类应该这么设计
   - oid我们将其设置为了只读,而不是放到exclude列表中.
     是因为只读,获取时返回,提交的时候不用.
     代入业务场景:‘
        oid发布运单时候,前端不用传,也不用返回它,就放到exclude中了,只是说sava新增时要自己生成一个传进去
        oid展示列表时候,需要在表格中展示它
   - DecimalField类型的字段,coerce_to_string值设置为False,是让序列化返回时以浮点型返回,而不是字符串类型
     你看下源码,还可以全局设置哦!!
class OrderModelSerializer(serializers.ModelSerializer):
    # oid = serializers.CharField(read_only=True)
    status_text = serializers.CharField(source='get_status_display')
    class Meta:
        model = models.Order
        # fields = "__all__"
        exclude = ["company", "driver"]
        extra_kwargs = {
            "unit_price": {"coerce_to_string": False},
            "weight": {"coerce_to_string": False},
            "oid": {"read_only": True},
        }
5> 关于按钮组里的内容,标准的流程应该是在页面在onMounted中发个请求获取,只不过有时候偷懒,就在前端写死了哈哈哈.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 电子签

额,用到了再说吧,了解了下,不是很明白..Hhh 略.

▲ 在线签合同 途径
  - 腾讯电子签
    - 企业用户
    - 个人用户,仅支持小程序
  - 君子签
  
▲ 在线签合同 方式
  - 人工 
    ==> 注册企业账号-创建合同模板-发起合同-签署
  - 程序
    腾讯给提供了两种环境:正式环境、沙箱环境
    以供应链系统为例,平台需作为中间方与供应商签署合同、也需与司机签署合同
    So,平台需要自动实现一些功能
    1> 自动生成PDF格式合同, 只有合同部分信息(不包含签署信息)
    2> 自动上传给腾讯电子签
    3> 自定义签署位置
       - 坐标来找位置
       - 关键字找位置(推荐)
    4> 触发签合同
       - 自动签署,公章上传平台 + 开通自动签章的服务.(企业静默签)
       - 手动签署,小程序扫码
    5> 对方签完了怎么通知我们? 电子签平台通知.(网址)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

供应链开发第四天
供应链开发第六天

← 供应链开发第四天 供应链开发第六天→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式