『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 50711|回复: 89

[经验分享] 米家门锁通过多模接入ha后利用自动化分离门和锁的状态下

  [复制链接]

76

主题

1359

帖子

1万

积分

元老级技术达人

积分
18502
金钱
17103
HASS币
290
发表于 2021-1-5 14:22:03 | 显示全部楼层 |阅读模式
本帖最后由 dscao 于 2023-3-5 17:10 编辑

2023年3月4日更新:
经过论坛帖子的学习,今天突然想到仅用模板就可以解决这个门锁状态的问题。新版的template有trigger可以用了,如果再有环境条件就可以更简化了。

现在的gateway3集成的小米蓝牙门锁的实体已经有 binary_sensor.xxxxxxx_contact 门的开关状态了,大部分自动化也够用了。

再增加“门内开锁,指纹开锁”等信息就可以了。

1.jpg




sensor.e50b9a2d2a9f_action 换成自己门锁的 action实体ID即可。重启ha不影响各模板实体状态。

代码也可以放在packages目录下的一个yaml文件中:

template:
  - trigger:
      - platform: state
        entity_id:
          - sensor.e50b9a2d2a9f_action
        attribute: message
        to:
          - 'Unlock outside the door'
          - 'Lock'
          - 'Turn on anti-lock'
          - 'Turn off anti-lock'
          - 'Unlock inside the door'
          - 'Lock inside the door'
          - 'Turn on child lock'
          - 'Turn off child lock'
          - 'Knock on the door'
          - 'Breaking the door'
          - 'Door is stuck'
        not_from:
          - unknown
          - unavailable      
    sensor:
      name: xiaomi_smartlock_state
      unique_id: xiaomi_smartlock_state
      state: |
        {% if is_state_attr('sensor.e50b9a2d2a9f_action','action_id',0) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"lock") %}
          门外开锁
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',1) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"lock") %}
          上提把手上锁
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',2) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"lock") %}
          反锁
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',3) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"lock") %}
          解除反锁
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',4) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"lock") %}
          门内开锁
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',5) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"lock") %}
          门内上锁
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',6) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"lock") %}
          开启童锁
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',7) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"lock") %}
          关闭童锁
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',0) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"door") %}
          开门 
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',1) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"door") %}
          关门
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',2) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"door") %}
          超时未关
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',3) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"door") %}
          敲门
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',4) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"door") %}
          门被破坏
        {% elif is_state_attr('sensor.e50b9a2d2a9f_action','action_id',5) and is_state_attr('sensor.e50b9a2d2a9f_action','action',"door") %}
          门卡住了
        {% else %}
          action_id:{{ state_attr('sensor.e50b9a2d2a9f_action','action_id') }}
        {% endif %} 
        
  - trigger:
      - platform: state
        entity_id:
          - sensor.e50b9a2d2a9f_action
        attribute: method_id
        to: 
          - 0
          - 1
          - 2
          - 3
          - 4
          - 5
          - 6
          - 7
          - 8
          - 10
          - 11
        not_from:
          - unknown
          - unavailable
      - platform: state
        entity_id:
          - sensor.e50b9a2d2a9f_action
        to: lock
        not_from:
          - unknown
          - unavailable          
    sensor:
      name: xiaomi_smartlock_open_method
      unique_id: xiaomi_smartlock_open_method
      state: |
        {% if state_attr('sensor.e50b9a2d2a9f_action','method_id') == 0 %}
          蓝牙
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 1 %}
          密码
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 2 %}
          指纹
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 3 %}
          钥匙
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 4 %}
          转盘
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 5 %}
          NFC
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 6 %}
          一次性密码
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 7 %}
          双重验证
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 8 %}
          强制
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 10 %}
          人工
        {% elif state_attr('sensor.e50b9a2d2a9f_action','method_id') == 11 %}
          自动
        {% else %}
          method_id:{{ state_attr('sensor.e50b9a2d2a9f_action','method_id') }}
        {% endif %} 
  - trigger:
      - platform: state
        entity_id:
          - sensor.e50b9a2d2a9f_action
        attribute: key_id
        to: 
          - 0
          - 1
          - 2
          - 3
          - 4
          - 5
          - 6
          - 7
          - 8
          - 9
          - 10
          - 11
          - 12
          - 13
          - 14
          - 15
          - 16
          - 17
          - 18
          - 19
          - 20
          - 'ffffffff'
          - 'DEADBEEF'
          - 0xc0de0000
          - 0xc0de0001
          - 0xc0de0002
          - 0xc0de0003
          - 0xc0de0004
          - 0xc0de0005
          - 0xc0de0006
          - 0xc0de0007
          - 0xc0de0008
          - 0xc0de0009
          - 0xc0de000a
          - 0xc0de000b
          - 0xc0de000c
          - 0xc0de000d
          - 0xc0de000e
          - 0xc0de000f
          - 0xc0de0010
          - 0xc0de1000
          - 0xc0de1001
          - 0xc0de1002
          - 0xc0de1003
          - 0xc0de1004
    sensor:
      name: xiaomi_smartlock_open_key
      unique_id: xiaomi_smartlock_open_key
      state: |
        {% if state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0 %}
          管理员
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 2 %}
          我的指纹
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 6 %}
          我的右手指纹
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 1 %}
          我的密码
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 3 %}
          老爸的指纹
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 5 %}
          老婆的指纹
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 7 %}
          老婆的右手指纹
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 'ffffffff' %}
          未知操作者
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 'DEADBEEF' %}
          无效操作者
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0000 %}
          错误的密码解锁次数过多
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0001 %}
          错误指纹解锁次数过多
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0002 %}
          操作超时(密码输入超时)
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0003 %}
          开锁
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0004 %}
          重置按钮被按下
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0005 %}
          钥匙弄错次数过多
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0006 %}
          钥匙孔内有异物
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0007 %}
          钥匙未取出
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0008 %}
          错误的NFC频繁解锁
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0009 %}
          超时未按要求锁定
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de000a %}
          多种方式频繁解锁失败
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de000b %}
          人脸解锁失败次数过多
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de000c %}
          静脉解锁失败次数过多
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de000d %}
          劫持报警
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de000e %}
          布防后在门内解锁
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de000f %}
          掌纹解锁失败次数过多
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de0010 %}
          保险被移除
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de1000 %}
          电池电量低于 10%
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de1001 %}
          电池电量低于 5%
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de1002 %}
          指纹传感器异常
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de1003 %}
          附件电池电量低
        {% elif state_attr('sensor.e50b9a2d2a9f_action','key_id') == 0xc0de1004 %}
          机械故障
        {% else %}
          {{ state_attr('sensor.e50b9a2d2a9f_action','key_id') }}
        {% endif %}
        
  - trigger:
      - platform: state
        entity_id: sensor.e50b9a2d2a9f_action
    sensor:
      name: xiaomi_smartlock_do_time
      unique_id: xiaomi_smartlock_do_time
      state: >
        {{ as_local(states.sensor.e50b9a2d2a9f_action.last_changed).strftime('%Y-%m-%d %H:%M:%S') }}


大大简化之前的方法,看起来效果几乎一样。

另非常感谢 louis_lee 大佬 在 76楼的分享。



-------上面代码更新后,以下部分已弃用-(非参考思路的话可以不看了)----




-----------------2021-10-10 更新----------------------
XiaomiGateway3 v1.5.1-rc.1已经修复action的bug。


-----------------2021-9-30 更新----------------------
多模网关插件 XiaomiGateway3 1.5.0被作者标记了一处Bug,https://github.com/AlexxIT/XiaomiGateway3/issues/469。
暂时可将代码中的锁动作显示中文的触发条件的到状态值由 lock 改为 key_id。

或者手动修改插件1.5.0中的代码,sensor.py 中324行:
将 elif k in ('key_id', 'lock_control', 'lock_state'):
改为 elif k in ('lock_control', 'lock_state'):

估计下一版作者应该会修复吧,修复后按原来的就可以了。


-----------------以下部分由 dscao 于 2021-1-31 01:48 编辑-----------------------

看到有坛友也提出这个思路或问题,我把我现在用的方法也分享一下,不过也还有一些不足的地方,希望也能找到更好的方案。

多模网关中门锁中门状态和锁状态共用一个 sensor.XXXXXX_action  ,导致用新建模板sensor,会出现有时一个为空。

所以利用自动化判断action来设定门的状态和锁的状态及其它相关的状态。

首先要安装 python_script,在ha的config目录中加入 python_scripts/set_state.py

内容为:
if 'entity_id' not in data:
    logger.warning("===== entity_id is required if you want to set something.")
else:
    data = data.copy()
    inputEntity = data.pop('entity_id')
    inputStateObject = hass.states.get(inputEntity)
    if inputStateObject:
        inputState = inputStateObject.state
        inputAttributesObject = inputStateObject.attributes.copy()
    else:
        inputState = 'unknown'
        inputAttributesObject = {}
    if 'state' in data:
        inputState = data.pop('state')
    logger.debug("===== new attrs: {}".format(data))
    inputAttributesObject.update(data)

    hass.states.set(inputEntity, inputState, inputAttributesObject)

在 configuration.yaml 加入一句:
python_script:   
启用这个。

2021年1月31日更新,门状态通过模板,因为只有开和关两种状态,可以不需要自动化来更新了,但锁状态还是要通过自动化来更新。:

设置几个模板Sensor,可以在packages目录下的yaml文件中:
binary_sensor:
  - platform: template
    sensors:
      smartlock_door:
        friendly_name: 门状态
        value_template: >-
          {% if (is_state_attr('sensor.e50b9a2dxxxx_action','action_id',0) and is_state_attr('sensor.e50b9a2dxxxx_action','action',"door")) or (is_state_attr('sensor.e50b9a2dxxxx_action','action_id',2) and is_state_attr('sensor.e50b9a2dxxxx_action','action',"door"))%}
            on
          {% else %}
            off
          {% endif %}
        icon_template: >-
          {% if (is_state_attr('sensor.e50b9a2dxxxx_action','action_id',0) and is_state_attr('sensor.e50b9a2dxxxx_action','action',"door")) or (is_state_attr('sensor.e50b9a2dxxxx_action','action_id',2) and is_state_attr('sensor.e50b9a2dxxxx_action','action',"door"))%}
            mdi:door-open
          {% else %}
            mdi:door-closed-lock
          {% endif %}


sensor:
  - platform: template      
    sensors:
      smartlock_state:
        friendly_name: 门锁状态
        value_template: 未知
      smartlock_method: 
        friendly_name: 开门方式
        value_template: 未知 
      smartlock_user: 
        friendly_name: 操作者
        value_template: 未知
      smartlock_changetime:
        friendly_name: 操作时间
        value_template: >-
          {% if as_timestamp(states.sensor.e50b9a2dxxxx_action.last_updated) > as_timestamp(states.sensor.xi_tong_qi_dong_shi_jian.state) %}
            {{ as_local(states.sensor.e50b9a2dxxxx_action.last_changed).strftime('%Y-%m-%d %H:%M:%S') }}
          {% else %}
            无
          {% endif %}

          
homeassistant:
  customize:
    sensor.smartlock_state:
      icon: mdi:lock-smart
    sensor.smartlock_method:
      icon: mdi:lock-question
    sensor.smartlock_user:
      icon: mdi:human-handsdown
    sensor.smartlock_changetime:
      icon: mdi:lock-clock



一个自动化改变锁的状态,门的状态上面通过模板可自动更新:
alias: 锁动作显示中文
description: ''
trigger:
  - platform: state
    entity_id: sensor.e50b9a2dxxxx_action
    to: lock
condition: []
action:
  - service: python_script.set_state
    data:
      entity_id: sensor.smartlock_method
      state: |
        {% if trigger.to_state.attributes['method_id'] == 0 %}
          蓝牙
        {% elif trigger.to_state.attributes['method_id'] == 1 %}
          密码
        {% elif trigger.to_state.attributes['method_id'] == 2 %}
          指纹
        {% elif trigger.to_state.attributes['method_id'] == 3 %}
          钥匙
        {% elif trigger.to_state.attributes['method_id'] == 4 %}
          转盘
        {% elif trigger.to_state.attributes['method_id'] == 5 %}
          NFC
        {% elif trigger.to_state.attributes['method_id'] == 6 %}
          一次性密码
        {% elif trigger.to_state.attributes['method_id'] == 7 %}
          双重验证
        {% elif trigger.to_state.attributes['method_id'] == 10 %}
          人工
        {% elif trigger.to_state.attributes['method_id'] == 11 %}
          自动
        {% else %}
          method_id:{{ trigger.to_state.attributes['method_id'] }}
        {% endif %}  
  - service: python_script.set_state
    data:
      entity_id: sensor.smartlock_state
      state: |
        {% if is_state_attr('sensor.e50b9a2dxxxx_action','action_id',0) %}
          门外开锁
        {% elif is_state_attr('sensor.e50b9a2dxxxxx_action','action_id',1) %}
          上提把手上锁
        {% elif is_state_attr('sensor.e50b9a2dxxxx_action','action_id',2) %}
          反锁
        {% elif is_state_attr('sensor.e50b9a2dxxxx_action','action_id',3) %}
          解除锁
        {% elif is_state_attr('sensor.e50b9a2dxxxx_action','action_id',4) %}
          门内开锁
        {% elif is_state_attr('sensor.e50b9a2dxxxx_action','action_id',5) %}
          门内上锁
        {% elif is_state_attr('sensor.e50b9a2dxxxx_action','action_id',6) %}
          开启童锁
        {% elif is_state_attr('sensor.e50b9a2dxxxx_action','action_id',7) %}
          关闭童锁  
        {% else %}
          action_id:{{ state_attr('sensor.e50b9a2dxxxx_action','action_id') }}
        {% endif %} 
  - service: python_script.set_state
    data:
      entity_id: sensor.smartlock_user
      state: |
        {% if trigger.to_state.attributes['key_id'] == 0 %}
          管理员
        {% elif trigger.to_state.attributes['key_id'] == 2 %}
          我的指纹
        {% elif trigger.to_state.attributes['key_id'] == 6 %}
          我的右手指纹
        {% elif trigger.to_state.attributes['key_id'] == 1 %}
          我的密码
        {% elif trigger.to_state.attributes['key_id'] == 3 %}
          老爸的指纹
        {% elif trigger.to_state.attributes['key_id'] == 5 %}
          老婆的指纹
        {% elif trigger.to_state.attributes['key_id'] == 7 %}
          老婆的右手指纹
        {% elif trigger.to_state.attributes['key_id'] == 'ffffffff' %}
          未知操作者
        {% elif trigger.to_state.attributes['key_id'] == 'DEADBEEF' %}
          无效操作者 
        {% else %}
          {{ trigger.to_state.attributes['key_id'] }}
        {% endif %}
mode: single



效果:












评分

参与人数 6金钱 +54 收起 理由
juno277 + 2
jajanuj + 1 感谢楼主分享!
louis_lee + 16 来抄作业啦!
adr + 5 膜拜大神!
+ 20 感谢楼主分享!
0703005 + 10 谢谢楼主,这样下来省去了一个8266.

查看全部评分

回复

使用道具 举报

3

主题

150

帖子

941

积分

高级会员

Rank: 4

积分
941
金钱
791
HASS币
0
发表于 2021-1-5 15:08:23 | 显示全部楼层
本帖最后由 Sourdough 于 2021-1-5 15:13 编辑

谢谢分享,从另外一个帖子过来啦,我想请问一下是怎么实现区分老爸指纹和其他用户指纹开门的,我在那个帖子的意思是好像这些用户信息现有的插件没有推送到到HA
------------------------------------------------------------
我回复的太快了,看到你更新了最后那段代码,所以请问一下key id是在哪里查看呢?
回复

使用道具 举报

21

主题

427

帖子

2417

积分

金牌会员

Rank: 6Rank: 6

积分
2417
金钱
1985
HASS币
20
发表于 2021-1-5 15:40:45 | 显示全部楼层
感谢分享!
新版ha,自动化这个缩进貌似不能直接粘贴到yaml使用啊。
automation:
  - alias: 门锁动作显示中文
    trigger:

我的这个缩进
回复

使用道具 举报

76

主题

1359

帖子

1万

积分

元老级技术达人

积分
18502
金钱
17103
HASS币
290
 楼主| 发表于 2021-1-5 16:07:07 | 显示全部楼层
AnyLine 发表于 2021-1-5 15:40
感谢分享!
新版ha,自动化这个缩进貌似不能直接粘贴到yaml使用啊。

我就是从自动化,右上角,以yaml编辑,复制出来的,应该可以直接复制进去,可能要修改一下门锁的实体ID才能保存。原来是用ui写的。
回复

使用道具 举报

76

主题

1359

帖子

1万

积分

元老级技术达人

积分
18502
金钱
17103
HASS币
290
 楼主| 发表于 2021-1-5 16:09:15 | 显示全部楼层
Sourdough 发表于 2021-1-5 15:08
谢谢分享,从另外一个帖子过来啦,我想请问一下是怎么实现区分老爸指纹和其他用户指纹开门的,我在那个帖子 ...

用指纹开锁试一下,在门锁Action的属性中就有。实际上小米锁添加指纹或密码时的顺序,但不成功也会占一个序号。
回复

使用道具 举报

21

主题

427

帖子

2417

积分

金牌会员

Rank: 6Rank: 6

积分
2417
金钱
1985
HASS币
20
发表于 2021-1-5 16:14:19 | 显示全部楼层
dscao 发表于 2021-1-5 16:07
我就是从自动化,右上角,以yaml编辑,复制出来的,应该可以直接复制进去,可能要修改一下门锁的实体ID才 ...

好像不对啊,你是哪个版本的ha?
我的打开automations.yaml文件的话里面是
- id: '1609752430998'
  alias: 新建自动化
  description: ''

开头的自动化或者
- alias: 门锁动作显示中文2
  description: ''
  trigger:


如果是别的yaml文件,手动写进自动化应该

automation:
  - alias: 门动作显示中文1
    description: ''
    trigger:

开头加上automation:
回复

使用道具 举报

21

主题

427

帖子

2417

积分

金牌会员

Rank: 6Rank: 6

积分
2417
金钱
1985
HASS币
20
发表于 2021-1-5 16:19:34 | 显示全部楼层
本帖最后由 AnyLine 于 2021-1-5 16:34 编辑

效果图里的门锁日志那个是哪个实体的历史记录呢?
回复

使用道具 举报

76

主题

1359

帖子

1万

积分

元老级技术达人

积分
18502
金钱
17103
HASS币
290
 楼主| 发表于 2021-1-5 16:41:09 | 显示全部楼层
AnyLine 发表于 2021-1-5 16:19
效果图里的门锁日志那个是哪个实体的历史记录呢?

那是新版ha中 编辑仪表盘 UI中的自带的日志卡片
02.jpg
回复

使用道具 举报

12

主题

242

帖子

2397

积分

论坛技术达人

积分
2397
金钱
2155
HASS币
30
发表于 2021-1-5 16:48:46 | 显示全部楼层
用 action_id 和 method_id 判断比这个靠谱些, 翻译随时会变的
回复

使用道具 举报

3

主题

334

帖子

2018

积分

金牌会员

Rank: 6Rank: 6

积分
2018
金钱
1684
HASS币
0
发表于 2021-1-6 03:26:41 | 显示全部楼层
“首先要安装python_script,在哈的配置目录中加入python_scripts / set_state.py”  大佬你的这一句我不理解,我是通过PVE安装的hassos  怎么添加呢?  还望能给小白讲解下。 谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-5-5 23:43 , Processed in 0.143342 second(s), 35 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表