当前位置:   article > 正文

物联网实战--平台篇之(九)分组界面设计

物联网实战--平台篇之(九)分组界面设计

目录

一、界面设计

二、项目工程概览

三、分组切换

四、分组管理

五、新建分组

六、编辑分组


 本项目的交流QQ群:701889554

物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html

物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html

本项目资源文件 https://download.csdn.net/download/ypp240124016/89317308

一、界面设计

                

上图是米家APP关于分组管理的界面,主页面是选项卡+视图的模式,分组管理可以删除和排序,重命名它需要单机某个分组再进入一层界面进行操作,我们做些省略,下图是模仿的界面。

                

             

     

二、项目工程概览

以下是针对这部分界面的项目代码结构图,主要分为两部分,一是分组切换页面——GroupTabView,二是分组管理页面——GroupEditView,其它都是对话框类型的,下面对这些内容做具体讲解。

三、分组切换

        分组就是下图红框里的内容,每个名称都是一个选项卡,下面对应的界面内容也会跟着切换,原本想着用QT自带的TabView来实现,后面发现达不到想要的效果,实际上米家APP里的选项卡和页面内容是分开的,是通过当前页面值关联起来的。所以后面就自己实现了这个过程,相对比较啰嗦点。

  1. import QtQuick 2.7
  2. import QtQuick.Controls 2.12
  3. import "../base"
  4. Rectangle
  5. {
  6. color: "transparent"
  7. ListView//滑动tab bar
  8. {
  9. id:id_tabBarView
  10. clip:true
  11. orientation: ListView.Horizontal
  12. height: 40
  13. anchors
  14. {
  15. left:parent.left
  16. right:id_listButton.left
  17. }
  18. model: ListModel{
  19. id:id_tabBarModel
  20. }
  21. delegate: Rectangle{
  22. height: 40
  23. width: id_titleText.contentWidth+15
  24. color: "transparent"
  25. Text{
  26. id:id_titleText
  27. height: parent.height
  28. width: 20
  29. anchors.centerIn: parent
  30. font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"
  31. font.pointSize: 18
  32. font.bold: id_tabBarView.currentIndex===id
  33. text: group_name
  34. verticalAlignment: Text.AlignVCenter
  35. horizontalAlignment: Text.AlignHCenter
  36. }
  37. MouseArea
  38. {
  39. anchors.fill: parent
  40. onClicked:
  41. {
  42. id_tabBarView.currentIndex=id
  43. }
  44. }
  45. }
  46. onCurrentIndexChanged:
  47. {
  48. id_mainView.currentIndex=currentIndex
  49. }
  50. }
  51. GroupNewDialog
  52. {
  53. id:id_groupNewDialog
  54. }
  55. GroupManDialog
  56. {
  57. id:id_groupManDialog
  58. onSiqNewGroup: //新建分组
  59. {
  60. id_groupNewDialog.funOpen("新分组")
  61. }
  62. onSiqManGroup: //分组管理
  63. {
  64. theAccountMan.setHomeCurrView("home-group")
  65. }
  66. onSiqOpenGroup:
  67. {
  68. id_tabBarView.currentIndex=id
  69. id_mainView.currentIndex=id
  70. }
  71. }
  72. Rectangle{ //列表按钮
  73. id:id_listButton
  74. height: id_tabBarView.height*0.8
  75. width: height*1.5
  76. anchors
  77. {
  78. right:parent.right
  79. rightMargin:15
  80. verticalCenter:id_tabBarView.verticalCenter
  81. }
  82. radius: height/2
  83. color: "#BFC5D6"
  84. ImageButton01{
  85. anchors.centerIn: parent
  86. height: parent.height*0.85
  87. width: height
  88. source: "qrc:/mainImgRC/images/home/list.png"
  89. onSiqClickedLeft:
  90. {
  91. id_groupManDialog.open()
  92. }
  93. }
  94. }
  95. SwipeView { //主页面切换
  96. id: id_mainView
  97. width: parent.width
  98. anchors
  99. {
  100. top:id_tabBarView.bottom
  101. bottom:parent.bottom
  102. }
  103. Repeater {
  104. model: ListModel{
  105. id:id_mainModel
  106. }
  107. Rectangle {
  108. color: "transparent"
  109. Text{
  110. anchors.centerIn: parent
  111. font.pointSize: 18
  112. text: id
  113. }
  114. }
  115. }
  116. onCurrentIndexChanged: {
  117. id_tabBarView.currentIndex=currentIndex
  118. }
  119. }
  120. Component.onCompleted:
  121. {
  122. for(var i=0; i<1; i++)
  123. {
  124. id_tabBarModel.append({"id":i, "group_name":"全部"})
  125. id_mainModel.append({"id":i, "group_name":"全部"})
  126. }
  127. }
  128. Connections
  129. {
  130. target: theCenterMan
  131. onSiqAddGroup:
  132. {
  133. if(index===0)
  134. {
  135. id_tabBarModel.clear()
  136. id_mainModel.clear()
  137. id_tabBarModel.append({"id":0, "group_name":"全部"})
  138. id_mainModel.append({"id":0, "group_name":"全部"})
  139. }
  140. index=id_tabBarModel.count
  141. id_tabBarModel.append({"id":index, "group_name":group_name})
  142. id_mainModel.append({"id":index, "group_name":group_name})
  143. }
  144. onSiqRenameGroup:
  145. {
  146. for(var i=1; i<id_tabBarModel.count; i++)
  147. {
  148. var group_name=id_tabBarModel.get(i).group_name
  149. if(group_name===old_name)
  150. {
  151. id_tabBarModel.setProperty(i, "group_name", new_name)
  152. id_mainModel.setProperty(i, "group_name", new_name)
  153. break
  154. }
  155. }
  156. }
  157. onSiqDelGroup:
  158. {
  159. for(var i=1; i<id_tabBarModel.count; i++)
  160. {
  161. if(group_name===id_tabBarModel.get(i).group_name)
  162. {
  163. id_tabBarModel.remove(i)
  164. id_mainModel.remove(i)
  165. break
  166. }
  167. }
  168. }
  169. }
  170. }

        分组切换具体代码如上所示,主要分为Tab和View两部分,Tab用一个ListView,这样就可以实现滑动而不切换的效果了,如果是QT的TabView,点一下就会切换过去,没法用。

        ListView核心就两个内容,模型和单元格,即model和delegate两个属性,模型一般采用ListModel,通过操作ListModel实例就可以改变单元格的内容以及增减单元格等操作了。delegate就是单元格具体内容了,在这里主要就是文本,另外背景的矩形要改成透明的,这样APP的背景色才能透出来,还有一个是鼠标,点击后会触发切换,tab切换后又会联动下方的主视图切换,这样两者就关联起来了。

        主页面是一个SwipeView ,这个是之前常用的模块了,后面这个页面是要承载设备显示用的,暂时没什么用处,就显示个页码。

四、分组管理

        在tab的右边有一个按钮,是触发分组管理用的,下面是分组管理的具体代码,是一个对话框,显示内容有三个——新建分组、编辑分组和各分组的显示。其中分组显示采用一个ListView列表视图,显示组名和组内设备数量。

  1. import QtQuick 2.7
  2. import QtQuick.Controls 2.14
  3. import "../base"
  4. //分组管理弹框
  5. Popup {
  6. signal siqNewGroup()
  7. signal siqManGroup()
  8. signal siqOpenGroup(var id, var group_name)
  9. property var rowHeight: 40
  10. id:id_popup
  11. visible: false
  12. implicitWidth: parent.width*0.6
  13. implicitHeight: rowHeight*(id_listModel.count+2)+id_popup.topPadding+id_popup.bottomPadding
  14. modal: true
  15. focus: true
  16. closePolicy: Popup.CloseOnEscape | Popup.CloseOnReleaseOutside
  17. x:parent.width*0.3
  18. y:10
  19. background: Rectangle
  20. {
  21. radius:15
  22. }
  23. Rectangle//分割横线
  24. {
  25. id:id_lineRect
  26. width: parent.width*0.8
  27. height: 1
  28. color:"#F0F0F0"
  29. anchors
  30. {
  31. horizontalCenter:parent.horizontalCenter
  32. bottom:parent.bottom
  33. bottomMargin:rowHeight*2
  34. }
  35. }
  36. TextButton01//新建按钮
  37. {
  38. id:id_newButton
  39. height: rowHeight
  40. width: parent.width
  41. anchors
  42. {
  43. left:parent.left
  44. leftMargin:10
  45. top:id_lineRect.bottom
  46. }
  47. textValue: "新建"
  48. onSiqClickedLeft:
  49. {
  50. id_popup.close()
  51. siqNewGroup()
  52. }
  53. Image//新建图标
  54. {
  55. width: height
  56. height: parent.height*0.6
  57. mipmap: true
  58. anchors
  59. {
  60. verticalCenter:parent.verticalCenter
  61. right:parent.right
  62. rightMargin:15
  63. }
  64. source: "qrc:/mainImgRC/images/home/new.png"
  65. }
  66. }
  67. TextButton01//分组管理
  68. {
  69. id:id_manButton
  70. height: id_newButton.height
  71. width: parent.width
  72. anchors
  73. {
  74. left:parent.left
  75. leftMargin:10
  76. top:id_newButton.bottom
  77. }
  78. textValue: "管理"
  79. onSiqClickedLeft:
  80. {
  81. id_popup.close()
  82. siqManGroup()
  83. }
  84. Image//管理图标
  85. {
  86. width: height
  87. height: parent.height*0.5
  88. mipmap: true
  89. anchors
  90. {
  91. verticalCenter:parent.verticalCenter
  92. right:parent.right
  93. rightMargin:17
  94. }
  95. source: "qrc:/mainImgRC/images/home/man.png"
  96. }
  97. }
  98. ListView
  99. {
  100. clip: true
  101. width: parent.width
  102. anchors
  103. {
  104. top:parent.top
  105. bottom:id_lineRect.top
  106. }
  107. model: ListModel{
  108. id:id_listModel
  109. }
  110. delegate: Rectangle{
  111. height: rowHeight
  112. width: parent.width
  113. TextButton01//分组按钮
  114. {
  115. id:id_groupButton
  116. height: rowHeight
  117. width: parent.width-20
  118. anchors
  119. {
  120. left:parent.left
  121. leftMargin:10
  122. verticalCenter:parent.verticalCenter
  123. }
  124. textValue: group_name
  125. onSiqClickedLeft: //打开某个分组
  126. {
  127. id_popup.close()
  128. siqOpenGroup(id, group_name)
  129. }
  130. Text{
  131. id:id_totalNumText
  132. height: parent.height
  133. width: 30
  134. anchors{
  135. right: parent.right
  136. verticalCenter: parent.verticalCenter
  137. }
  138. color: "#808080"
  139. font.family: "宋体"
  140. font.pointSize: 18
  141. text: total_num
  142. verticalAlignment: Text.AlignVCenter
  143. horizontalAlignment: Text.AlignHCenter
  144. }
  145. }
  146. }
  147. }
  148. Component.onCompleted:
  149. {
  150. for(var i=0; i<1; i++)
  151. {
  152. id_listModel.append({"id":i, "group_name":"全部", "total_num":0})
  153. }
  154. }
  155. Connections
  156. {
  157. target: theCenterMan
  158. onSiqAddGroup:
  159. {
  160. if(index===0)
  161. {
  162. id_listModel.clear()
  163. id_listModel.append({"id":0, "group_name":"全部", "total_num":total_num})
  164. }
  165. index=id_listModel.count
  166. id_listModel.append({"id":index, "group_name":group_name, "total_num":total_num})
  167. }
  168. onSiqRenameGroup:
  169. {
  170. for(var i=1; i<id_listModel.count; i++)
  171. {
  172. var group_name=id_listModel.get(i).group_name
  173. if(group_name===old_name)
  174. {
  175. id_listModel.setProperty(i, "group_name", new_name)
  176. break
  177. }
  178. }
  179. }
  180. onSiqDelGroup:
  181. {
  182. for(var i=1; i<id_listModel.count; i++)
  183. {
  184. if(group_name===id_listModel.get(i).group_name)
  185. {
  186. id_listModel.remove(i)
  187. break
  188. }
  189. }
  190. }
  191. }
  192. }

五、新建分组

        点击 新建按钮后,会弹出新建对话框,可以输入组名进行新建操作。

六、编辑分组

        编辑分组比较复杂,包含了删除、重命名和排序,其中重点是排序功能,具体代码如下。这里面主要难点是一个分组排序的拖拽功能,核心思想是—— 单元格内分为两部分,一个是拖拽有效区id_dragRect,一个是拖拽显示区dropRectangle,当鼠标捕捉到拖拽信号后,就把拖拽区的父组件从单元格修改为根矩形组件,然后取消布局,这样拖拽区就可以被拉动了;接着是放掉后检测当前坐标,看下在哪个单元格上就跟其做交换即可,最后配合ListView的move和moveDisplaced动画,产生交换效果就完成了,具体实现看代码。

  1. import QtQuick 2.7
  2. import QtQuick.Controls 2.0
  3. import "../base"
  4. //分组编辑界面
  5. Rectangle {
  6. id:id_rootRect
  7. focus: true
  8. MsgDialog01
  9. {
  10. id:id_msgDialog
  11. }
  12. Keys.onPressed:
  13. {
  14. if(event.key === Qt.Key_Back)
  15. {
  16. console.log("phone Key_Back!")
  17. event.accepted = true;
  18. theAccountMan.setHomeCurrView("home-logined")
  19. }
  20. }
  21. ImageButton01//返回按钮
  22. {
  23. id:id_backButton
  24. source: "qrc:/mainImgRC/images/login/back.png"
  25. anchors
  26. {
  27. left:parent.left
  28. leftMargin:20
  29. top:parent.top
  30. topMargin:20
  31. }
  32. onSiqClickedLeft:
  33. {
  34. theAccountMan.setHomeCurrView("home-logined")
  35. }
  36. }
  37. ImageButton01{
  38. id:id_okButton
  39. source: "qrc:/mainImgRC/images/home/ok.png"
  40. height: 35
  41. anchors
  42. {
  43. right:parent.right
  44. rightMargin:20
  45. verticalCenter:id_backButton.verticalCenter
  46. }
  47. onSiqClickedLeft: //完成
  48. {
  49. var str_list=[]
  50. for(var i=1; i<id_listModel.count; i++)
  51. {
  52. str_list[i]=id_listModel.get(i).group_name
  53. }
  54. theCenterMan.requestOrderGroup(str_list)
  55. }
  56. }
  57. GroupRenameDialog//重命名
  58. {
  59. id:id_renameDialog
  60. onSiqOkClicked:
  61. {
  62. if(text)
  63. {
  64. if(text==="全部")
  65. {
  66. id_msgDialog.funOpen("不能使用\"全部\"作为组名!")
  67. return
  68. }
  69. theCenterMan.requestRenameGroup(oldName, text)
  70. }
  71. funClose()
  72. }
  73. }
  74. GroupDelDialog //删除分组对话框
  75. {
  76. id:id_delGroupDialog
  77. onSiqOkClicked:
  78. {
  79. theCenterMan.requestDelGroup(groupName)
  80. funClose()
  81. }
  82. }
  83. ListView{
  84. property int dragItemIndex: -1
  85. id:id_editListView
  86. clip: true
  87. width: parent.width
  88. anchors
  89. {
  90. top:id_backButton.bottom
  91. bottom:parent.bottom
  92. }
  93. model: ListModel{
  94. id:id_listModel
  95. }
  96. move:Transition {
  97. NumberAnimation { properties: "x,y"; duration: 200 }
  98. }
  99. moveDisplaced:Transition {
  100. NumberAnimation { properties: "x,y"; duration: 200 }
  101. }
  102. delegate: Rectangle{
  103. id:id_unionRect
  104. height: 60
  105. width: parent.width
  106. Rectangle
  107. {
  108. id:id_dragRect
  109. height: id_unionRect.height
  110. width: id_unionRect.width
  111. color: id_moveMouseArea.drag.active ? "transparent" : "white"
  112. MouseArea
  113. {
  114. id:id_moveMouseArea
  115. enabled: id>0
  116. anchors.fill: parent
  117. drag.target: id_dragRect
  118. drag.axis: Drag.YAxis
  119. drag.onActiveChanged: {
  120. if (id_moveMouseArea.drag.active) {
  121. id_editListView.dragItemIndex = index;
  122. // console.log("index=", index)
  123. }
  124. id_dragRect.Drag.drop();
  125. }
  126. }
  127. states: [
  128. State {
  129. when: id_dragRect.Drag.active
  130. ParentChange {
  131. target: id_dragRect
  132. parent: id_rootRect
  133. }
  134. AnchorChanges {
  135. target: id_dragRect
  136. anchors.horizontalCenter: undefined
  137. anchors.verticalCenter: undefined
  138. }
  139. }
  140. ]
  141. Drag.active: id_moveMouseArea.drag.active
  142. Drag.hotSpot.x: id_dragRect.width / 2
  143. Drag.hotSpot.y: id_dragRect.height / 2
  144. ImageButton01{
  145. id:id_delButton
  146. source: "qrc:/mainImgRC/images/home/del.png"
  147. height: 25
  148. width: height
  149. visible: id>0
  150. anchors
  151. {
  152. verticalCenter:parent.verticalCenter
  153. left:parent.left
  154. leftMargin:20
  155. }
  156. onSiqClickedLeft: //删除
  157. {
  158. id_delGroupDialog.groupName=group_name
  159. id_delGroupDialog.funOpen()
  160. }
  161. }
  162. Text{ //组名文本
  163. id:id_groupText
  164. height: 40
  165. anchors{
  166. left: id_delButton.right
  167. leftMargin: 10
  168. right: id_totalNumText.left
  169. verticalCenter: parent.verticalCenter
  170. }
  171. color: "black"
  172. font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"
  173. font.pointSize: 18
  174. font.bold: id_moveMouseArea.pressed
  175. text: group_name
  176. verticalAlignment: Text.AlignVCenter
  177. horizontalAlignment: Text.AlignLeft
  178. elide: Text.ElideRight
  179. }
  180. Text{ //数量文本
  181. id:id_totalNumText
  182. height: 30
  183. width: 30
  184. anchors{
  185. right: id_renameButton.left
  186. rightMargin: 5
  187. verticalCenter: parent.verticalCenter
  188. }
  189. color: "#808080"
  190. font.family: "宋体"
  191. font.pointSize: 18
  192. text: total_num
  193. verticalAlignment: Text.AlignVCenter
  194. horizontalAlignment: Text.AlignLeft
  195. elide: Text.ElideRight
  196. }
  197. ImageButton01{
  198. id:id_renameButton
  199. source: "qrc:/mainImgRC/images/home/rename.png"
  200. height: 25
  201. width: height
  202. visible: id>0
  203. anchors
  204. {
  205. verticalCenter:parent.verticalCenter
  206. right:parent.right
  207. rightMargin:20
  208. }
  209. onSiqClickedLeft: //重命名
  210. {
  211. id_renameDialog.oldName=group_name
  212. id_renameDialog.funOpen(group_name)
  213. }
  214. }
  215. }
  216. DropArea {
  217. id: dropArea
  218. anchors.fill: parent
  219. onDropped:{
  220. // console.log("onDropped")
  221. var other_index = id_editListView.indexAt(id_moveMouseArea.mouseX + id_unionRect.x, id_moveMouseArea.mouseY + id_unionRect.y);
  222. // console.log("index:",index,"other_index:",other_index,"listView.dragItemIndex:",id_editListView.dragItemIndex);
  223. if(other_index>0)
  224. {
  225. id_listModel.move(id_editListView.dragItemIndex,other_index, 1);
  226. }
  227. }
  228. Rectangle {
  229. id: dropRectangle
  230. anchors.fill: parent
  231. color: "transparent"
  232. states: [
  233. State {
  234. when: dropArea.containsDrag
  235. PropertyChanges {
  236. target: dropRectangle
  237. color: "lightsteelblue"
  238. opacity:0.3
  239. }
  240. }
  241. ]
  242. }//end Rectangle
  243. }//end drop
  244. }
  245. }
  246. Component.onCompleted:
  247. {
  248. for(var i=0; i<1; i++)
  249. {
  250. id_listModel.append({"id":i, "group_name":"全部", "total_num":0})
  251. }
  252. }
  253. Connections
  254. {
  255. target: theCenterMan
  256. onSiqAddGroup:
  257. {
  258. if(index===0)
  259. {
  260. id_listModel.clear()
  261. id_listModel.append({"id":0, "group_name":"全部", "total_num":total_num})
  262. }
  263. index=id_listModel.count
  264. id_listModel.append({"id":index, "group_name":group_name, "total_num":total_num})
  265. }
  266. onSiqRenameGroup:
  267. {
  268. for(var i=1; i<id_listModel.count; i++)
  269. {
  270. var group_name=id_listModel.get(i).group_name
  271. if(group_name===old_name)
  272. {
  273. id_listModel.setProperty(i, "group_name", new_name)
  274. break
  275. }
  276. }
  277. }
  278. onSiqDelGroup:
  279. {
  280. for(var i=1; i<id_listModel.count; i++)
  281. {
  282. if(group_name===id_listModel.get(i).group_name)
  283. {
  284. id_listModel.remove(i)
  285. break
  286. }
  287. }
  288. }
  289. }
  290. }

        删除和重命名就是相关对话框内容了,没有很复杂的内容,具体看代码。

  1. import QtQuick 2.7
  2. import QtQuick.Controls 2.14
  3. Popup {
  4. property var titleText: "标题"
  5. property var cancelText: "取消"
  6. property var okText: "确定"
  7. property var cancelColor: "#303030"
  8. property var okColor: "#303030"
  9. signal siqCancelClicked()
  10. signal siqOkClicked()
  11. id:id_popup
  12. visible: false
  13. implicitWidth: parent.width
  14. implicitHeight: 200
  15. modal: true
  16. focus: true
  17. closePolicy: Popup.CloseOnEscape | Popup.CloseOnReleaseOutside
  18. anchors.centerIn: Overlay.overlay
  19. background: Rectangle
  20. {
  21. radius:10
  22. }
  23. Text {//标题文字
  24. id:id_titleText
  25. height: 40
  26. width: parent.width*0.8
  27. anchors
  28. {
  29. top:parent.top
  30. topMargin:10
  31. horizontalCenter:parent.horizontalCenter
  32. }
  33. verticalAlignment: Text.AlignVCenter
  34. horizontalAlignment: Text.AlignHCenter
  35. font.pointSize: height*0.4
  36. font.family: "宋体"
  37. text: titleText
  38. color: "black"
  39. }
  40. BaseButton02//取消按钮
  41. {
  42. id:id_cancelButton
  43. height: 50
  44. width: parent.width*0.4
  45. releaseColor: "#F0F0F0"
  46. pressedColor: "#F0F0F0"
  47. anchors
  48. {
  49. left:parent.left
  50. leftMargin:20
  51. bottom:parent.bottom
  52. bottomMargin:20
  53. }
  54. buttonText: cancelText
  55. buttonColor:cancelColor
  56. onSiqClickedLeft:
  57. {
  58. siqCancelClicked()
  59. }
  60. }
  61. BaseButton02//确定按钮
  62. {
  63. id:id_okButton
  64. height: id_cancelButton.height
  65. width: id_cancelButton.width
  66. releaseColor: "#F0F0F0"
  67. pressedColor: "#F0F0F0"
  68. anchors
  69. {
  70. verticalCenter:id_cancelButton.verticalCenter
  71. right:parent.right
  72. rightMargin:20
  73. }
  74. buttonText: okText
  75. buttonColor:okColor
  76. onSiqClickedLeft:
  77. {
  78. siqOkClicked()
  79. }
  80. }
  81. function funOpen()
  82. {
  83. id_popup.open()
  84. }
  85. function funClose()
  86. {
  87. id_popup.close()
  88. }
  89. }
  1. import QtQuick 2.0
  2. import "../base"
  3. //删除警示对话框
  4. BaseWarnDialog {
  5. titleText: "确认删除分组吗?"
  6. property var groupName: ""
  7. okText: "删除"
  8. okColor: "#F00000"
  9. onSiqCancelClicked:
  10. {
  11. funClose()
  12. }
  13. }
  1. import QtQuick 2.0
  2. import "../base"
  3. //重命名分组对话框
  4. BaseEditDialog {
  5. titleText: "重命名分组"
  6. property var oldName: ""
  7. onSiqCancelClicked:
  8. {
  9. funClose()
  10. }
  11. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/588116
推荐阅读
相关标签
  

闽ICP备14008679号