mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 08:13:43 +08:00 
			
		
		
		
	feat: use vant replace element-plus as mobile UI framework
This commit is contained in:
		@@ -4,7 +4,7 @@
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
 | 
			
		||||
    <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
 | 
			
		||||
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
 | 
			
		||||
    <title>ChatGPT-Plus</title>
 | 
			
		||||
</head>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
.title {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
.app-background {
 | 
			
		||||
  background-color: #282828;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
.mobile-setting .content {
 | 
			
		||||
  padding-top: 60px;
 | 
			
		||||
}
 | 
			
		||||
.mobile-setting .content .van-field__label {
 | 
			
		||||
  width: 100px;
 | 
			
		||||
  text-align: right;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
.title {
 | 
			
		||||
  color  #fff 
 | 
			
		||||
  text-align  center 
 | 
			
		||||
  font-size  16px 
 | 
			
		||||
  font-weight  bold 
 | 
			
		||||
}
 | 
			
		||||
.app-background {
 | 
			
		||||
  background-color  #282828 
 | 
			
		||||
  height  100vh 
 | 
			
		||||
}
 | 
			
		||||
.mobile-setting {
 | 
			
		||||
  .content {
 | 
			
		||||
    padding-top 60px
 | 
			
		||||
 | 
			
		||||
    .van-field__label {
 | 
			
		||||
      width 100px
 | 
			
		||||
      text-align right
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,47 +0,0 @@
 | 
			
		||||
.app-background {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
.mobile-chat-list {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 40px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.content .van-cell__value .chat-list-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
}
 | 
			
		||||
.content .van-cell__value .chat-list-item .van-image {
 | 
			
		||||
  min-width: 32px;
 | 
			
		||||
  width: 32px;
 | 
			
		||||
  height: 32px;
 | 
			
		||||
}
 | 
			
		||||
.content .van-cell__value .chat-list-item .van-ellipsis {
 | 
			
		||||
  margin-top: 5px;
 | 
			
		||||
  margin-left: 10px;
 | 
			
		||||
}
 | 
			
		||||
.van-picker-column .picker-option {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 0 10px;
 | 
			
		||||
}
 | 
			
		||||
.van-picker-column .picker-option .van-image {
 | 
			
		||||
  width: 20px;
 | 
			
		||||
  height: 20px;
 | 
			
		||||
  margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
.van-nav-bar .van-nav-bar__right .van-icon {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
}
 | 
			
		||||
.popup {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
}
 | 
			
		||||
.dialog {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
}
 | 
			
		||||
.field {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,58 +0,0 @@
 | 
			
		||||
$fontSize = 16px;
 | 
			
		||||
.app-background {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
.mobile-chat-list {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 40px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
  .content {
 | 
			
		||||
    .van-cell__value {
 | 
			
		||||
      .chat-list-item {
 | 
			
		||||
        display flex
 | 
			
		||||
        font-size $fontSize
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        background-color: #1c1c1c;
 | 
			
		||||
        .van-image {
 | 
			
		||||
          min-width 32px
 | 
			
		||||
          width 32px
 | 
			
		||||
          height 32px
 | 
			
		||||
        }
 | 
			
		||||
        .van-ellipsis {
 | 
			
		||||
          margin-top 5px;
 | 
			
		||||
          margin-left 10px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .van-picker-column {
 | 
			
		||||
    .picker-option {
 | 
			
		||||
      display flex
 | 
			
		||||
      width 100%
 | 
			
		||||
      padding 0 10px
 | 
			
		||||
      .van-image {
 | 
			
		||||
        width 20px;
 | 
			
		||||
        height 20px;
 | 
			
		||||
        margin-right 5px
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .van-nav-bar {
 | 
			
		||||
    .van-nav-bar__right {
 | 
			
		||||
      .van-icon {
 | 
			
		||||
        font-size 20px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .popup {
 | 
			
		||||
    background-color: #1c1c1c;
 | 
			
		||||
  }
 | 
			
		||||
  .dialog {
 | 
			
		||||
    background-color: #1c1c1c;
 | 
			
		||||
  }
 | 
			
		||||
  .field {
 | 
			
		||||
    background-color: #1c1c1c;
 | 
			
		||||
  }
 | 
			
		||||
@@ -1,45 +1,36 @@
 | 
			
		||||
.app-background {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
.mobile-chat .message-list-box {
 | 
			
		||||
  padding-top: 50px;
 | 
			
		||||
  padding-bottom: 10px;
 | 
			
		||||
  overflow-x: auto;
 | 
			
		||||
  background: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
body,
 | 
			
		||||
.mobile-chat,
 | 
			
		||||
.van-sticky,
 | 
			
		||||
.van-nav-bar,
 | 
			
		||||
.van-list,
 | 
			
		||||
.message-list-box,
 | 
			
		||||
.van-cell,
 | 
			
		||||
.chat-box,
 | 
			
		||||
.van-cell-group,
 | 
			
		||||
.van-field {
 | 
			
		||||
  background-color: #1c1c1c !important;
 | 
			
		||||
  color: #fff !important;
 | 
			
		||||
.mobile-chat .message-list-box .van-cell {
 | 
			
		||||
  background: none;
 | 
			
		||||
  font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
 | 
			
		||||
}
 | 
			
		||||
.chat-box-wrapper {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
.mobile-chat .chat-box-wrapper .van-sticky .van-cell-group--inset {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
.icon-box .van-icon,
 | 
			
		||||
.mobile-chat .van-nav-bar__title .van-dropdown-menu__title,
 | 
			
		||||
.mobile-chat .van-nav-bar__title .van-cell__title,
 | 
			
		||||
.mobile-chat .van-nav-bar__right .van-icon {
 | 
			
		||||
  color: #fff !important;
 | 
			
		||||
.mobile-chat .chat-box-wrapper .van-sticky .van-cell-group--inset .van-cell {
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
}
 | 
			
		||||
.mobile-chat .chat-box-wrapper .van-sticky .van-cell-group--inset .van-cell .icon-box .van-icon {
 | 
			
		||||
  font-size: 24px;
 | 
			
		||||
  margin: 10px 0;
 | 
			
		||||
}
 | 
			
		||||
.mobile-chat .chat-box-wrapper .van-sticky .van-cell-group--inset .van-cell .button-voice {
 | 
			
		||||
  padding: 0 5px;
 | 
			
		||||
  height: 30px;
 | 
			
		||||
}
 | 
			
		||||
.mobile-chat .van-nav-bar__title .van-dropdown-menu__title {
 | 
			
		||||
  margin-right: 15px;
 | 
			
		||||
  margin-right: 10px;
 | 
			
		||||
}
 | 
			
		||||
.mobile-chat .van-nav-bar__title .van-cell__title {
 | 
			
		||||
  text-align: left;
 | 
			
		||||
}
 | 
			
		||||
.mobile-chat .chat-list-wrapper {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  top: 50px;
 | 
			
		||||
  bottom: 60px;
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
}
 | 
			
		||||
.mobile-chat .van-nav-bar__right .van-icon {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
}
 | 
			
		||||
.van-theme-dark .mobile-chat .message-list-box {
 | 
			
		||||
  background: #232425;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,51 +1,61 @@
 | 
			
		||||
.app-background {
 | 
			
		||||
    background-color  #1c1c1c 
 | 
			
		||||
    height  100vh 
 | 
			
		||||
  }
 | 
			
		||||
  body,
 | 
			
		||||
  .mobile-chat,
 | 
			
		||||
  .van-sticky,
 | 
			
		||||
  .van-nav-bar,
 | 
			
		||||
  .van-list,
 | 
			
		||||
  .message-list-box
 | 
			
		||||
  .van-cell,
 | 
			
		||||
  .chat-box,
 | 
			
		||||
  .van-cell-group,
 | 
			
		||||
  .van-field {
 | 
			
		||||
    background-color  #1c1c1c !important 
 | 
			
		||||
    color  #fff !important 
 | 
			
		||||
  }
 | 
			
		||||
  .chat-box-wrapper {
 | 
			
		||||
    position  fixed 
 | 
			
		||||
    bottom  0 
 | 
			
		||||
    width  100% 
 | 
			
		||||
    background-color  #1c1c1c 
 | 
			
		||||
    }
 | 
			
		||||
  .icon-box .van-icon,
 | 
			
		||||
  .mobile-chat .van-nav-bar__title .van-dropdown-menu__title,
 | 
			
		||||
  .mobile-chat .van-nav-bar__title .van-cell__title,
 | 
			
		||||
  .mobile-chat .van-nav-bar__right .van-icon {
 | 
			
		||||
    color  #fff !important 
 | 
			
		||||
  }
 | 
			
		||||
  .mobile-chat {
 | 
			
		||||
    .van-nav-bar__title {
 | 
			
		||||
      .van-dropdown-menu__title {
 | 
			
		||||
        margin-right  15px 
 | 
			
		||||
      }
 | 
			
		||||
      .van-cell__title {
 | 
			
		||||
        text-align  left 
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .chat-list-wrapper {
 | 
			
		||||
      position  fixed 
 | 
			
		||||
      top  50px 
 | 
			
		||||
      bottom  60px 
 | 
			
		||||
      width  100vw 
 | 
			
		||||
      overflow-y  scroll 
 | 
			
		||||
    }
 | 
			
		||||
    .van-nav-bar__right {
 | 
			
		||||
      .van-icon {
 | 
			
		||||
        font-size  20px 
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
.mobile-chat {
 | 
			
		||||
  .message-list-box {
 | 
			
		||||
    padding-top 50px
 | 
			
		||||
    padding-bottom 10px
 | 
			
		||||
    overflow-x auto
 | 
			
		||||
    background #F5F5F5;
 | 
			
		||||
 | 
			
		||||
    .van-cell {
 | 
			
		||||
      background none
 | 
			
		||||
      font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .chat-box-wrapper {
 | 
			
		||||
    .van-sticky {
 | 
			
		||||
      .van-cell-group--inset {
 | 
			
		||||
        margin 0
 | 
			
		||||
 | 
			
		||||
        .van-cell {
 | 
			
		||||
          padding 10px
 | 
			
		||||
 | 
			
		||||
          .icon-box {
 | 
			
		||||
            .van-icon {
 | 
			
		||||
              font-size 24px
 | 
			
		||||
              margin 10px 0
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .button-voice {
 | 
			
		||||
            padding 0 5px
 | 
			
		||||
            height 30px
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .van-nav-bar__title {
 | 
			
		||||
    .van-dropdown-menu__title {
 | 
			
		||||
      margin-right 10px
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .van-cell__title {
 | 
			
		||||
      text-align left
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .van-nav-bar__right {
 | 
			
		||||
    .van-icon {
 | 
			
		||||
      font-size 20px
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.van-theme-dark {
 | 
			
		||||
  .mobile-chat {
 | 
			
		||||
    .message-list-box {
 | 
			
		||||
      background #232425;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
.custom-scroll ::-webkit-scrollbar {
 | 
			
		||||
  width: 8px; /* 滚动条宽度 */
 | 
			
		||||
}
 | 
			
		||||
.custom-scroll ::-webkit-scrollbar-track {
 | 
			
		||||
  background-color: #282c34;
 | 
			
		||||
}
 | 
			
		||||
.custom-scroll ::-webkit-scrollbar-thumb {
 | 
			
		||||
  background-color: #444;
 | 
			
		||||
  border-radius: 8px;
 | 
			
		||||
}
 | 
			
		||||
.custom-scroll ::-webkit-scrollbar-thumb:hover {
 | 
			
		||||
  background-color: #666;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
.custom-scroll {
 | 
			
		||||
  /* 修改滚动条的颜色 */
 | 
			
		||||
 | 
			
		||||
  ::-webkit-scrollbar {
 | 
			
		||||
    width: 8px; /* 滚动条宽度 */
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* 修改滚动条轨道的背景颜色 */
 | 
			
		||||
 | 
			
		||||
  ::-webkit-scrollbar-track {
 | 
			
		||||
    background-color: #282C34;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* 修改滚动条的滑块颜色 */
 | 
			
		||||
 | 
			
		||||
  ::-webkit-scrollbar-thumb {
 | 
			
		||||
    background-color: #444444;
 | 
			
		||||
    border-radius 8px
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* 修改滚动条的滑块的悬停颜色 */
 | 
			
		||||
 | 
			
		||||
  ::-webkit-scrollbar-thumb:hover {
 | 
			
		||||
    background-color: #666666;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,45 +0,0 @@
 | 
			
		||||
.my-tabbar {
 | 
			
		||||
  background-color: #171717;
 | 
			
		||||
  box-shadow: -3px 4px 16px #000;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
.banner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  background-color: #171717;
 | 
			
		||||
  border-bottom-right-radius: 10px;
 | 
			
		||||
  box-shadow: 0 -4px 13px #000;
 | 
			
		||||
  height: 40px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  z-index: 2 /* Add z-index */;
 | 
			
		||||
}
 | 
			
		||||
.banner-title {
 | 
			
		||||
  color: #2cc995;
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  text-shadow: 0 -4px 13px #000;
 | 
			
		||||
}
 | 
			
		||||
.mobile-home {
 | 
			
		||||
  background-color: #171717;
 | 
			
		||||
}
 | 
			
		||||
.mobile-home .van-tabbar before {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  height: 50px;
 | 
			
		||||
  background-color: #171717;
 | 
			
		||||
  border-top-left-radius: 10px;
 | 
			
		||||
  border-top-right-radius: 10px;
 | 
			
		||||
  opacity: 0;
 | 
			
		||||
  transition: opacity 0.5s;
 | 
			
		||||
  z-index: -1;
 | 
			
		||||
}
 | 
			
		||||
.mobile-home .van-tabbar.activeTab before {
 | 
			
		||||
  opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
.router-view {
 | 
			
		||||
  margin-bottom: 50px;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,45 +0,0 @@
 | 
			
		||||
.my-tabbar {
 | 
			
		||||
  background-color  #171717  
 | 
			
		||||
  box-shadow  -3px 4px 16px #000  
 | 
			
		||||
  box-sizing  border-box 
 | 
			
		||||
}
 | 
			
		||||
.banner {
 | 
			
		||||
  display  flex 
 | 
			
		||||
  justify-content  center 
 | 
			
		||||
  align-items  center 
 | 
			
		||||
  background-color  #171717 
 | 
			
		||||
  border-bottom-right-radius  10px 
 | 
			
		||||
  box-shadow  0 -4px 13px #000 
 | 
			
		||||
  height  40px 
 | 
			
		||||
  width  100% 
 | 
			
		||||
  position  fixed 
 | 
			
		||||
  z-index  2    /* Add z-index */
 | 
			
		||||
} 
 | 
			
		||||
.banner-title {
 | 
			
		||||
  color  #2CC995 
 | 
			
		||||
  font-size  20px 
 | 
			
		||||
  font-weight  bold 
 | 
			
		||||
  text-shadow  0 -4px 13px #000 
 | 
			
		||||
}
 | 
			
		||||
.mobile-home {
 | 
			
		||||
  background-color  #171717 
 | 
			
		||||
}
 | 
			
		||||
.mobile-home .van-tabbar  before {
 | 
			
		||||
  position  absolute 
 | 
			
		||||
  bottom  0 
 | 
			
		||||
  left  0 
 | 
			
		||||
  right  0 
 | 
			
		||||
  height  50px 
 | 
			
		||||
  background-color  #171717 
 | 
			
		||||
  border-top-left-radius  10px 
 | 
			
		||||
  border-top-right-radius  10px 
 | 
			
		||||
  opacity  0 
 | 
			
		||||
  transition  opacity 0.5s 
 | 
			
		||||
  z-index  -1 
 | 
			
		||||
}
 | 
			
		||||
.mobile-home .van-tabbar.activeTab  before {
 | 
			
		||||
  opacity  1 
 | 
			
		||||
}
 | 
			
		||||
.router-view {
 | 
			
		||||
  margin-bottom  50px 
 | 
			
		||||
}
 | 
			
		||||
@@ -1,252 +0,0 @@
 | 
			
		||||
 | 
			
		||||
.page-sd {
 | 
			
		||||
  background-color: #282828;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box {
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
  background-color: #282828;
 | 
			
		||||
  min-width: 92%;
 | 
			
		||||
  max-width: 92%;
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
  border-radius: 0px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box h2 {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box ::-webkit-scrollbar {
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line {
 | 
			
		||||
  padding: 0 10px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .el-icon {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 3px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .el-input__suffix-inner .el-icon {
 | 
			
		||||
  top: 0;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .grid-content,
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .form-item-inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .grid-content .el-icon,
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .form-item-inner .el-icon {
 | 
			
		||||
  margin-left: 10px;
 | 
			
		||||
  margin-top: 2px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line.pt {
 | 
			
		||||
  padding-top: 5px;
 | 
			
		||||
  padding-bottom: 5px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .submit-btn {
 | 
			
		||||
  padding: 10px 15px 0 15px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .submit-btn .el-button {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .submit-btn .el-button span {
 | 
			
		||||
  color: #2d3a4b;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .el-form .el-form-item__label {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .running-job-list .job-item {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 2px;
 | 
			
		||||
  background-color: #555;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner .progress {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner .progress span {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  border: 1px solid #666;
 | 
			
		||||
  padding: 6px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
  transition: all 0.3s ease; /* 添加过渡效果 */
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line {
 | 
			
		||||
  margin: 6px 0;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li {
 | 
			
		||||
  margin-right: 6px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li a {
 | 
			
		||||
  padding: 3px 0;
 | 
			
		||||
  width: 40px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  display: block;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  background-color: #4e5058;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover {
 | 
			
		||||
  background-color: #6d6f78;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul .show-prompt {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .animate:hover {
 | 
			
		||||
  box-shadow: 0 0 10px rgba(71,255,241,0.6); /* 添加阴影效果 */
 | 
			
		||||
  transform: translateY(-10px); /* 向上移动10像素 */
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image img {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image .el-image-viewer__wrapper img {
 | 
			
		||||
  width: auto;
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image .image-slot {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: column;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  min-height: 200px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  height: 240px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image .image-slot .iconfont {
 | 
			
		||||
  font-size: 50px;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image.upscale {
 | 
			
		||||
  max-height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image.upscale img {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image.upscale .el-image-viewer__wrapper img {
 | 
			
		||||
  width: auto;
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog {
 | 
			
		||||
  background-color: #1a1b1e;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__header .el-dialog__title {
 | 
			
		||||
  color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body {
 | 
			
		||||
  padding: 0 0 0 15px !important;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container .image-slot {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container .image-slot .el-icon {
 | 
			
		||||
  font-size: 60px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info {
 | 
			
		||||
  background-color: #25262b;
 | 
			
		||||
  padding: 1rem 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .prompt {
 | 
			
		||||
  background-color: #35363b;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  max-height: 100%;
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .prompt .el-icon {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 10px;
 | 
			
		||||
  bottom: 10px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper label {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width:100%;
 | 
			
		||||
  color: #a5a5a5;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper .item-value {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  background-color: #35363b;
 | 
			
		||||
  padding: 2px 5px;
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .copy-params {
 | 
			
		||||
  padding: 20px 0 10px 0;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .copy-params .el-button {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .mj-list-item-prompt .el-icon {
 | 
			
		||||
  margin-left: 10px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 2px;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,106 +0,0 @@
 | 
			
		||||
.page-sd {
 | 
			
		||||
  background-color: #282828;
 | 
			
		||||
 | 
			
		||||
  .inner {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
 | 
			
		||||
    .sd-box {
 | 
			
		||||
      background-color #282828
 | 
			
		||||
      min-width 92%
 | 
			
		||||
      max-width 92%
 | 
			
		||||
      padding 0px
 | 
			
		||||
      border-radius 0px
 | 
			
		||||
      color #ffffff;
 | 
			
		||||
      font-size 14px
 | 
			
		||||
 | 
			
		||||
      h2 {
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        font-size 20px
 | 
			
		||||
        text-align center
 | 
			
		||||
        color #fff
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // 隐藏滚动条
 | 
			
		||||
 | 
			
		||||
      ::-webkit-scrollbar {
 | 
			
		||||
        width: 0;
 | 
			
		||||
        height: 0;
 | 
			
		||||
        background-color: transparent;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .sd-params {
 | 
			
		||||
        margin-top 10px
 | 
			
		||||
        overflow auto
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        .param-line {
 | 
			
		||||
          padding 0 10px
 | 
			
		||||
 | 
			
		||||
          .el-icon {
 | 
			
		||||
            position relative
 | 
			
		||||
            top 3px
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .el-input__suffix-inner {
 | 
			
		||||
            .el-icon {
 | 
			
		||||
              top 0
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .grid-content
 | 
			
		||||
          .form-item-inner {
 | 
			
		||||
            display flex
 | 
			
		||||
 | 
			
		||||
            .el-icon {
 | 
			
		||||
              margin-left 10px
 | 
			
		||||
              margin-top 2px
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .param-line.pt {
 | 
			
		||||
          padding-top 5px
 | 
			
		||||
          padding-bottom 5px
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .submit-btn {
 | 
			
		||||
        padding 10px 15px 0 15px
 | 
			
		||||
        text-align center
 | 
			
		||||
 | 
			
		||||
        .el-button {
 | 
			
		||||
          width 100%
 | 
			
		||||
 | 
			
		||||
          span {
 | 
			
		||||
            color #2D3A4B
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-form {
 | 
			
		||||
      .el-form-item__label {
 | 
			
		||||
        color #ffffff
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @import "mobile/task-mobile-list.styl"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @import "sd-task-mobile-dialog.styl"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  .mj-list-item-prompt {
 | 
			
		||||
    .el-icon {
 | 
			
		||||
      margin-left 10px
 | 
			
		||||
      cursor pointer
 | 
			
		||||
      position relative
 | 
			
		||||
      top 2px
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,252 +0,0 @@
 | 
			
		||||
.page-sd {
 | 
			
		||||
  background-color: #282828;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box {
 | 
			
		||||
  background-color: #282828;
 | 
			
		||||
  min-width: 92%;
 | 
			
		||||
  max-width: 92%;
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
  border-radius: 0px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box h2 {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box ::-webkit-scrollbar {
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line {
 | 
			
		||||
  padding: 0 10px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .el-icon {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 3px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .el-input__suffix-inner .el-icon {
 | 
			
		||||
  top: 0;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .grid-content,
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .form-item-inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .grid-content .el-icon,
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line .form-item-inner .el-icon {
 | 
			
		||||
  margin-left: 10px;
 | 
			
		||||
  margin-top: 2px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .sd-params .param-line.pt {
 | 
			
		||||
  padding-top: 5px;
 | 
			
		||||
  padding-bottom: 5px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .submit-btn {
 | 
			
		||||
  padding: 10px 15px 0 15px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .submit-btn .el-button {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .sd-box .submit-btn .el-button span {
 | 
			
		||||
  color: #2d3a4b;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .el-form .el-form-item__label {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .running-job-list .job-item {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 2px;
 | 
			
		||||
  background-color: #555;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner .progress {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner .progress span {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  border: 1px solid #666;
 | 
			
		||||
  padding: 6px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
  transition: all 0.3s ease; /* 添加过渡效果 */
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line {
 | 
			
		||||
  margin: 6px 0;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li {
 | 
			
		||||
  margin-right: 6px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li a {
 | 
			
		||||
  padding: 3px 0;
 | 
			
		||||
  width: 40px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  display: block;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  background-color: #4e5058;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover {
 | 
			
		||||
  background-color: #6d6f78;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul .show-prompt {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .finish-job-list .animate:hover {
 | 
			
		||||
  box-shadow: 0 0 10px rgba(71,255,241,0.6); /* 添加阴影效果 */
 | 
			
		||||
  transform: translateY(-10px); /* 向上移动10像素 */
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image img {
 | 
			
		||||
  height: 240px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image .el-image-viewer__wrapper img {
 | 
			
		||||
  width: auto;
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image .image-slot {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: column;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  min-height: 200px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  height: 240px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image .image-slot .iconfont {
 | 
			
		||||
  font-size: 50px;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image.upscale {
 | 
			
		||||
  max-height: 310px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image.upscale img {
 | 
			
		||||
  height: 310px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .inner .task-list-box .el-image.upscale .el-image-viewer__wrapper img {
 | 
			
		||||
  width: auto;
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog {
 | 
			
		||||
  background-color: #1a1b1e;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__header .el-dialog__title {
 | 
			
		||||
  color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body {
 | 
			
		||||
  padding: 0 0 0 15px !important;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container .image-slot {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container .image-slot .el-icon {
 | 
			
		||||
  font-size: 60px;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info {
 | 
			
		||||
  background-color: #25262b;
 | 
			
		||||
  padding: 1rem 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .prompt {
 | 
			
		||||
  background-color: #35363b;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  max-height: 100px;
 | 
			
		||||
  min-height: 50px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .prompt .el-icon {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 10px;
 | 
			
		||||
  bottom: 10px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper label {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100px;
 | 
			
		||||
  color: #a5a5a5;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper .item-value {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  background-color: #35363b;
 | 
			
		||||
  padding: 2px 5px;
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .copy-params {
 | 
			
		||||
  padding: 30px 0 10px 0;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .copy-params .el-button {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.page-sd .mj-list-item-prompt .el-icon {
 | 
			
		||||
  margin-left: 10px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 2px;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,106 +0,0 @@
 | 
			
		||||
.page-sd {
 | 
			
		||||
  background-color: #282828;
 | 
			
		||||
 | 
			
		||||
  .inner {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
 | 
			
		||||
    .sd-box {
 | 
			
		||||
      background-color #282828
 | 
			
		||||
      min-width 92%
 | 
			
		||||
      max-width 92%
 | 
			
		||||
      padding 0px
 | 
			
		||||
      border-radius 0px
 | 
			
		||||
      color #ffffff;
 | 
			
		||||
      font-size 14px
 | 
			
		||||
 | 
			
		||||
      h2 {
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        font-size 16px
 | 
			
		||||
        text-align center
 | 
			
		||||
        color #fff
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // 隐藏滚动条
 | 
			
		||||
 | 
			
		||||
      ::-webkit-scrollbar {
 | 
			
		||||
        width: 0;
 | 
			
		||||
        height: 0;
 | 
			
		||||
        background-color: transparent;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .sd-params {
 | 
			
		||||
        margin-top 10px
 | 
			
		||||
        overflow auto
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        .param-line {
 | 
			
		||||
          padding 0 10px
 | 
			
		||||
 | 
			
		||||
          .el-icon {
 | 
			
		||||
            position relative
 | 
			
		||||
            top 3px
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .el-input__suffix-inner {
 | 
			
		||||
            .el-icon {
 | 
			
		||||
              top 0
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .grid-content
 | 
			
		||||
          .form-item-inner {
 | 
			
		||||
            display flex
 | 
			
		||||
 | 
			
		||||
            .el-icon {
 | 
			
		||||
              margin-left 10px
 | 
			
		||||
              margin-top 2px
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .param-line.pt {
 | 
			
		||||
          padding-top 5px
 | 
			
		||||
          padding-bottom 5px
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .submit-btn {
 | 
			
		||||
        padding 10px 15px 0 15px
 | 
			
		||||
        text-align center
 | 
			
		||||
 | 
			
		||||
        .el-button {
 | 
			
		||||
          width 100%
 | 
			
		||||
 | 
			
		||||
          span {
 | 
			
		||||
            color #2D3A4B
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-form {
 | 
			
		||||
      .el-form-item__label {
 | 
			
		||||
        color #ffffff
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @import "./task-list.styl"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @import "./sd-task-dialog.styl"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  .mj-list-item-prompt {
 | 
			
		||||
    .el-icon {
 | 
			
		||||
      margin-left 10px
 | 
			
		||||
      cursor pointer
 | 
			
		||||
      position relative
 | 
			
		||||
      top 2px
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,93 +0,0 @@
 | 
			
		||||
.page-invitation {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  overflow-y: visible;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner {
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .center {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .title {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .share-box .info {
 | 
			
		||||
  line-height: 1.5;
 | 
			
		||||
  border: 1px solid #444;
 | 
			
		||||
  border-radius: 10px;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .share-box .info strong {
 | 
			
		||||
  color: #f56c6c;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .share-box .invite-qrcode {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  margin: 15px;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .share-box .invite-url {
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  border: 1px solid #444;
 | 
			
		||||
  border-radius: 10px;
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .share-box .invite-url span {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
 | 
			
		||||
  top: 0px;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats {
 | 
			
		||||
  padding: 10px 10px;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .item-box {
 | 
			
		||||
  border-radius: 10px;
 | 
			
		||||
  padding: 10 0px;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .item-box .el-col {
 | 
			
		||||
  height: 80px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .item-box .el-col .iconfont {
 | 
			
		||||
  font-size: 30px;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .item-box .el-col .item-info {
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .item-box .el-col .item-info .text,
 | 
			
		||||
.page-invitation .inner .invite-stats .item-box .el-col .item-info .num {
 | 
			
		||||
  padding: 3px 0;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .item-box .el-col .item-info .num {
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .yellow {
 | 
			
		||||
  background-color: #fec;
 | 
			
		||||
  color: #d68f00;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .blue {
 | 
			
		||||
  background-color: #d6e4ff;
 | 
			
		||||
  color: #1062fe;
 | 
			
		||||
}
 | 
			
		||||
.page-invitation .inner .invite-stats .green {
 | 
			
		||||
  background-color: #e7f8eb;
 | 
			
		||||
  color: #2d9f46;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,94 +0,0 @@
 | 
			
		||||
.page-invitation {
 | 
			
		||||
  display  flex 
 | 
			
		||||
  justify-content  center 
 | 
			
		||||
  background-color  #1c1c1c 
 | 
			
		||||
  height  100vh 
 | 
			
		||||
  overflow-x  hidden 
 | 
			
		||||
  overflow-y  visible 
 | 
			
		||||
  .inner {
 | 
			
		||||
    max-width  100% 
 | 
			
		||||
    width  100% 
 | 
			
		||||
    color  #fff 
 | 
			
		||||
    .center {
 | 
			
		||||
      display  flex 
 | 
			
		||||
      justify-content  center 
 | 
			
		||||
      align-items  center 
 | 
			
		||||
    }
 | 
			
		||||
    .title {
 | 
			
		||||
      color  #fff 
 | 
			
		||||
      text-align  center 
 | 
			
		||||
      font-size  16px 
 | 
			
		||||
      font-weight  bold 
 | 
			
		||||
    }
 | 
			
		||||
    .share-box {
 | 
			
		||||
      .info {
 | 
			
		||||
        line-height  1.5 
 | 
			
		||||
        border  1px solid #444444 
 | 
			
		||||
        border-radius  10px 
 | 
			
		||||
        padding  10px 
 | 
			
		||||
        margin  10px 
 | 
			
		||||
        background-color  #1c1c1c 
 | 
			
		||||
        strong {
 | 
			
		||||
          color  #f56c6c 
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .invite-qrcode {
 | 
			
		||||
        text-align  center 
 | 
			
		||||
        margin  15px 
 | 
			
		||||
      }
 | 
			
		||||
      .invite-url {
 | 
			
		||||
        margin  10px 
 | 
			
		||||
        padding  8px 
 | 
			
		||||
        display  flex 
 | 
			
		||||
        justify-content  space-between 
 | 
			
		||||
        border  1px solid #444444 
 | 
			
		||||
        border-radius  10px 
 | 
			
		||||
        background-color  #1c1c1c 
 | 
			
		||||
        span {
 | 
			
		||||
          position  relative 
 | 
			
		||||
          font-size  14px 
 | 
			
		||||
          font-family  'Microsoft YaHei', '微软雅黑', Arial, sans-serif 
 | 
			
		||||
          top  0px 
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .invite-stats {
 | 
			
		||||
      padding  10px 10px 
 | 
			
		||||
      .item-box {
 | 
			
		||||
        border-radius  10px 
 | 
			
		||||
        padding  10 0px 
 | 
			
		||||
        .el-col {
 | 
			
		||||
          height  80px 
 | 
			
		||||
          display  flex 
 | 
			
		||||
          align-items  center 
 | 
			
		||||
          justify-content  center 
 | 
			
		||||
          .iconfont {
 | 
			
		||||
            font-size  30px 
 | 
			
		||||
          }
 | 
			
		||||
          .item-info {
 | 
			
		||||
            font-size  14px 
 | 
			
		||||
            .text, .num {
 | 
			
		||||
              padding  3px 0 
 | 
			
		||||
              text-align  center 
 | 
			
		||||
            }
 | 
			
		||||
            .num {
 | 
			
		||||
              font-size  14px 
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .yellow {
 | 
			
		||||
        background-color  #ffeecc 
 | 
			
		||||
        color  #D68F00 
 | 
			
		||||
      }
 | 
			
		||||
      .blue {
 | 
			
		||||
        background-color  #D6E4FF 
 | 
			
		||||
        color  #1062FE 
 | 
			
		||||
      }
 | 
			
		||||
      .green {
 | 
			
		||||
        background-color  #E7F8EB 
 | 
			
		||||
        color  #2D9F46 
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,142 +0,0 @@
 | 
			
		||||
.app-background {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
.member {
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
.member .el-dialog .el-dialog__body {
 | 
			
		||||
  padding-top: 5px;
 | 
			
		||||
}
 | 
			
		||||
.member .el-dialog .el-dialog__body .pay-container .count-down {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.member .el-dialog .el-dialog__body .pay-container .pay-qrcode {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.member .el-dialog .el-dialog__body .pay-container .pay-qrcode .el-image {
 | 
			
		||||
  width: 280px;
 | 
			
		||||
  height: 280px;
 | 
			
		||||
}
 | 
			
		||||
.member .el-dialog .el-dialog__body .pay-container .tip {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.member .el-dialog .el-dialog__body .pay-container .tip .el-icon {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
}
 | 
			
		||||
.member .el-dialog .el-dialog__body .pay-container .tip .text {
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  margin-left: 10px;
 | 
			
		||||
}
 | 
			
		||||
.member .el-dialog .el-dialog__body .pay-container .tip.success {
 | 
			
		||||
  color: #07c160;
 | 
			
		||||
}
 | 
			
		||||
.member .title {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
.member .inner {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  overflow-y: visible;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .user-profile {
 | 
			
		||||
  padding: 0 20px 0 20px;
 | 
			
		||||
  background-color: #1c1c1c;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  border-radius: 10px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 91vh;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .user-profile .el-form-item__label {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  justify-content: start;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .user-profile .user-opt .el-col {
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .user-profile .user-opt .el-col .el-button {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .info {
 | 
			
		||||
  padding: 0 20px 0 20px;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .info .el-alert__description {
 | 
			
		||||
  font-size: 14px !important;
 | 
			
		||||
  color: #1c1c1c;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box {
 | 
			
		||||
  padding: 0 20px 0 5px;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item {
 | 
			
		||||
  border: 1px solid #5f5f5f;
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  transition: all 0.3s ease /* 添加过渡效果 */;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .image-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .image-container .el-image {
 | 
			
		||||
  width: 50px;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .image-container .el-image .el-image__inner {
 | 
			
		||||
  border-radius: 10px;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-title {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-title .name {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  color: #2cc995;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-info {
 | 
			
		||||
  padding: 10px 20px;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  color: #999;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-info .info-line {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 2px 0;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-info .info-line .label {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-info .info-line .price,
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-info .info-line .expire {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  justify-content: right;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-info .info-line .price {
 | 
			
		||||
  color: #f56c6c;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-info .info-line .expire {
 | 
			
		||||
  color: #409eff;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item .product-info .pay-way {
 | 
			
		||||
  padding: 5px 0;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
.member .inner .product-box .list-box .product-item hover {
 | 
			
		||||
  box-shadow: 0 0 10px rgba(71,255,241,0.6) /* 添加阴影效果 */;
 | 
			
		||||
  transform: translateY(-10px) /* 向上移动10像素 */;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,149 +0,0 @@
 | 
			
		||||
.app-background {
 | 
			
		||||
  background-color  #1c1c1c 
 | 
			
		||||
  height  100vh 
 | 
			
		||||
}
 | 
			
		||||
.member {
 | 
			
		||||
  background-color  #1c1c1c 
 | 
			
		||||
  height 100vh 
 | 
			
		||||
  .el-dialog {
 | 
			
		||||
    .el-dialog__body {
 | 
			
		||||
      padding-top 5px 
 | 
			
		||||
      .pay-container {
 | 
			
		||||
        .count-down {
 | 
			
		||||
          display flex 
 | 
			
		||||
          justify-content center 
 | 
			
		||||
        }
 | 
			
		||||
        .pay-qrcode {
 | 
			
		||||
          display flex
 | 
			
		||||
          justify-content center
 | 
			
		||||
          .el-image {
 | 
			
		||||
            width 280px 
 | 
			
		||||
            height 280px 
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        .tip {
 | 
			
		||||
          display flex
 | 
			
		||||
          justify-content center
 | 
			
		||||
          .el-icon {
 | 
			
		||||
            font-size  20px 
 | 
			
		||||
          }
 | 
			
		||||
          .text {
 | 
			
		||||
            font-size  16px 
 | 
			
		||||
            margin-left  10px 
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        .tip.success {
 | 
			
		||||
          color  #07c160 
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .title {
 | 
			
		||||
    text-align  center 
 | 
			
		||||
    background-color  #1c1c1c 
 | 
			
		||||
    font-size 16px 
 | 
			
		||||
    color  #ffffff 
 | 
			
		||||
    padding  5px 
 | 
			
		||||
    font-weight bold
 | 
			
		||||
  }
 | 
			
		||||
  .inner {
 | 
			
		||||
    color  #ffffff 
 | 
			
		||||
    overflow-x hidden
 | 
			
		||||
    overflow-y visible
 | 
			
		||||
    .user-profile {
 | 
			
		||||
      padding  0 20px 0 20px 
 | 
			
		||||
      background-color  #1c1c1c 
 | 
			
		||||
      color  #ffffff 
 | 
			
		||||
      border-radius 10px 
 | 
			
		||||
      width  100% 
 | 
			
		||||
      height  91vh 
 | 
			
		||||
      .el-form-item__label {
 | 
			
		||||
        color  #ffffff 
 | 
			
		||||
        justify-content start 
 | 
			
		||||
      }
 | 
			
		||||
      .user-opt {
 | 
			
		||||
        .el-col {
 | 
			
		||||
          padding  8px 
 | 
			
		||||
          .el-button {
 | 
			
		||||
            width  100% 
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .product-box {
 | 
			
		||||
      .info {
 | 
			
		||||
        .el-alert__description {
 | 
			
		||||
          font-size  14px !important 
 | 
			
		||||
          color #1c1c1c
 | 
			
		||||
          margin  0 
 | 
			
		||||
        }
 | 
			
		||||
        padding  0 20px 0 20px 
 | 
			
		||||
      }
 | 
			
		||||
      .list-box {
 | 
			
		||||
        padding  0 20px 0 5px
 | 
			
		||||
        .product-item {
 | 
			
		||||
          border 1px solid #5f5f5f 
 | 
			
		||||
          border-radius  6px 
 | 
			
		||||
          overflow hidden
 | 
			
		||||
          cursor pointer
 | 
			
		||||
          transition  all 0.3s ease  /* 添加过渡效果 */
 | 
			
		||||
          .image-container {
 | 
			
		||||
            display flex
 | 
			
		||||
            justify-content center
 | 
			
		||||
            .el-image {
 | 
			
		||||
              width  50px
 | 
			
		||||
              .el-image__inner {
 | 
			
		||||
                border-radius  10px 
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          .product-title {
 | 
			
		||||
            display  flex 
 | 
			
		||||
            padding  5px 
 | 
			
		||||
            .name {
 | 
			
		||||
              width  100% 
 | 
			
		||||
              text-align  center 
 | 
			
		||||
              font-size  16px 
 | 
			
		||||
              font-weight  bold 
 | 
			
		||||
              color  #2cc995 
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          .product-info {
 | 
			
		||||
            padding  10px 20px 
 | 
			
		||||
            font-size  14px 
 | 
			
		||||
            color  #999999 
 | 
			
		||||
            .info-line {
 | 
			
		||||
              display  flex 
 | 
			
		||||
              width  100% 
 | 
			
		||||
              padding  2px 0 
 | 
			
		||||
              .label {
 | 
			
		||||
                display  flex 
 | 
			
		||||
                width  100% 
 | 
			
		||||
              }
 | 
			
		||||
              .price, .expire {
 | 
			
		||||
                display  flex 
 | 
			
		||||
                width  100% 
 | 
			
		||||
                justify-content  right 
 | 
			
		||||
              }
 | 
			
		||||
              .price {
 | 
			
		||||
                color  #f56c6c 
 | 
			
		||||
              }
 | 
			
		||||
              .expire {
 | 
			
		||||
                color  #409eff 
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            .pay-way {
 | 
			
		||||
              padding  5px 0 
 | 
			
		||||
              display  flex 
 | 
			
		||||
              justify-content  space-between 
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          & hover {
 | 
			
		||||
            box-shadow  0 0 10px rgba(71, 255, 241, 0.6)  /* 添加阴影效果 */
 | 
			
		||||
            transform  translateY(-10px)  /* 向上移动10像素 */
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,72 +0,0 @@
 | 
			
		||||
.el-overlay-dialog .el-dialog {
 | 
			
		||||
  background-color: #1a1b1e;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__header .el-dialog__title {
 | 
			
		||||
  color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body {
 | 
			
		||||
  padding: 0 0 0 15px !important;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container .image-slot {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .img-container .image-slot .el-icon {
 | 
			
		||||
  font-size: 60px;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info {
 | 
			
		||||
  background-color: #25262b;
 | 
			
		||||
  padding: 1rem 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .prompt {
 | 
			
		||||
  background-color: #35363b;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  max-height: 100px;
 | 
			
		||||
  min-height: 50px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .prompt .el-icon {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 10px;
 | 
			
		||||
  bottom: 10px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper label {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100px;
 | 
			
		||||
  color: #a5a5a5;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .info-line .wrapper .item-value {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  background-color: #35363b;
 | 
			
		||||
  padding: 2px 5px;
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .copy-params {
 | 
			
		||||
  padding: 30px 0 10px 0;
 | 
			
		||||
}
 | 
			
		||||
.el-overlay-dialog .el-dialog .el-dialog__body .el-row .task-info .copy-params .el-button {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,96 +0,0 @@
 | 
			
		||||
.el-overlay-dialog {
 | 
			
		||||
  .el-dialog {
 | 
			
		||||
    background-color #1a1b1e
 | 
			
		||||
 | 
			
		||||
    .el-dialog__header {
 | 
			
		||||
      .el-dialog__title {
 | 
			
		||||
        color #F5F5F5
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-dialog__body {
 | 
			
		||||
      padding 0 0 0 15px !important
 | 
			
		||||
      display flex
 | 
			
		||||
      height 100%
 | 
			
		||||
 | 
			
		||||
      .el-row {
 | 
			
		||||
        width 100%
 | 
			
		||||
 | 
			
		||||
        .img-container {
 | 
			
		||||
          display flex
 | 
			
		||||
          justify-content center
 | 
			
		||||
 | 
			
		||||
          .image-slot {
 | 
			
		||||
            display flex
 | 
			
		||||
            height 100vh
 | 
			
		||||
            align-items center
 | 
			
		||||
            justify-content center
 | 
			
		||||
 | 
			
		||||
            .el-icon {
 | 
			
		||||
              font-size 60px
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .task-info {
 | 
			
		||||
          background-color #25262b
 | 
			
		||||
          padding 1rem 1.5rem
 | 
			
		||||
 | 
			
		||||
          .info-line {
 | 
			
		||||
            width 100%
 | 
			
		||||
 | 
			
		||||
            .prompt {
 | 
			
		||||
              background-color #35363b
 | 
			
		||||
              padding 10px
 | 
			
		||||
              color #999999
 | 
			
		||||
              overflow auto
 | 
			
		||||
              max-height 100px
 | 
			
		||||
              min-height 50px
 | 
			
		||||
 | 
			
		||||
              position relative
 | 
			
		||||
 | 
			
		||||
              .el-icon {
 | 
			
		||||
                position absolute
 | 
			
		||||
                right 10px
 | 
			
		||||
                bottom 10px
 | 
			
		||||
                cursor pointer
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .wrapper {
 | 
			
		||||
              margin-top 10px
 | 
			
		||||
              display flex
 | 
			
		||||
 | 
			
		||||
              label {
 | 
			
		||||
                display flex
 | 
			
		||||
                width 100px
 | 
			
		||||
                color #a5a5a5
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              .item-value {
 | 
			
		||||
                display flex
 | 
			
		||||
                width 100%
 | 
			
		||||
                background-color #35363b
 | 
			
		||||
                padding 2px 5px
 | 
			
		||||
                border-radius 5px
 | 
			
		||||
                color #F5F5F5
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .copy-params {
 | 
			
		||||
            padding 30px 0 10px 0
 | 
			
		||||
 | 
			
		||||
            .el-button {
 | 
			
		||||
              width 100%
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // end el-row
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,106 +0,0 @@
 | 
			
		||||
.task-list-box {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .running-job-list .job-item {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding: 2px;
 | 
			
		||||
  background-color: #555;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .running-job-list .job-item .job-item-inner {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .running-job-list .job-item .job-item-inner .progress {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .running-job-list .job-item .job-item-inner .progress span {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .finish-job-list .job-item {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  border: 1px solid #666;
 | 
			
		||||
  padding: 6px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
  transition: all 0.3s ease; /* 添加过渡效果 */
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .finish-job-list .job-item .opt .opt-line {
 | 
			
		||||
  margin: 6px 0;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .finish-job-list .job-item .opt .opt-line ul {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .finish-job-list .job-item .opt .opt-line ul li {
 | 
			
		||||
  margin-right: 6px;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .finish-job-list .job-item .opt .opt-line ul li a {
 | 
			
		||||
  padding: 3px 0;
 | 
			
		||||
  width: 40px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  display: block;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  background-color: #4e5058;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover {
 | 
			
		||||
  background-color: #6d6f78;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .finish-job-list .job-item .opt .opt-line ul .show-prompt {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .finish-job-list .animate:hover {
 | 
			
		||||
  box-shadow: 0 0 10px rgba(71,255,241,0.6); /* 添加阴影效果 */
 | 
			
		||||
  transform: translateY(-10px); /* 向上移动10像素 */
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .el-image {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .el-image img {
 | 
			
		||||
  height: 240px;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .el-image .el-image-viewer__wrapper img {
 | 
			
		||||
  width: auto;
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .el-image .image-slot {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: column;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  min-height: 200px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  height: 240px;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .el-image .image-slot .iconfont {
 | 
			
		||||
  font-size: 50px;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .el-image.upscale {
 | 
			
		||||
  max-height: 310px;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .el-image.upscale img {
 | 
			
		||||
  height: 310px;
 | 
			
		||||
}
 | 
			
		||||
.task-list-box .el-image.upscale .el-image-viewer__wrapper img {
 | 
			
		||||
  width: auto;
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,142 +0,0 @@
 | 
			
		||||
.task-list-box {
 | 
			
		||||
  width 100%
 | 
			
		||||
  padding 5px
 | 
			
		||||
  color #ffffff
 | 
			
		||||
  overflow-x hidden
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  .running-job-list {
 | 
			
		||||
    .job-item {
 | 
			
		||||
      //border: 1px solid #454545;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      padding 2px
 | 
			
		||||
      background-color #555555
 | 
			
		||||
 | 
			
		||||
      .job-item-inner {
 | 
			
		||||
        position relative
 | 
			
		||||
        height 100%
 | 
			
		||||
        overflow hidden
 | 
			
		||||
 | 
			
		||||
        .progress {
 | 
			
		||||
          position absolute
 | 
			
		||||
          width 100%
 | 
			
		||||
          height 100%
 | 
			
		||||
          top 0
 | 
			
		||||
          left 0
 | 
			
		||||
          display flex
 | 
			
		||||
          justify-content center
 | 
			
		||||
          align-items center
 | 
			
		||||
 | 
			
		||||
          span {
 | 
			
		||||
            font-size 20px
 | 
			
		||||
            color #ffffff
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  .finish-job-list {
 | 
			
		||||
    .job-item {
 | 
			
		||||
      width 100%
 | 
			
		||||
      height 100%
 | 
			
		||||
      border 1px solid #666666
 | 
			
		||||
      padding 6px
 | 
			
		||||
      overflow hidden
 | 
			
		||||
      border-radius 6px
 | 
			
		||||
      transition: all 0.3s ease; /* 添加过渡效果 */
 | 
			
		||||
 | 
			
		||||
      .opt {
 | 
			
		||||
        .opt-line {
 | 
			
		||||
          margin 6px 0
 | 
			
		||||
 | 
			
		||||
          ul {
 | 
			
		||||
            display flex
 | 
			
		||||
            flex-flow row
 | 
			
		||||
 | 
			
		||||
            li {
 | 
			
		||||
              margin-right 6px
 | 
			
		||||
 | 
			
		||||
              a {
 | 
			
		||||
                padding 3px 0
 | 
			
		||||
                width 40px
 | 
			
		||||
                text-align center
 | 
			
		||||
                border-radius 5px
 | 
			
		||||
                display block
 | 
			
		||||
                cursor pointer
 | 
			
		||||
                background-color #4E5058
 | 
			
		||||
                color #ffffff
 | 
			
		||||
 | 
			
		||||
                &:hover {
 | 
			
		||||
                  background-color #6D6F78
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .show-prompt {
 | 
			
		||||
              font-size 20px
 | 
			
		||||
              cursor pointer
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .animate {
 | 
			
		||||
      &:hover {
 | 
			
		||||
        box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* 添加阴影效果 */
 | 
			
		||||
        transform: translateY(-10px); /* 向上移动10像素 */
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .el-image {
 | 
			
		||||
    width 100%
 | 
			
		||||
    height 100%
 | 
			
		||||
    overflow visible
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
      height 240px
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-image-viewer__wrapper {
 | 
			
		||||
      img {
 | 
			
		||||
        width auto
 | 
			
		||||
        height auto
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .image-slot {
 | 
			
		||||
      display flex
 | 
			
		||||
      flex-flow column
 | 
			
		||||
      justify-content center
 | 
			
		||||
      align-items center
 | 
			
		||||
      height 100%
 | 
			
		||||
      min-height 200px
 | 
			
		||||
      color #ffffff
 | 
			
		||||
      height 240px
 | 
			
		||||
 | 
			
		||||
      .iconfont {
 | 
			
		||||
        font-size 50px
 | 
			
		||||
        margin-bottom 10px
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .el-image.upscale {
 | 
			
		||||
    max-height 310px
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
      height 310px
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-image-viewer__wrapper {
 | 
			
		||||
      img {
 | 
			
		||||
        width auto
 | 
			
		||||
        height auto
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -176,26 +176,12 @@ const routes = [
 | 
			
		||||
                name: 'mobile-chat-list',
 | 
			
		||||
                component: () => import('@/views/mobile/ChatList.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/mobile/imageSd',
 | 
			
		||||
                name: 'mobile-imageSd',
 | 
			
		||||
                component: () => import('@/views/mobile/ImageSd.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/mobile/apps',
 | 
			
		||||
                name: 'mobile-apps',
 | 
			
		||||
                component: () => import('@/views/mobile/Apps.vue'),
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            {
 | 
			
		||||
                path: '/mobile/profile',
 | 
			
		||||
                name: 'mobile-profile',
 | 
			
		||||
                component: () => import('@/views/mobile/Profile.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/mobile/invitation',
 | 
			
		||||
                name: 'mobile-invitation',
 | 
			
		||||
                component: () => import('@/views/mobile/Invitation.vue'),
 | 
			
		||||
            },
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -567,6 +567,19 @@ const connect = function (chat_id, role_id) {
 | 
			
		||||
      host = 'ws://' + location.host;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 心跳函数
 | 
			
		||||
  const sendHeartbeat = () => {
 | 
			
		||||
    clearTimeout(heartbeatHandle.value)
 | 
			
		||||
    new Promise((resolve, reject) => {
 | 
			
		||||
      if (socket.value !== null) {
 | 
			
		||||
        socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
 | 
			
		||||
      }
 | 
			
		||||
      resolve("success")
 | 
			
		||||
    }).then(() => {
 | 
			
		||||
      heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000)
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  const _socket = new WebSocket(host + `/api/chat/new?session_id=${_sessionId}&role_id=${role_id}&chat_id=${chat_id}&model_id=${modelID.value}&token=${getUserToken()}`);
 | 
			
		||||
  _socket.addEventListener('open', () => {
 | 
			
		||||
    chatData.value = []; // 初始化聊天数据
 | 
			
		||||
@@ -589,15 +602,8 @@ const connect = function (chat_id, role_id) {
 | 
			
		||||
    } else { // 加载聊天记录
 | 
			
		||||
      loadChatHistory(chat_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 发送心跳消息
 | 
			
		||||
    clearInterval(heartbeatHandle.value)
 | 
			
		||||
    heartbeatHandle.value = setInterval(() => {
 | 
			
		||||
      if (socket.value !== null) {
 | 
			
		||||
        socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
 | 
			
		||||
      }
 | 
			
		||||
    }, 5000);
 | 
			
		||||
 | 
			
		||||
    sendHeartbeat()
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _socket.addEventListener('message', event => {
 | 
			
		||||
 
 | 
			
		||||
@@ -573,17 +573,26 @@ const connect = () => {
 | 
			
		||||
      host = 'ws://' + location.host;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 心跳函数
 | 
			
		||||
  const sendHeartbeat = () => {
 | 
			
		||||
    clearTimeout(heartbeatHandle.value)
 | 
			
		||||
    new Promise((resolve, reject) => {
 | 
			
		||||
      if (socket.value !== null) {
 | 
			
		||||
        socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
 | 
			
		||||
      }
 | 
			
		||||
      resolve("success")
 | 
			
		||||
    }).then(() => {
 | 
			
		||||
      heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000)
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const _socket = new WebSocket(host + `/api/mj/client?user_id=${userId.value}`);
 | 
			
		||||
  _socket.addEventListener('open', () => {
 | 
			
		||||
    socket.value = _socket;
 | 
			
		||||
 | 
			
		||||
    // 发送心跳消息
 | 
			
		||||
    clearInterval(heartbeatHandle.value)
 | 
			
		||||
    heartbeatHandle.value = setInterval(() => {
 | 
			
		||||
      if (socket.value !== null) {
 | 
			
		||||
        socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
 | 
			
		||||
      }
 | 
			
		||||
    }, 5000);
 | 
			
		||||
    sendHeartbeat()
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _socket.addEventListener('message', event => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="app-background">
 | 
			
		||||
    <div class="mobile-setting container">
 | 
			
		||||
      <div class="title" style="padding-top: 50px">应用广场</div>
 | 
			
		||||
      <div class="title" style="padding-top: 200px">视频生成器即将开启……敬请期待</div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
@import "@/assets/css/mobile/apps.styl"
 | 
			
		||||
</style>
 | 
			
		||||
@@ -261,5 +261,49 @@ const removeChat = (item) => {
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
@import "@/assets/css/mobile/chat-list.styl"
 | 
			
		||||
$fontSize = 16px;
 | 
			
		||||
.mobile-chat-list {
 | 
			
		||||
 | 
			
		||||
  .content {
 | 
			
		||||
    .van-cell__value {
 | 
			
		||||
      .chat-list-item {
 | 
			
		||||
        display flex
 | 
			
		||||
        font-size $fontSize
 | 
			
		||||
 | 
			
		||||
        .van-image {
 | 
			
		||||
          min-width 32px
 | 
			
		||||
          width 32px
 | 
			
		||||
          height 32px
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .van-ellipsis {
 | 
			
		||||
          margin-top 5px;
 | 
			
		||||
          margin-left 10px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .van-picker-column {
 | 
			
		||||
    .picker-option {
 | 
			
		||||
      display flex
 | 
			
		||||
      width 100%
 | 
			
		||||
      padding 0 10px
 | 
			
		||||
 | 
			
		||||
      .van-image {
 | 
			
		||||
        width 20px;
 | 
			
		||||
        height 20px;
 | 
			
		||||
        margin-right 5px
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .van-nav-bar {
 | 
			
		||||
    .van-nav-bar__right {
 | 
			
		||||
      .van-icon {
 | 
			
		||||
        font-size 20px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,99 +1,103 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="app-background">
 | 
			
		||||
    <van-config-provider theme="dark">
 | 
			
		||||
      <div class="mobile-chat" v-loading="loading" element-loading-text="正在连接会话...">
 | 
			
		||||
        <van-sticky ref="navBarRef" :offset-top="0" position="top">
 | 
			
		||||
          <van-nav-bar left-arrow left-text="返回" @click-left="router.back()">
 | 
			
		||||
            <template #title>
 | 
			
		||||
              <van-dropdown-menu>
 | 
			
		||||
                <van-dropdown-item :title="title">
 | 
			
		||||
                  <van-cell center title="角色"> {{ role.name }}</van-cell>
 | 
			
		||||
                  <van-cell center title="模型">{{ modelValue }}</van-cell>
 | 
			
		||||
                </van-dropdown-item>
 | 
			
		||||
              </van-dropdown-menu>
 | 
			
		||||
            </template>
 | 
			
		||||
    <div class="mobile-chat" v-loading="loading" element-loading-text="正在连接会话...">
 | 
			
		||||
      <van-sticky ref="navBarRef" :offset-top="0" position="top">
 | 
			
		||||
        <van-nav-bar left-arrow left-text="返回" @click-left="router.back()">
 | 
			
		||||
          <template #title>
 | 
			
		||||
            <van-dropdown-menu>
 | 
			
		||||
              <van-dropdown-item :title="title">
 | 
			
		||||
                <van-cell center title="角色"> {{ role.name }}</van-cell>
 | 
			
		||||
                <van-cell center title="模型">{{ modelValue }}</van-cell>
 | 
			
		||||
              </van-dropdown-item>
 | 
			
		||||
            </van-dropdown-menu>
 | 
			
		||||
          </template>
 | 
			
		||||
 | 
			
		||||
            <template #right>
 | 
			
		||||
              <van-icon name="share-o" @click="showShare = true"/>
 | 
			
		||||
            </template>
 | 
			
		||||
          <template #right>
 | 
			
		||||
            <van-icon name="share-o" @click="showShare = true"/>
 | 
			
		||||
          </template>
 | 
			
		||||
 | 
			
		||||
          </van-nav-bar>
 | 
			
		||||
        </van-sticky>
 | 
			
		||||
        </van-nav-bar>
 | 
			
		||||
      </van-sticky>
 | 
			
		||||
 | 
			
		||||
        <van-share-sheet
 | 
			
		||||
            v-model:show="showShare"
 | 
			
		||||
            title="立即分享给好友"
 | 
			
		||||
            :options="shareOptions"
 | 
			
		||||
            @select="shareChat"
 | 
			
		||||
        />
 | 
			
		||||
      <van-share-sheet
 | 
			
		||||
          v-model:show="showShare"
 | 
			
		||||
          title="立即分享给好友"
 | 
			
		||||
          :options="shareOptions"
 | 
			
		||||
          @select="shareChat"
 | 
			
		||||
      />
 | 
			
		||||
 | 
			
		||||
        <div class="chat-list-wrapper">
 | 
			
		||||
          <div id="message-list-box" :style="{height: winHeight + 'px'}" class="message-list-box">
 | 
			
		||||
            <van-list
 | 
			
		||||
                v-model:error="error"
 | 
			
		||||
                :finished="finished"
 | 
			
		||||
                error-text="请求失败,点击重新加载"
 | 
			
		||||
                @load="onLoad"
 | 
			
		||||
            >
 | 
			
		||||
              <van-cell v-for="item in chatData" :key="item" :border="false" class="message-line">
 | 
			
		||||
                <chat-prompt
 | 
			
		||||
                    v-if="item.type==='prompt'"
 | 
			
		||||
                    :content="item.content"
 | 
			
		||||
                    :created-at="dateFormat(item['created_at'])"
 | 
			
		||||
                    :icon="item.icon"
 | 
			
		||||
                    :model="model"
 | 
			
		||||
                    :tokens="item['tokens']"/>
 | 
			
		||||
                <chat-reply v-else-if="item.type==='reply'"
 | 
			
		||||
                            :content="item.content"
 | 
			
		||||
                            :created-at="dateFormat(item['created_at'])"
 | 
			
		||||
                            :icon="item.icon"
 | 
			
		||||
                            :org-content="item.orgContent"
 | 
			
		||||
                            :tokens="item['tokens']"/>
 | 
			
		||||
                <chat-mid-journey v-else-if="item.type==='mj'"
 | 
			
		||||
                                  :content="item.content"
 | 
			
		||||
                                  :icon="item.icon"
 | 
			
		||||
                                  :role-id="role"
 | 
			
		||||
                                  :chat-id="chatId"
 | 
			
		||||
                                  @disable-input="disableInput(true)"
 | 
			
		||||
                                  @enable-input="enableInput"
 | 
			
		||||
                                  :created-at="dateFormat(item['created_at'])"/>
 | 
			
		||||
              </van-cell>
 | 
			
		||||
            </van-list>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="chat-box-wrapper">
 | 
			
		||||
          <van-sticky ref="bottomBarRef" :offset-bottom="0" position="bottom">
 | 
			
		||||
 | 
			
		||||
            <van-cell-group inset>
 | 
			
		||||
              <van-field
 | 
			
		||||
                  v-model="prompt"
 | 
			
		||||
                  center
 | 
			
		||||
                  clearable
 | 
			
		||||
                  placeholder="输入你的问题"
 | 
			
		||||
              >
 | 
			
		||||
                <template #button>
 | 
			
		||||
                  <van-button size="small" type="primary" @click="sendMessage">发送</van-button>
 | 
			
		||||
                </template>
 | 
			
		||||
                <template #extra>
 | 
			
		||||
                  <div class="icon-box">
 | 
			
		||||
                    <van-icon v-if="showStopGenerate" name="stop-circle-o" @click="stopGenerate"/>
 | 
			
		||||
                    <van-icon v-if="showReGenerate" name="play-circle-o" @click="reGenerate"/>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </template>
 | 
			
		||||
              </van-field>
 | 
			
		||||
            </van-cell-group>
 | 
			
		||||
 | 
			
		||||
          </van-sticky>
 | 
			
		||||
      <div class="chat-list-wrapper">
 | 
			
		||||
        <div id="message-list-box" :style="{height: winHeight + 'px'}" class="message-list-box">
 | 
			
		||||
          <van-list
 | 
			
		||||
              v-model:error="error"
 | 
			
		||||
              :finished="finished"
 | 
			
		||||
              error-text="请求失败,点击重新加载"
 | 
			
		||||
              @load="onLoad"
 | 
			
		||||
          >
 | 
			
		||||
            <van-cell v-for="item in chatData" :key="item" :border="false" class="message-line">
 | 
			
		||||
              <chat-prompt
 | 
			
		||||
                  v-if="item.type==='prompt'"
 | 
			
		||||
                  :content="item.content"
 | 
			
		||||
                  :created-at="dateFormat(item['created_at'])"
 | 
			
		||||
                  :icon="item.icon"
 | 
			
		||||
                  :model="model"
 | 
			
		||||
                  :tokens="item['tokens']"/>
 | 
			
		||||
              <chat-reply v-else-if="item.type==='reply'"
 | 
			
		||||
                          :content="item.content"
 | 
			
		||||
                          :created-at="dateFormat(item['created_at'])"
 | 
			
		||||
                          :icon="item.icon"
 | 
			
		||||
                          :org-content="item.orgContent"
 | 
			
		||||
                          :tokens="item['tokens']"/>
 | 
			
		||||
              <chat-mid-journey v-else-if="item.type==='mj'"
 | 
			
		||||
                                :content="item.content"
 | 
			
		||||
                                :icon="item.icon"
 | 
			
		||||
                                :role-id="role"
 | 
			
		||||
                                :chat-id="chatId"
 | 
			
		||||
                                @disable-input="disableInput(true)"
 | 
			
		||||
                                @enable-input="enableInput"
 | 
			
		||||
                                :created-at="dateFormat(item['created_at'])"/>
 | 
			
		||||
            </van-cell>
 | 
			
		||||
          </van-list>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </van-config-provider>
 | 
			
		||||
      <div class="chat-box-wrapper">
 | 
			
		||||
        <van-sticky ref="bottomBarRef" :offset-bottom="0" position="bottom">
 | 
			
		||||
 | 
			
		||||
          <van-cell-group inset>
 | 
			
		||||
            <van-field
 | 
			
		||||
                v-model="prompt"
 | 
			
		||||
                center
 | 
			
		||||
                clearable
 | 
			
		||||
                placeholder="输入你的问题"
 | 
			
		||||
            >
 | 
			
		||||
              <template #left-icon>
 | 
			
		||||
                <van-button round type="success" class="button-voice" @click="inputVoice">
 | 
			
		||||
                  <van-icon name="volume-o"/>
 | 
			
		||||
                </van-button>
 | 
			
		||||
              </template>
 | 
			
		||||
 | 
			
		||||
              <template #button>
 | 
			
		||||
                <van-button size="small" type="primary" @click="sendMessage">发送</van-button>
 | 
			
		||||
              </template>
 | 
			
		||||
              <template #extra>
 | 
			
		||||
                <div class="icon-box">
 | 
			
		||||
                  <van-icon v-if="showStopGenerate" name="stop-circle-o" @click="stopGenerate"/>
 | 
			
		||||
                  <van-icon v-if="showReGenerate" name="play-circle-o" @click="reGenerate"/>
 | 
			
		||||
                </div>
 | 
			
		||||
              </template>
 | 
			
		||||
            </van-field>
 | 
			
		||||
          </van-cell-group>
 | 
			
		||||
 | 
			
		||||
        </van-sticky>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {nextTick, onMounted, ref} from "vue";
 | 
			
		||||
import {showToast} from "vant";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import {showFailToast, showNotify, showToast} from "vant";
 | 
			
		||||
import {onBeforeRouteLeave, useRouter} from "vue-router";
 | 
			
		||||
import {dateFormat, randString, renderInputText, UUID} from "@/utils/libs";
 | 
			
		||||
import {getChatConfig} from "@/store/chat";
 | 
			
		||||
import {httpGet} from "@/utils/http";
 | 
			
		||||
@@ -103,14 +107,8 @@ import ChatPrompt from "@/components/mobile/ChatPrompt.vue";
 | 
			
		||||
import ChatReply from "@/components/mobile/ChatReply.vue";
 | 
			
		||||
import {getSessionId, getUserToken} from "@/store/session";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import {getMobileTheme} from "@/store/system";
 | 
			
		||||
import ChatMidJourney from "@/components/mobile/ChatMidJourney.vue";
 | 
			
		||||
 | 
			
		||||
import QRCode from "qrcode";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
import InviteList from "@/components/InviteList.vue";
 | 
			
		||||
 | 
			
		||||
const winHeight = ref(0)
 | 
			
		||||
const navBarRef = ref(null)
 | 
			
		||||
const bottomBarRef = ref(null)
 | 
			
		||||
@@ -124,15 +122,7 @@ const title = chatConfig.title
 | 
			
		||||
const chatId = chatConfig.chatId
 | 
			
		||||
const loginUser = ref(null)
 | 
			
		||||
 | 
			
		||||
const listBoxHeight = window.innerHeight
 | 
			
		||||
const inviteURL = ref("")
 | 
			
		||||
const qrImg = ref("")
 | 
			
		||||
const inviteChatCalls = ref(0)
 | 
			
		||||
const inviteImgCalls = ref(0)
 | 
			
		||||
const hits = ref(0)
 | 
			
		||||
const regNum = ref(0)
 | 
			
		||||
const rate = ref(0)
 | 
			
		||||
const isLogin = ref(false)
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  winHeight.value = document.body.offsetHeight - navBarRef.value.$el.offsetHeight - bottomBarRef.value.$el.offsetHeight
 | 
			
		||||
@@ -191,6 +181,16 @@ const onLoad = () => {
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 离开页面时主动关闭 websocket 连接,节省网络资源
 | 
			
		||||
onBeforeRouteLeave(() => {
 | 
			
		||||
  if (socket.value !== null) {
 | 
			
		||||
    activelyClose.value = true;
 | 
			
		||||
    clearTimeout(heartbeatHandle.value)
 | 
			
		||||
    socket.value.close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 创建 socket 连接
 | 
			
		||||
const prompt = ref('');
 | 
			
		||||
const showStopGenerate = ref(false); // 停止生成
 | 
			
		||||
@@ -207,11 +207,6 @@ const connect = function (chat_id, role_id) {
 | 
			
		||||
    isNewChat = true;
 | 
			
		||||
    chat_id = UUID();
 | 
			
		||||
  }
 | 
			
		||||
  // 先关闭已有连接
 | 
			
		||||
  if (socket.value !== null) {
 | 
			
		||||
    activelyClose.value = true;
 | 
			
		||||
    socket.value.close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 初始化 WebSocket 对象
 | 
			
		||||
  const _sessionId = getSessionId();
 | 
			
		||||
@@ -223,6 +218,19 @@ const connect = function (chat_id, role_id) {
 | 
			
		||||
      host = 'ws://' + location.host;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 心跳函数
 | 
			
		||||
  const sendHeartbeat = () => {
 | 
			
		||||
    if (socket.value !== null) {
 | 
			
		||||
      new Promise((resolve) => {
 | 
			
		||||
        socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
 | 
			
		||||
        resolve("success")
 | 
			
		||||
      }).then(() => {
 | 
			
		||||
        heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000)
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const _socket = new WebSocket(host + `/api/chat/new?session_id=${_sessionId}&role_id=${role_id}&chat_id=${chat_id}&model_id=${model}&token=${getUserToken()}`);
 | 
			
		||||
  _socket.addEventListener('open', () => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
@@ -241,12 +249,7 @@ const connect = function (chat_id, role_id) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 发送心跳消息
 | 
			
		||||
    clearInterval(heartbeatHandle.value)
 | 
			
		||||
    heartbeatHandle.value = setInterval(() => {
 | 
			
		||||
      if (socket.value !== null) {
 | 
			
		||||
        socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
 | 
			
		||||
      }
 | 
			
		||||
    }, 5000);
 | 
			
		||||
    sendHeartbeat()
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _socket.addEventListener('message', event => {
 | 
			
		||||
@@ -327,6 +330,7 @@ const connect = function (chat_id, role_id) {
 | 
			
		||||
    // 停止发送消息
 | 
			
		||||
    canSend.value = true;
 | 
			
		||||
    socket.value = null;
 | 
			
		||||
    // 重连
 | 
			
		||||
    checkSession().then(() => {
 | 
			
		||||
      connect(chat_id, role_id)
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
@@ -408,16 +412,34 @@ const reGenerate = () => {
 | 
			
		||||
const showShare = ref(false)
 | 
			
		||||
const shareOptions = [
 | 
			
		||||
  {name: '微信', icon: 'wechat'},
 | 
			
		||||
  {name: '微博', icon: 'weibo'},
 | 
			
		||||
  {name: '复制链接', icon: 'link'},
 | 
			
		||||
  {name: '分享海报', icon: 'poster'},
 | 
			
		||||
]
 | 
			
		||||
const shareChat = () => {
 | 
			
		||||
  showShare.value = false
 | 
			
		||||
  router.push('/mobile/Invitation');
 | 
			
		||||
  showToast('功能待开发')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const inputVoice = () => {
 | 
			
		||||
  const recognition = new webkitSpeechRecognition() || SpeechRecognition();
 | 
			
		||||
  // recognition.lang = 'zh-CN' // 设置语音识别语言
 | 
			
		||||
 | 
			
		||||
  recognition.onresult = function (event) {
 | 
			
		||||
    const result = event.results[0][0].transcript;
 | 
			
		||||
    showToast('你说了: ' + result)
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  recognition.onerror = function (event) {
 | 
			
		||||
    showNotify({type: 'danger', message: '语音识别错误:' + event.error})
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  recognition.onend = function () {
 | 
			
		||||
    console.log('语音识别结束');
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  recognition.start();
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
@import "@/assets/css/mobile/chat-session.css"
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
@import "@/assets/css/mobile/chat-session.styl"
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,26 +1,17 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="banner">
 | 
			
		||||
    <h1 class="banner-title">ChatPuls-V3 智能助理</h1>
 | 
			
		||||
  </div>
 | 
			
		||||
  <van-config-provider theme="dark">
 | 
			
		||||
  <van-config-provider :theme="getMobileTheme()">
 | 
			
		||||
    <div class="mobile-home">
 | 
			
		||||
      <router-view/>
 | 
			
		||||
      <van-tabbar
 | 
			
		||||
          fixed
 | 
			
		||||
          route
 | 
			
		||||
          v-model="active"
 | 
			
		||||
          active-color="#F5F5F5"
 | 
			
		||||
          inactive-color="#2CC995"
 | 
			
		||||
          class="my-tabbar"
 | 
			
		||||
      >
 | 
			
		||||
        <van-tabbar-item to="/mobile/chat/list" name="home" icon="chat-o">对话</van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/imageSd" name="imageSd" icon="photo-o">绘图</van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/apps" name="apps" icon="apps-o">应用</van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/profile" name="profile" icon="user-o">我的</van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/invitation" name="invitation" icon="share-o">分享</van-tabbar-item>
 | 
			
		||||
 | 
			
		||||
      <van-tabbar route v-model="active" @change="onChange">
 | 
			
		||||
        <van-tabbar-item to="/mobile/chat/list" name="home" icon="chat-o"></van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/setting" name="setting" icon="setting-o"></van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/profile" name="profile" icon="user-o"></van-tabbar-item>
 | 
			
		||||
      </van-tabbar>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </van-config-provider>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
@@ -47,6 +38,33 @@ const onChange = (index) => {
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
@import "@/assets/css/mobile/home.css"
 | 
			
		||||
</style>
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.mobile-home {
 | 
			
		||||
  .container {
 | 
			
		||||
    .van-nav-bar {
 | 
			
		||||
      position fixed
 | 
			
		||||
      width 100%
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .content {
 | 
			
		||||
      padding 46px 10px 0 10px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 黑色主题
 | 
			
		||||
.van-theme-dark body {
 | 
			
		||||
  background #1c1c1e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.van-toast--fail {
 | 
			
		||||
  background #fef0f0
 | 
			
		||||
  color #f56c6c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.van-nav-bar {
 | 
			
		||||
  position fixed
 | 
			
		||||
  width 100%
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,657 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="page-sd" theme="dark">
 | 
			
		||||
    <div class="inner">
 | 
			
		||||
      <div class="sd-box" style="padding-top: 35px">
 | 
			
		||||
        <h2>Ai绘图</h2>
 | 
			
		||||
        <div class="sd-params" :style="{ height: mjBoxHeight + 'px' }">
 | 
			
		||||
          <el-form :model="params" label-width="80px" label-position="left">
 | 
			
		||||
            <div class="param-line" style="padding-top: 10px">
 | 
			
		||||
              <el-form-item label="采样方法">
 | 
			
		||||
                <template #default>
 | 
			
		||||
                  <div class="form-item-inner">
 | 
			
		||||
                    <el-select v-model="params.sampler" size="small">
 | 
			
		||||
                      <el-option v-for="item in samplers" :label="item" :value="item" :key="item"/>
 | 
			
		||||
                    </el-select>
 | 
			
		||||
                    <el-tooltip
 | 
			
		||||
                        effect="light"
 | 
			
		||||
                        content="出图效果比较好的一般是 Euler 和 DPM 系列算法"
 | 
			
		||||
                        raw-content
 | 
			
		||||
                        placement="right"
 | 
			
		||||
                    >
 | 
			
		||||
                      <el-icon>
 | 
			
		||||
                        <InfoFilled/>
 | 
			
		||||
                      </el-icon>
 | 
			
		||||
                    </el-tooltip>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </template>
 | 
			
		||||
              </el-form-item>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="param-line">
 | 
			
		||||
              <el-form-item label="图片尺寸">
 | 
			
		||||
                <template #default>
 | 
			
		||||
                  <div class="form-item-inner">
 | 
			
		||||
                    <el-row :gutter="20">
 | 
			
		||||
                      <el-col :span="12">
 | 
			
		||||
                        <el-input v-model.number="params.width" size="small" placeholder="图片宽度"/>
 | 
			
		||||
                      </el-col>
 | 
			
		||||
                      <el-col :span="12">
 | 
			
		||||
                        <el-input v-model.number="params.height" size="small" placeholder="图片高度"/>
 | 
			
		||||
                      </el-col>
 | 
			
		||||
                    </el-row>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </template>
 | 
			
		||||
              </el-form-item>
 | 
			
		||||
            </div>
 | 
			
		||||
            <!-- 这是一个示例注释
 | 
			
		||||
                        <div class="param-line">
 | 
			
		||||
                          <el-form-item label="迭代步数">
 | 
			
		||||
                            <template #default>
 | 
			
		||||
                              <div class="form-item-inner">
 | 
			
		||||
                                <el-input v-model.number="params.steps" size="small"/>
 | 
			
		||||
                                <el-tooltip
 | 
			
		||||
                                    effect="light"
 | 
			
		||||
                                    content="值越大则代表细节越多,同时也意味着出图速度越慢"
 | 
			
		||||
                                    raw-content
 | 
			
		||||
                                    placement="right"
 | 
			
		||||
                                >
 | 
			
		||||
                                  <el-icon>
 | 
			
		||||
                                    <InfoFilled/>
 | 
			
		||||
                                  </el-icon>
 | 
			
		||||
                                </el-tooltip>
 | 
			
		||||
                              </div>
 | 
			
		||||
                            </template>
 | 
			
		||||
                          </el-form-item>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="param-line">
 | 
			
		||||
                          <el-form-item label="引导系数">
 | 
			
		||||
                            <template #default>
 | 
			
		||||
                              <div class="form-item-inner">
 | 
			
		||||
                                <el-input v-model.number="params.cfg_scale" size="small"/>
 | 
			
		||||
                                <el-tooltip
 | 
			
		||||
                                    effect="light"
 | 
			
		||||
                                    content="提示词引导系数,图像在多大程度上服从提示词<br/> 较低值会产生更有创意的结果"
 | 
			
		||||
                                    raw-content
 | 
			
		||||
                                    placement="right"
 | 
			
		||||
                                >
 | 
			
		||||
                                  <el-icon>
 | 
			
		||||
                                    <InfoFilled/>
 | 
			
		||||
                                  </el-icon>
 | 
			
		||||
                                </el-tooltip>
 | 
			
		||||
                              </div>
 | 
			
		||||
                            </template>
 | 
			
		||||
                          </el-form-item>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="param-line">
 | 
			
		||||
                          <el-form-item label="随机因子">
 | 
			
		||||
                            <template #default>
 | 
			
		||||
                              <div class="form-item-inner">
 | 
			
		||||
                                <el-input v-model.number="params.seed" size="small"/>
 | 
			
		||||
                                <el-tooltip
 | 
			
		||||
                                    effect="light"
 | 
			
		||||
                                    content="随机数种子,相同的种子会得到相同的结果<br/> 设置为 -1 则每次随机生成种子"
 | 
			
		||||
                                    raw-content
 | 
			
		||||
                                    placement="right"
 | 
			
		||||
                                >
 | 
			
		||||
                                  <el-icon>
 | 
			
		||||
                                    <InfoFilled/>
 | 
			
		||||
                                  </el-icon>
 | 
			
		||||
                                </el-tooltip>
 | 
			
		||||
 | 
			
		||||
                                <el-tooltip
 | 
			
		||||
                                    effect="light"
 | 
			
		||||
                                    content="使用随机数"
 | 
			
		||||
                                    raw-content
 | 
			
		||||
                                    placement="right"
 | 
			
		||||
                                >
 | 
			
		||||
                                  <el-icon @click="params.seed = -1">
 | 
			
		||||
                                    <Orange/>
 | 
			
		||||
                                  </el-icon>
 | 
			
		||||
                                </el-tooltip>
 | 
			
		||||
                              </div>
 | 
			
		||||
                            </template>
 | 
			
		||||
                          </el-form-item>
 | 
			
		||||
                        </div>
 | 
			
		||||
             -->
 | 
			
		||||
            <!-- 这是一个示例注释
 | 
			
		||||
                       <div class="param-line">
 | 
			
		||||
                         <el-form-item label="面部修复">
 | 
			
		||||
                           <template #default>
 | 
			
		||||
                             <div class="form-item-inner">
 | 
			
		||||
                               <el-switch v-model="params.face_fix" style="--el-switch-on-color: #47fff1;"/>
 | 
			
		||||
                               <el-tooltip
 | 
			
		||||
                                   effect="light"
 | 
			
		||||
                                   content="仅对绘制人物图像有效果。"
 | 
			
		||||
                                   raw-content
 | 
			
		||||
                                   placement="right"
 | 
			
		||||
                               >
 | 
			
		||||
                                 <el-icon style="margin-top: 6px">
 | 
			
		||||
                                   <InfoFilled/>
 | 
			
		||||
                                 </el-icon>
 | 
			
		||||
                               </el-tooltip>
 | 
			
		||||
                             </div>
 | 
			
		||||
                           </template>
 | 
			
		||||
                         </el-form-item>
 | 
			
		||||
                       </div>
 | 
			
		||||
 | 
			
		||||
                       <div class="param-line">
 | 
			
		||||
                         <el-form-item label="高清修复">
 | 
			
		||||
                           <template #default>
 | 
			
		||||
                             <div class="form-item-inner">
 | 
			
		||||
                               <el-switch v-model="params.hd_fix" style="--el-switch-on-color: #47fff1;"/>
 | 
			
		||||
                               <el-tooltip
 | 
			
		||||
                                   effect="light"
 | 
			
		||||
                                   content="先以较小的分辨率生成图像,接着方法图像<br />然后在不更改构图的情况下再修改细节"
 | 
			
		||||
                                   raw-content
 | 
			
		||||
                                   placement="right"
 | 
			
		||||
                               >
 | 
			
		||||
                                 <el-icon style="margin-top: 6px">
 | 
			
		||||
                                   <InfoFilled/>
 | 
			
		||||
                                 </el-icon>
 | 
			
		||||
                               </el-tooltip>
 | 
			
		||||
                             </div>
 | 
			
		||||
                           </template>
 | 
			
		||||
                         </el-form-item>
 | 
			
		||||
                       </div>
 | 
			
		||||
 | 
			
		||||
                       <div v-show="params.hd_fix">
 | 
			
		||||
                         <div class="param-line">
 | 
			
		||||
                           <el-form-item label="重绘幅度">
 | 
			
		||||
                             <template #default>
 | 
			
		||||
                               <div class="form-item-inner">
 | 
			
		||||
                                 <el-slider v-model.number="params.hd_redraw_rate" :max="1" :step="0.1"
 | 
			
		||||
                                            style="width: 180px;--el-slider-main-bg-color:#47fff1"/>
 | 
			
		||||
                                 <el-tooltip
 | 
			
		||||
                                     effect="light"
 | 
			
		||||
                                     content="决定算法对图像内容的影响程度<br />较大的值将得到越有创意的图像"
 | 
			
		||||
                                     raw-content
 | 
			
		||||
                                     placement="right"
 | 
			
		||||
                                 >
 | 
			
		||||
                                   <el-icon style="margin-top: 6px">
 | 
			
		||||
                                     <InfoFilled/>
 | 
			
		||||
                                   </el-icon>
 | 
			
		||||
                                 </el-tooltip>
 | 
			
		||||
                               </div>
 | 
			
		||||
                             </template>
 | 
			
		||||
                           </el-form-item>
 | 
			
		||||
                         </div>
 | 
			
		||||
 | 
			
		||||
                         <div class="param-line">
 | 
			
		||||
                           <el-form-item label="放大算法">
 | 
			
		||||
                             <template #default>
 | 
			
		||||
                               <div class="form-item-inner">
 | 
			
		||||
                                 <el-select v-model="params.hd_scale_alg" size="small">
 | 
			
		||||
                                   <el-option v-for="item in scaleAlg" :label="item" :value="item" :key="item"/>
 | 
			
		||||
                                 </el-select>
 | 
			
		||||
                                 <el-tooltip
 | 
			
		||||
                                     effect="light"
 | 
			
		||||
                                     content="高清修复放大算法,主流算法有Latent和ESRGAN_4x"
 | 
			
		||||
                                     raw-content
 | 
			
		||||
                                     placement="right"
 | 
			
		||||
                                 >
 | 
			
		||||
                                   <el-icon>
 | 
			
		||||
                                     <InfoFilled/>
 | 
			
		||||
                                   </el-icon>
 | 
			
		||||
                                 </el-tooltip>
 | 
			
		||||
                               </div>
 | 
			
		||||
                             </template>
 | 
			
		||||
                           </el-form-item>
 | 
			
		||||
                         </div>
 | 
			
		||||
 | 
			
		||||
                         <div class="param-line">
 | 
			
		||||
                           <el-form-item label="放大倍数">
 | 
			
		||||
                             <template #default>
 | 
			
		||||
                               <div class="form-item-inner">
 | 
			
		||||
                                 <el-input v-model.number="params.hd_scale" size="small"/>
 | 
			
		||||
                                 <el-tooltip
 | 
			
		||||
                                     effect="light"
 | 
			
		||||
                                     content="随机数种子,相同的种子会得到相同的结果<br/> 设置为 -1 则每次随机生成种子"
 | 
			
		||||
                                     raw-content
 | 
			
		||||
                                     placement="right"
 | 
			
		||||
                                 >
 | 
			
		||||
                                   <el-icon>
 | 
			
		||||
                                     <InfoFilled/>
 | 
			
		||||
                                   </el-icon>
 | 
			
		||||
                                 </el-tooltip>
 | 
			
		||||
                               </div>
 | 
			
		||||
                             </template>
 | 
			
		||||
                           </el-form-item>
 | 
			
		||||
                         </div>
 | 
			
		||||
 | 
			
		||||
                         <div class="param-line">
 | 
			
		||||
                           <el-form-item label="迭代步数">
 | 
			
		||||
                             <template #default>
 | 
			
		||||
                               <div class="form-item-inner">
 | 
			
		||||
                                 <el-input v-model.number="params.hd_steps" size="small"/>
 | 
			
		||||
                                 <el-tooltip
 | 
			
		||||
                                     effect="light"
 | 
			
		||||
                                     content="重绘迭代步数,如果设置为0,则设置跟原图相同的迭代步数"
 | 
			
		||||
                                     raw-content
 | 
			
		||||
                                     placement="right"
 | 
			
		||||
                                 >
 | 
			
		||||
                                   <el-icon>
 | 
			
		||||
                                     <InfoFilled/>
 | 
			
		||||
                                   </el-icon>
 | 
			
		||||
                                 </el-tooltip>
 | 
			
		||||
                               </div>
 | 
			
		||||
                             </template>
 | 
			
		||||
                           </el-form-item>
 | 
			
		||||
                         </div>
 | 
			
		||||
                       </div>
 | 
			
		||||
            -->
 | 
			
		||||
            <div class="param-line" v-loading="loading" element-loading-background="rgba(122, 122, 122, 0.8)">
 | 
			
		||||
              <el-input
 | 
			
		||||
                  v-model="params.prompt"
 | 
			
		||||
                  :autosize="{ minRows: 4, maxRows: 6 }"
 | 
			
		||||
                  type="textarea"
 | 
			
		||||
                  ref="promptRef"
 | 
			
		||||
                  placeholder="正向提示词,例如:“一个中国女孩,黑色的长发,穿着职业女装走在深圳夜晚的街头,看着街上的车流”,输入后点击翻译或翻译并重写按钮后点击生成。"
 | 
			
		||||
              />
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div style="padding: 10px">
 | 
			
		||||
              <el-button type="primary" @click="translatePrompt" size="small">
 | 
			
		||||
                <el-icon style="margin-right: 6px;font-size: 18px;">
 | 
			
		||||
                  <Refresh/>
 | 
			
		||||
                </el-icon>
 | 
			
		||||
                翻译
 | 
			
		||||
              </el-button>
 | 
			
		||||
 | 
			
		||||
              <el-tooltip
 | 
			
		||||
                  class="box-item"
 | 
			
		||||
                  effect="dark"
 | 
			
		||||
                  raw-content
 | 
			
		||||
                  content="使用 AI 翻译并重写提示词,<br/>增加更多细节,风格等描述"
 | 
			
		||||
                  placement="top-end"
 | 
			
		||||
              >
 | 
			
		||||
                <el-button type="success" @click="rewritePrompt" size="small">
 | 
			
		||||
                  <el-icon style="margin-right: 6px;font-size: 18px;">
 | 
			
		||||
                    <Refresh/>
 | 
			
		||||
                  </el-icon>
 | 
			
		||||
                  翻译并重写
 | 
			
		||||
                </el-button>
 | 
			
		||||
              </el-tooltip>
 | 
			
		||||
              <el-tag type="success" style="margin-left: 12px;">绘图可用额度:{{ imgCalls }}</el-tag>
 | 
			
		||||
            </div>
 | 
			
		||||
            <!--
 | 
			
		||||
                        <div class="param-line pt">
 | 
			
		||||
                          <span>反向提示词:</span>
 | 
			
		||||
                          <el-tooltip
 | 
			
		||||
                              effect="light"
 | 
			
		||||
                              content="不希望出现的元素,下面给了默认的起手式"
 | 
			
		||||
                              placement="right"
 | 
			
		||||
                          >
 | 
			
		||||
                            <el-icon>
 | 
			
		||||
                              <InfoFilled/>
 | 
			
		||||
                            </el-icon>
 | 
			
		||||
                          </el-tooltip>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="param-line">
 | 
			
		||||
                          <el-input
 | 
			
		||||
                              v-model="params.negative_prompt"
 | 
			
		||||
                              :autosize="{ minRows: 4, maxRows: 6 }"
 | 
			
		||||
                              type="textarea"
 | 
			
		||||
                              placeholder="反向提示词"
 | 
			
		||||
                          />
 | 
			
		||||
                        </div>
 | 
			
		||||
            -->
 | 
			
		||||
          </el-form>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="submit-btn">
 | 
			
		||||
          <el-button color="#47fff1" :dark="false" round @click="generate">立即生成</el-button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="task-list-box">
 | 
			
		||||
          <div class="task-list-inner" :style="{ height: listBoxHeight + 'px' }">
 | 
			
		||||
            <h2>任务列表</h2>
 | 
			
		||||
            <div class="running-job-list">
 | 
			
		||||
              <ItemList :items="runningJobs" v-if="runningJobs.length > 0" width="240">
 | 
			
		||||
                <template #default="scope">
 | 
			
		||||
                  <div class="job-item">
 | 
			
		||||
                    <div v-if="scope.item.progress > 0" class="job-item-inner">
 | 
			
		||||
                      <el-image :src="scope.item['img_url']"
 | 
			
		||||
                                fit="cover"
 | 
			
		||||
                                loading="lazy">
 | 
			
		||||
                        <template #placeholder>
 | 
			
		||||
                          <div class="image-slot">
 | 
			
		||||
                            正在加载图片
 | 
			
		||||
                          </div>
 | 
			
		||||
                        </template>
 | 
			
		||||
 | 
			
		||||
                        <template #error>
 | 
			
		||||
                          <div class="image-slot">
 | 
			
		||||
                            <el-icon v-if="scope.item['img_url'] !== ''">
 | 
			
		||||
                              <Picture/>
 | 
			
		||||
                            </el-icon>
 | 
			
		||||
                          </div>
 | 
			
		||||
                        </template>
 | 
			
		||||
                      </el-image>
 | 
			
		||||
 | 
			
		||||
                      <div class="progress">
 | 
			
		||||
                        <el-progress type="circle" :percentage="scope.item.progress" :width="100" color="#47fff1"/>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <el-image fit="cover" v-else>
 | 
			
		||||
                      <template #error>
 | 
			
		||||
                        <div class="image-slot">
 | 
			
		||||
                          <i class="iconfont icon-quick-start"></i>
 | 
			
		||||
                          <span>任务正在排队中</span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                      </template>
 | 
			
		||||
                    </el-image>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </template>
 | 
			
		||||
              </ItemList>
 | 
			
		||||
              <el-empty :image-size="100" v-else/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h2>创作记录</h2>
 | 
			
		||||
            <div class="finish-job-list">
 | 
			
		||||
              <ItemList :items="finishedJobs" v-if="finishedJobs.length > 0" width="480" :gap="20">
 | 
			
		||||
                <template #default="scope">
 | 
			
		||||
                  <div class="job-item animate" @click="showTask(scope.item)">
 | 
			
		||||
                    <el-image
 | 
			
		||||
                        :src="scope.item['img_url']+'?imageView2/1/w/480/h/480/q/75'"
 | 
			
		||||
                        fit="cover"
 | 
			
		||||
                        loading="lazy">
 | 
			
		||||
                      <template #placeholder>
 | 
			
		||||
                        <div class="image-slot">
 | 
			
		||||
                          正在加载图片
 | 
			
		||||
                        </div>
 | 
			
		||||
                      </template>
 | 
			
		||||
 | 
			
		||||
                      <template #error>
 | 
			
		||||
                        <div class="image-slot">
 | 
			
		||||
                          <el-icon>
 | 
			
		||||
                            <Picture/>
 | 
			
		||||
                          </el-icon>
 | 
			
		||||
                        </div>
 | 
			
		||||
                      </template>
 | 
			
		||||
                    </el-image>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </template>
 | 
			
		||||
              </ItemList>
 | 
			
		||||
              <el-empty :image-size="100" v-else/>
 | 
			
		||||
            </div> <!-- end finish job list-->
 | 
			
		||||
          </div>
 | 
			
		||||
        </div><!-- end task list box -->
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <el-dialog v-model="showTaskDialog" title="绘画任务详情" :fullscreen="true">
 | 
			
		||||
      <el-row class="mobile-form-row">
 | 
			
		||||
        <el-col :span="24" class="mobile-form-col">
 | 
			
		||||
          <div class="img-container" :style="{maxHeight: fullImgHeight+'px'}">
 | 
			
		||||
            <el-image :src="item['img_url']" fit="contain"/>
 | 
			
		||||
          </div>
 | 
			
		||||
          <el-col :span="50">
 | 
			
		||||
            <div class="task-info">
 | 
			
		||||
              <div class="info-line">
 | 
			
		||||
                <el-divider>
 | 
			
		||||
                  正向提示词
 | 
			
		||||
                </el-divider>
 | 
			
		||||
                <div class="prompt">
 | 
			
		||||
                  <span>{{ item.prompt }}</span>
 | 
			
		||||
                  <el-icon class="copy-prompt" :data-clipboard-text="item.prompt">
 | 
			
		||||
                    <DocumentCopy/>
 | 
			
		||||
                  </el-icon>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="info-line">
 | 
			
		||||
                <el-divider>
 | 
			
		||||
                  反向提示词
 | 
			
		||||
                </el-divider>
 | 
			
		||||
                <div class="prompt">
 | 
			
		||||
                  <span>{{ item.params.negative_prompt }}</span>
 | 
			
		||||
                  <el-icon class="copy-prompt" :data-clipboard-text="item.params.negative_prompt">
 | 
			
		||||
                    <DocumentCopy/>
 | 
			
		||||
                  </el-icon>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="info-line">
 | 
			
		||||
                <div class="wrapper">
 | 
			
		||||
                  <label>采样方法:</label>
 | 
			
		||||
                  <div class="item-value">{{ item.params.sampler }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="info-line">
 | 
			
		||||
                <div class="wrapper">
 | 
			
		||||
                  <label>图片尺寸:</label>
 | 
			
		||||
                  <div class="item-value">{{ item.params.width }} x {{ item.params.height }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="info-line">
 | 
			
		||||
                <div class="wrapper">
 | 
			
		||||
                  <label>迭代步数:</label>
 | 
			
		||||
                  <div class="item-value">{{ item.params.steps }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="info-line">
 | 
			
		||||
                <div class="wrapper">
 | 
			
		||||
                  <label>引导系数:</label>
 | 
			
		||||
                  <div class="item-value">{{ item.params.cfg_scale }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="info-line">
 | 
			
		||||
                <div class="wrapper">
 | 
			
		||||
                  <label>随机因子:</label>
 | 
			
		||||
                  <div class="item-value">{{ item.params.seed }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div v-if="item.params.hd_fix">
 | 
			
		||||
                <el-divider>
 | 
			
		||||
                  高清修复
 | 
			
		||||
                </el-divider>
 | 
			
		||||
                <div class="info-line">
 | 
			
		||||
                  <div class="wrapper">
 | 
			
		||||
                    <label>重绘幅度:</label>
 | 
			
		||||
                    <div class="item-value">{{ item.params.hd_redraw_rate }}</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="info-line">
 | 
			
		||||
                  <div class="wrapper">
 | 
			
		||||
                    <label>放大算法:</label>
 | 
			
		||||
                    <div class="item-value">{{ item.params.hd_scale_alg }}</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="info-line">
 | 
			
		||||
                  <div class="wrapper">
 | 
			
		||||
                    <label>放大倍数:</label>
 | 
			
		||||
                    <div class="item-value">{{ item.params.hd_scale }}</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="info-line">
 | 
			
		||||
                  <div class="wrapper">
 | 
			
		||||
                    <label>迭代步数:</label>
 | 
			
		||||
                    <div class="item-value">{{ item.params.hd_steps }}</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="copy-params">
 | 
			
		||||
                <el-button type="primary" round @click="copyParams(item)">画一张同款的</el-button>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
          </el-col>
 | 
			
		||||
        </el-col>
 | 
			
		||||
      </el-row>
 | 
			
		||||
 | 
			
		||||
    </el-dialog>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {onMounted, ref} from "vue"
 | 
			
		||||
import {DocumentCopy, InfoFilled, Orange, Picture, Refresh} from "@element-plus/icons-vue";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import {ElMessage, ElNotification} from "element-plus";
 | 
			
		||||
import ItemList from "@/components/ItemList.vue";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import {getSessionId} from "@/store/session";
 | 
			
		||||
 | 
			
		||||
const listBoxHeight = ref(window.innerHeight - 40)
 | 
			
		||||
// const mjBoxHeight = ref(window.innerHeight - 150)
 | 
			
		||||
const fullImgHeight = ref(window.innerHeight - 60)
 | 
			
		||||
const showTaskDialog = ref(false)
 | 
			
		||||
const item = ref({})
 | 
			
		||||
const loading = ref(false)
 | 
			
		||||
 | 
			
		||||
window.onresize = () => {
 | 
			
		||||
  listBoxHeight.value = window.innerHeight - 40
 | 
			
		||||
//   mjBoxHeight.value = window.innerHeight - 150
 | 
			
		||||
}
 | 
			
		||||
const samplers = ["Euler a", "Euler", "DPM2 a Karras", "DPM++ 2S a Karras", "DPM++ 2M Karras", "DPM++ SDE Karras", "DPM2", "DPM2 a", "DPM++ 2S a", "DPM++ 2M", "DPM++ SDE", "DPM fast", "DPM adaptive",
 | 
			
		||||
  "LMS Karras", "DPM2 Karras", "DDIM", "PLMS", "UniPC", "LMS", "Heun",]
 | 
			
		||||
const scaleAlg = ["Latent", "ESRGAN_4x", "R-ESRGAN 4x+", "SwinIR_4x", "LDSR"]
 | 
			
		||||
const params = ref({
 | 
			
		||||
  width: 768,
 | 
			
		||||
  height: 1024,
 | 
			
		||||
  sampler: samplers[0],
 | 
			
		||||
  seed: -1,
 | 
			
		||||
  steps: 20,
 | 
			
		||||
  cfg_scale: 7,
 | 
			
		||||
  face_fix: false,
 | 
			
		||||
  hd_fix: false,
 | 
			
		||||
  hd_redraw_rate: 0.7,
 | 
			
		||||
  hd_scale: 2,
 | 
			
		||||
  hd_scale_alg: scaleAlg[0],
 | 
			
		||||
  hd_steps: 10,
 | 
			
		||||
  prompt: "",
 | 
			
		||||
  negative_prompt: "nsfw, paintings,low quality,easynegative,ng_deepnegative ,lowres,bad anatomy,bad hands,bad feet",
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const runningJobs = ref([])
 | 
			
		||||
const finishedJobs = ref([])
 | 
			
		||||
const router = useRouter()
 | 
			
		||||
// 检查是否有画同款的参数
 | 
			
		||||
const _params = router.currentRoute.value.params["copyParams"]
 | 
			
		||||
if (_params) {
 | 
			
		||||
  params.value = JSON.parse(_params)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const imgCalls = ref(0)
 | 
			
		||||
 | 
			
		||||
const rewritePrompt = () => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  httpPost("/api/prompt/rewrite", {"prompt": params.value.prompt}).then(res => {
 | 
			
		||||
    params.value.prompt = res.data
 | 
			
		||||
    loading.value = false
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
    ElMessage.error("翻译失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const translatePrompt = () => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  httpPost("/api/prompt/translate", {"prompt": params.value.prompt}).then(res => {
 | 
			
		||||
    params.value.prompt = res.data
 | 
			
		||||
    loading.value = false
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
    ElMessage.error("翻译失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  checkSession().then(user => {
 | 
			
		||||
    imgCalls.value = user['img_calls']
 | 
			
		||||
 | 
			
		||||
    fetchRunningJobs(user.id)
 | 
			
		||||
    fetchFinishJobs(user.id)
 | 
			
		||||
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    router.push('/login')
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const fetchRunningJobs = (userId) => {
 | 
			
		||||
    // 获取运行中的任务
 | 
			
		||||
    httpGet(`/api/sd/jobs?status=0&user_id=${userId}`).then(res => {
 | 
			
		||||
      const jobs = res.data
 | 
			
		||||
      const _jobs = []
 | 
			
		||||
      for (let i = 0; i < jobs.length; i++) {
 | 
			
		||||
        if (jobs[i].progress === -1) {
 | 
			
		||||
          ElNotification({
 | 
			
		||||
            title: '任务执行失败',
 | 
			
		||||
            message: "任务ID:" + jobs[i]['task_id'],
 | 
			
		||||
            type: 'error',
 | 
			
		||||
          })
 | 
			
		||||
          continue
 | 
			
		||||
        }
 | 
			
		||||
        _jobs.push(jobs[i])
 | 
			
		||||
      }
 | 
			
		||||
      runningJobs.value = _jobs
 | 
			
		||||
 | 
			
		||||
      setTimeout(() => fetchRunningJobs(userId), 5000)
 | 
			
		||||
    }).catch(e => {
 | 
			
		||||
      ElMessage.error("获取任务失败:" + e.message)
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 获取已完成的任务
 | 
			
		||||
  const fetchFinishJobs = (userId) => {
 | 
			
		||||
    httpGet(`/api/sd/jobs?status=1&user_id=${userId}`).then(res => {
 | 
			
		||||
      finishedJobs.value = res.data
 | 
			
		||||
      setTimeout(() => fetchFinishJobs(userId), 5000)
 | 
			
		||||
    }).catch(e => {
 | 
			
		||||
      ElMessage.error("获取任务失败:" + e.message)
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const clipboard = new Clipboard('.copy-prompt');
 | 
			
		||||
  clipboard.on('success', () => {
 | 
			
		||||
    ElMessage.success("复制成功!");
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  clipboard.on('error', () => {
 | 
			
		||||
    ElMessage.error('复制失败!');
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 创建绘图任务
 | 
			
		||||
const promptRef = ref(null)
 | 
			
		||||
const generate = () => {
 | 
			
		||||
  if (params.value.prompt === '') {
 | 
			
		||||
    promptRef.value.focus()
 | 
			
		||||
    return ElMessage.error("请输入绘画提示词!")
 | 
			
		||||
  }
 | 
			
		||||
  if (params.value.seed === '') {
 | 
			
		||||
    params.value.seed = -1
 | 
			
		||||
  }
 | 
			
		||||
  params.value.session_id = getSessionId()
 | 
			
		||||
  httpPost("/api/sd/image", params.value).then(() => {
 | 
			
		||||
    ElMessage.success("绘画任务推送成功,请耐心等待任务执行...")
 | 
			
		||||
    imgCalls.value -= 1
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("任务推送失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const showTask = (row) => {
 | 
			
		||||
  item.value = row
 | 
			
		||||
  showTaskDialog.value = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const copyParams = (row) => {
 | 
			
		||||
  params.value = row.params
 | 
			
		||||
  showTaskDialog.value = false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
@import "@/assets/css/mobile/image-sd.css"
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,152 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="page-invitation" :style="{height: listBoxHeight + 'px'}">
 | 
			
		||||
    <div class="inner">
 | 
			
		||||
      <div class="title" style="padding-top: 50px">会员推广计划</div>
 | 
			
		||||
      <div class="share-box">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          感谢您把此应用分享给您身边的朋友,分享成功注册后您将获得 <strong>{{ inviteChatCalls }}</strong>
 | 
			
		||||
          次对话额度以及
 | 
			
		||||
          <strong>{{ inviteImgCalls }}</strong> 次AI绘画额度作为奖励。
 | 
			
		||||
          你可以保存下面的二维码或者直接复制分享您的专属推广链接发送给微信好友。
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="invite-qrcode">
 | 
			
		||||
          <el-image :src="qrImg" fit="contain"/>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="invite-url">
 | 
			
		||||
          <span>{{ inviteURL }}</span>
 | 
			
		||||
          <el-button type="primary" plain class="copy-link" :data-clipboard-text="inviteURL">复制链接</el-button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="invite-stats">
 | 
			
		||||
        <el-row :gutter="20">
 | 
			
		||||
          <el-col :span="8">
 | 
			
		||||
            <div class="item-box yellow">
 | 
			
		||||
              <el-row :gutter="10">
 | 
			
		||||
                <!--                <el-col :span="10">-->
 | 
			
		||||
                <!--                  <div class="item-icon">-->
 | 
			
		||||
                <!--                    <i class="iconfont icon-role"></i>-->
 | 
			
		||||
                <!--                  </div>-->
 | 
			
		||||
                <!--                </el-col>-->
 | 
			
		||||
                <el-col :span="24">
 | 
			
		||||
                  <div class="item-info">
 | 
			
		||||
                    <div class="num">{{ hits }}</div>
 | 
			
		||||
                    <div class="text">点击量</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </el-col>
 | 
			
		||||
              </el-row>
 | 
			
		||||
            </div>
 | 
			
		||||
          </el-col>
 | 
			
		||||
          <el-col :span="8">
 | 
			
		||||
            <div class="item-box blue">
 | 
			
		||||
              <el-row :gutter="10">
 | 
			
		||||
                <!--                <el-col :span="10">-->
 | 
			
		||||
                <!--                  <div class="item-icon">-->
 | 
			
		||||
                <!--                    <i class="iconfont icon-order"></i>-->
 | 
			
		||||
                <!--                  </div>-->
 | 
			
		||||
                <!--                </el-col>-->
 | 
			
		||||
                <el-col :span="24">
 | 
			
		||||
                  <div class="item-info">
 | 
			
		||||
                    <div class="num">{{ regNum }}</div>
 | 
			
		||||
                    <div class="text">注册量</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </el-col>
 | 
			
		||||
              </el-row>
 | 
			
		||||
            </div>
 | 
			
		||||
          </el-col>
 | 
			
		||||
          <el-col :span="8">
 | 
			
		||||
            <div class="item-box green">
 | 
			
		||||
              <el-row :gutter="10">
 | 
			
		||||
                <!--                <el-col :span="10">-->
 | 
			
		||||
                <!--                  <div class="item-icon">-->
 | 
			
		||||
                <!--                    <i class="iconfont icon-chart"></i>-->
 | 
			
		||||
                <!--                  </div>-->
 | 
			
		||||
                <!--                </el-col>-->
 | 
			
		||||
                <el-col :span="24">
 | 
			
		||||
                  <div class="item-info">
 | 
			
		||||
                    <div class="num">{{ rate }}%</div>
 | 
			
		||||
                    <div class="text">转化率</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </el-col>
 | 
			
		||||
              </el-row>
 | 
			
		||||
            </div>
 | 
			
		||||
          </el-col>
 | 
			
		||||
        </el-row>
 | 
			
		||||
        <div class="title" style="padding: 20px">您推荐的用户</div>
 | 
			
		||||
        <div class="invite-logs" style="padding-bottom: 50px">
 | 
			
		||||
          <invite-list v-if="isLogin"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {onMounted, ref} from "vue"
 | 
			
		||||
import QRCode from "qrcode";
 | 
			
		||||
import {httpGet} from "@/utils/http";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
import InviteList from "@/components/InviteList.vue";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
 | 
			
		||||
const listBoxHeight = window.innerHeight
 | 
			
		||||
const inviteURL = ref("")
 | 
			
		||||
const qrImg = ref("")
 | 
			
		||||
const inviteChatCalls = ref(0)
 | 
			
		||||
const inviteImgCalls = ref(0)
 | 
			
		||||
const hits = ref(0)
 | 
			
		||||
const regNum = ref(0)
 | 
			
		||||
const rate = ref(0)
 | 
			
		||||
const router = useRouter()
 | 
			
		||||
const isLogin = ref(false)
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  checkSession().then(() => {
 | 
			
		||||
    isLogin.value = true
 | 
			
		||||
    httpGet("/api/invite/code").then(res => {
 | 
			
		||||
      const text = `${location.protocol}//${location.host}/register?invite_code=${res.data.code}`
 | 
			
		||||
      hits.value = res.data["hits"]
 | 
			
		||||
      regNum.value = res.data["reg_num"]
 | 
			
		||||
      if (hits.value > 0) {
 | 
			
		||||
        rate.value = ((regNum.value / hits.value) * 100).toFixed(2)
 | 
			
		||||
      }
 | 
			
		||||
      QRCode.toDataURL(text, {width: 300, height: 300, margin: 2}, (error, url) => {
 | 
			
		||||
        if (error) {
 | 
			
		||||
          console.error(error)
 | 
			
		||||
        } else {
 | 
			
		||||
          qrImg.value = url;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      inviteURL.value = text
 | 
			
		||||
    }).catch(e => {
 | 
			
		||||
      ElMessage.error("获取邀请码失败:" + e.message)
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    httpGet("/api/admin/config/get?key=system").then(res => {
 | 
			
		||||
      inviteChatCalls.value = res.data["invite_chat_calls"]
 | 
			
		||||
      inviteImgCalls.value = res.data["invite_img_calls"]
 | 
			
		||||
    }).catch(e => {
 | 
			
		||||
      ElMessage.error("获取系统配置失败:" + e.message)
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    router.push('/login')
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 复制链接
 | 
			
		||||
  const clipboard = new Clipboard('.copy-link');
 | 
			
		||||
  clipboard.on('success', () => {
 | 
			
		||||
    ElMessage.success('复制成功!');
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  clipboard.on('error', () => {
 | 
			
		||||
    ElMessage.error('复制失败!');
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
@import "@/assets/css/mobile/invitation.styl"
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,287 +1,128 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="app-background" theme="dark">
 | 
			
		||||
    <div class="member">
 | 
			
		||||
      <div class="title" style="padding-top: 50px">
 | 
			
		||||
        会员中心
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="inner" :style="{height: listBoxHeight + 'px'}">
 | 
			
		||||
        <div class="product-box">
 | 
			
		||||
          <ItemList :items="list" v-if="list.length > 0" :gap="30">
 | 
			
		||||
            <template #default="scope">
 | 
			
		||||
              <div class="product-item" :style="{width: scope.width+'px'}">
 | 
			
		||||
                <div class="image-container">
 | 
			
		||||
                  <el-image :src="vipImg" fit="cover"/>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="product-title">
 | 
			
		||||
                  <span class="name">{{ scope.item.name }}</span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="product-info">
 | 
			
		||||
                  <div class="info-line">
 | 
			
		||||
                    <span class="label">商品原价:</span>
 | 
			
		||||
                    <span class="price">¥{{ scope.item.price }}</span>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div class="info-line">
 | 
			
		||||
                    <span class="label">促销立减:</span>
 | 
			
		||||
                    <span class="price">¥{{ scope.item.discount }}</span>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div class="info-line">
 | 
			
		||||
                    <span class="label">有效期:</span>
 | 
			
		||||
                    <span class="expire" v-if="scope.item.days > 0">{{ scope.item.days }}天</span>
 | 
			
		||||
                    <span class="expire" v-else>当月有效</span>
 | 
			
		||||
                  </div>
 | 
			
		||||
  <div class="mobile-user-profile container">
 | 
			
		||||
    <van-nav-bar :title="title"/>
 | 
			
		||||
 | 
			
		||||
                  <div class="pay-way">
 | 
			
		||||
                    <el-button type="primary" @click="alipay(scope.item)" size="small" v-if="payWays['alipay']">
 | 
			
		||||
                      <i class="iconfont icon-alipay"></i> 支付宝
 | 
			
		||||
                    </el-button>
 | 
			
		||||
                    <el-button type="success" @click="huPiPay(scope.item)" size="small" v-if="payWays['hupi']">
 | 
			
		||||
                      <span v-if="payWays['hupi']['name'] === 'wechat'"><i
 | 
			
		||||
                          class="iconfont icon-wechat-pay"></i> 微信</span>
 | 
			
		||||
                      <span v-else><i class="iconfont icon-alipay"></i> 支付宝</span>
 | 
			
		||||
                    </el-button>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
    <div class="content">
 | 
			
		||||
      <van-form @submit="save">
 | 
			
		||||
        <van-cell-group inset v-model="form">
 | 
			
		||||
          <van-field
 | 
			
		||||
              v-model="form.mobile"
 | 
			
		||||
              name="手机号"
 | 
			
		||||
              label="手机号"
 | 
			
		||||
              readonly
 | 
			
		||||
              disabled
 | 
			
		||||
              placeholder="手机号"
 | 
			
		||||
          />
 | 
			
		||||
          <van-field label="头像">
 | 
			
		||||
            <template #input>
 | 
			
		||||
              <van-uploader v-model="fileList"
 | 
			
		||||
                            reupload max-count="1"
 | 
			
		||||
                            :deletable="false"
 | 
			
		||||
                            :after-read="afterRead"/>
 | 
			
		||||
            </template>
 | 
			
		||||
          </ItemList>
 | 
			
		||||
        </div>
 | 
			
		||||
        <el-row>
 | 
			
		||||
          <div class="user-profile">
 | 
			
		||||
            <user-profile/>
 | 
			
		||||
            <el-row class="user-opt" :gutter="20">
 | 
			
		||||
              <el-col :span="12">
 | 
			
		||||
                <el-button type="primary" @click="showPasswordDialog = true">修改密码</el-button>
 | 
			
		||||
              </el-col>
 | 
			
		||||
              <el-col :span="12">
 | 
			
		||||
                <el-button type="primary" v-if="enableReward" @click="showRewardDialog = true">加入众筹</el-button>
 | 
			
		||||
              </el-col>
 | 
			
		||||
              <el-col :span="12">
 | 
			
		||||
                <el-button type="primary" v-if="enableReward" @click="showRewardVerifyDialog = true">众筹核销
 | 
			
		||||
                </el-button>
 | 
			
		||||
              </el-col>
 | 
			
		||||
              <el-col :span="24" style="padding-bottom: 50px;">
 | 
			
		||||
                <el-button type="danger" round @click="logout">退出登录</el-button>
 | 
			
		||||
              </el-col>
 | 
			
		||||
            </el-row>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-row>
 | 
			
		||||
      </div>
 | 
			
		||||
      <login-dialog :show="showLoginDialog" @hide="showLoginDialog = false"/>
 | 
			
		||||
      <password-dialog v-if="isLogin" :show="showPasswordDialog" width="100%" @hide="showPasswordDialog = false"
 | 
			
		||||
                       @logout="logout"/>
 | 
			
		||||
      <reward-verify v-if="isLogin" :show="showRewardVerifyDialog" @hide="showRewardVerifyDialog = false"/>
 | 
			
		||||
      <el-dialog
 | 
			
		||||
          v-model="showRewardDialog"
 | 
			
		||||
          :show-close="true"
 | 
			
		||||
          width="100%"
 | 
			
		||||
          title="参与众筹"
 | 
			
		||||
      >
 | 
			
		||||
        <el-alert type="info" :closable="false">
 | 
			
		||||
          <div style="font-size: 14px">您好,众筹 9.9元,就可以兑换 100 次对话,以此来覆盖我们的 OpenAI
 | 
			
		||||
            账单和服务器的费用。<strong
 | 
			
		||||
                style="color: #f56c6c">由于本人没有开通微信支付,付款后请凭借转账单号,点击【众筹核销】按钮手动核销。</strong>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-alert>
 | 
			
		||||
        <div style="text-align: center;padding-top: 10px;">
 | 
			
		||||
          <el-image v-if="enableReward" :src="rewardImg"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </el-dialog>
 | 
			
		||||
          </van-field>
 | 
			
		||||
 | 
			
		||||
      <el-dialog
 | 
			
		||||
          v-model="showPayDialog"
 | 
			
		||||
          :close-on-click-modal="false"
 | 
			
		||||
          :show-close="true"
 | 
			
		||||
          :width="400"
 | 
			
		||||
          title="充值订单支付">
 | 
			
		||||
        <div class="pay-container">
 | 
			
		||||
          <div class="count-down">
 | 
			
		||||
            <count-down :second="orderTimeout" @timeout="refreshPayCode" ref="countDownRef"/>
 | 
			
		||||
          </div>
 | 
			
		||||
          <van-field label="剩余对话次数">
 | 
			
		||||
            <template #input>
 | 
			
		||||
              <van-tag type="primary">{{ form.calls }}</van-tag>
 | 
			
		||||
            </template>
 | 
			
		||||
          </van-field>
 | 
			
		||||
 | 
			
		||||
          <div class="pay-qrcode" v-loading="loading">
 | 
			
		||||
            <el-image :src="qrcode"/>
 | 
			
		||||
          </div>
 | 
			
		||||
          <van-field label="剩余绘图次数">
 | 
			
		||||
            <template #input>
 | 
			
		||||
              <van-tag type="primary">{{ form.img_calls }}</van-tag>
 | 
			
		||||
            </template>
 | 
			
		||||
          </van-field>
 | 
			
		||||
 | 
			
		||||
          <div class="tip success" v-if="text !== ''">
 | 
			
		||||
            <el-icon>
 | 
			
		||||
              <SuccessFilled/>
 | 
			
		||||
            </el-icon>
 | 
			
		||||
            <span class="text">{{ text }}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="tip" v-else>
 | 
			
		||||
            <el-icon>
 | 
			
		||||
              <InfoFilled/>
 | 
			
		||||
            </el-icon>
 | 
			
		||||
            <span class="text">请打开手机{{ payName }}扫码支付</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <van-field label="累计消耗tokens">
 | 
			
		||||
            <template #input>
 | 
			
		||||
              <van-tag type="primary">{{ form.total_tokens }}</van-tag>
 | 
			
		||||
            </template>
 | 
			
		||||
          </van-field>
 | 
			
		||||
        </van-cell-group>
 | 
			
		||||
        <div style="margin: 16px;">
 | 
			
		||||
          <van-button round block type="primary" native-type="submit">
 | 
			
		||||
            提交
 | 
			
		||||
          </van-button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </el-dialog>
 | 
			
		||||
      </van-form>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {onMounted, ref} from "vue"
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {onMounted, ref} from "vue";
 | 
			
		||||
import {showFailToast, showNotify, showSuccessToast} from "vant";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import ItemList from "@/components/ItemList.vue";
 | 
			
		||||
import {InfoFilled, SuccessFilled} from "@element-plus/icons-vue";
 | 
			
		||||
import LoginDialog from "@/components/LoginDialog.vue";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import UserProfile from "@/components/UserProfile.vue";
 | 
			
		||||
import PasswordDialog from "@/components/PasswordDialog.vue";
 | 
			
		||||
import RewardVerify from "@/components/RewardVerify.vue";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import {removeUserToken} from "@/store/session";
 | 
			
		||||
import CountDown from "@/components/CountDown.vue";
 | 
			
		||||
 | 
			
		||||
const listBoxHeight = window.innerHeight - 97
 | 
			
		||||
const list = ref([])
 | 
			
		||||
const showLoginDialog = ref(false)
 | 
			
		||||
const showPayDialog = ref(false)
 | 
			
		||||
const vipImg = ref("/images/vip.png")
 | 
			
		||||
const enableReward = ref(false) // 是否启用众筹功能
 | 
			
		||||
const rewardImg = ref('/images/reward.png')
 | 
			
		||||
const qrcode = ref("")
 | 
			
		||||
const showPasswordDialog = ref(false);
 | 
			
		||||
const showRewardDialog = ref(false);
 | 
			
		||||
const showRewardVerifyDialog = ref(false);
 | 
			
		||||
const text = ref("")
 | 
			
		||||
const user = ref(null)
 | 
			
		||||
const isLogin = ref(false)
 | 
			
		||||
const router = useRouter()
 | 
			
		||||
const curPayProduct = ref(null)
 | 
			
		||||
const activeOrderNo = ref("")
 | 
			
		||||
const countDownRef = ref(null)
 | 
			
		||||
const orderTimeout = ref(1800)
 | 
			
		||||
const loading = ref(true)
 | 
			
		||||
const orderPayInfoText = ref("")
 | 
			
		||||
 | 
			
		||||
const payWays = ref({})
 | 
			
		||||
const payName = ref("支付宝")
 | 
			
		||||
const curPay = ref("alipay") // 当前支付方式
 | 
			
		||||
import Compressor from 'compressorjs';
 | 
			
		||||
 | 
			
		||||
const title = ref('用户设置')
 | 
			
		||||
const form = ref({
 | 
			
		||||
  username: '',
 | 
			
		||||
  nickname: '',
 | 
			
		||||
  mobile: '',
 | 
			
		||||
  avatar: '',
 | 
			
		||||
  calls: 0,
 | 
			
		||||
  tokens: 0
 | 
			
		||||
})
 | 
			
		||||
const fileList = ref([
 | 
			
		||||
  {
 | 
			
		||||
    url: 'https://fastly.jsdelivr.net/npm/@vant/assets/leaf.jpeg',
 | 
			
		||||
    message: '上传中...',
 | 
			
		||||
  }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  checkSession().then(_user => {
 | 
			
		||||
    user.value = _user
 | 
			
		||||
    isLogin.value = true
 | 
			
		||||
    httpGet("/api/product/list").then((res) => {
 | 
			
		||||
      list.value = res.data
 | 
			
		||||
    }).catch(e => {
 | 
			
		||||
      ElMessage.error("获取产品套餐失败:" + e.message)
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    router.push("/login")
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  httpGet("/api/admin/config/get?key=system").then(res => {
 | 
			
		||||
    rewardImg.value = res.data['reward_img']
 | 
			
		||||
    enableReward.value = res.data['enabled_reward']
 | 
			
		||||
    orderPayInfoText.value = res.data['order_pay_info_text']
 | 
			
		||||
    if (res.data['order_pay_timeout'] > 0) {
 | 
			
		||||
      orderTimeout.value = res.data['order_pay_timeout']
 | 
			
		||||
    }
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("获取系统配置失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  httpGet("/api/payment/payWays").then(res => {
 | 
			
		||||
    payWays.value = res.data
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("获取支付方式失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
  httpGet('/api/user/profile').then(res => {
 | 
			
		||||
    form.value = res.data
 | 
			
		||||
    fileList.value[0].url = form.value.avatar
 | 
			
		||||
  }).catch((e) => {
 | 
			
		||||
    console.log(e.message)
 | 
			
		||||
    showFailToast('获取用户信息失败')
 | 
			
		||||
  });
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// refresh payment qrcode
 | 
			
		||||
const refreshPayCode = () => {
 | 
			
		||||
  if (curPay.value === 'alipay') {
 | 
			
		||||
    alipay()
 | 
			
		||||
  } else if (curPay.value === 'hupi') {
 | 
			
		||||
    huPiPay()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
const afterRead = (file) => {
 | 
			
		||||
  file.status = 'uploading';
 | 
			
		||||
  file.message = '上传中...';
 | 
			
		||||
  // 压缩图片并上传
 | 
			
		||||
  new Compressor(file.file, {
 | 
			
		||||
    quality: 0.6,
 | 
			
		||||
    success(result) {
 | 
			
		||||
      const formData = new FormData();
 | 
			
		||||
      formData.append('file', result, result.name);
 | 
			
		||||
      // 执行上传操作
 | 
			
		||||
      httpPost('/api/upload', formData).then((res) => {
 | 
			
		||||
        form.value.avatar = res.data
 | 
			
		||||
        file.status = 'success'
 | 
			
		||||
        showNotify({type: 'success', message: '上传成功'})
 | 
			
		||||
      }).catch((e) => {
 | 
			
		||||
        console.log(e.message)
 | 
			
		||||
        showNotify({type: 'danger', message: '上传失败'})
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    error(err) {
 | 
			
		||||
      console.log(err.message);
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const genPayQrcode = () => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  text.value = ""
 | 
			
		||||
  httpPost("/api/payment/qrcode", {
 | 
			
		||||
    pay_way: curPay.value,
 | 
			
		||||
    product_id: curPayProduct.value.id,
 | 
			
		||||
    user_id: user.value.id
 | 
			
		||||
  }).then(res => {
 | 
			
		||||
    showPayDialog.value = true
 | 
			
		||||
    qrcode.value = res.data['image']
 | 
			
		||||
    activeOrderNo.value = res.data['order_no']
 | 
			
		||||
    queryOrder(activeOrderNo.value)
 | 
			
		||||
    loading.value = false
 | 
			
		||||
    // 重置计数器
 | 
			
		||||
    if (countDownRef.value) {
 | 
			
		||||
      countDownRef.value.resetTimer()
 | 
			
		||||
    }
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("生成支付订单失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const alipay = (row) => {
 | 
			
		||||
  payName.value = "支付宝"
 | 
			
		||||
  curPay.value = "alipay"
 | 
			
		||||
  if (!user.value.id) {
 | 
			
		||||
    showLoginDialog.value = true
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  if (row) {
 | 
			
		||||
    curPayProduct.value = row
 | 
			
		||||
  }
 | 
			
		||||
  genPayQrcode()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 虎皮椒支付
 | 
			
		||||
const huPiPay = (row) => {
 | 
			
		||||
  payName.value = payWays.value["hupi"]["name"] === "wechat" ? '微信' : '支付宝'
 | 
			
		||||
  curPay.value = "hupi"
 | 
			
		||||
  if (!user.value.id) {
 | 
			
		||||
    showLoginDialog.value = true
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  if (row) {
 | 
			
		||||
    curPayProduct.value = row
 | 
			
		||||
  }
 | 
			
		||||
  genPayQrcode()
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const queryOrder = (orderNo) => {
 | 
			
		||||
  httpPost("/api/payment/query", {order_no: orderNo}).then(res => {
 | 
			
		||||
    if (res.data.status === 1) {
 | 
			
		||||
      text.value = "扫码成功,请在手机上进行支付!"
 | 
			
		||||
      queryOrder(orderNo)
 | 
			
		||||
    } else if (res.data.status === 2) {
 | 
			
		||||
      text.value = "支付成功,正在刷新页面"
 | 
			
		||||
      setTimeout(() => location.reload(), 500)
 | 
			
		||||
    } else {
 | 
			
		||||
      // 如果当前订单没有过期,继续等待订单的下一个状态
 | 
			
		||||
      if (activeOrderNo.value === orderNo) {
 | 
			
		||||
        queryOrder(orderNo)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("查询支付状态失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const logout = function () {
 | 
			
		||||
  httpGet('/api/user/logout').then(() => {
 | 
			
		||||
    removeUserToken();
 | 
			
		||||
    router.push('/login');
 | 
			
		||||
const save = () => {
 | 
			
		||||
  httpPost('/api/user/profile/update', form.value).then(() => {
 | 
			
		||||
    showSuccessToast('保存成功')
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    ElMessage.error('注销失败!');
 | 
			
		||||
    showFailToast('保存失败')
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
@import "@/assets/css/mobile/profile.styl"
 | 
			
		||||
</style>
 | 
			
		||||
.mobile-user-profile {
 | 
			
		||||
  .content {
 | 
			
		||||
    .van-field__label {
 | 
			
		||||
      width 100px
 | 
			
		||||
      text-align right
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
		Reference in New Issue
	
	Block a user