Browse Source

Merge branch 'master' into dev

# Conflicts:
#	components/multi-uploader.vue
#	pages/job/index.vue
bruce 5 years ago
parent
commit
1080bcbdc3
60 changed files with 15 additions and 10377 deletions
  1. 13 10
      components/multi-uploader.vue
  2. 0 72
      kaifain_v2/apis/apigateway.ts
  3. 0 13
      kaifain_v2/apis/case.ts
  4. 0 44
      kaifain_v2/apis/common.ts
  5. 0 25
      kaifain_v2/apis/contact.ts
  6. 0 81
      kaifain_v2/apis/solution.ts
  7. BIN
      kaifain_v2/assets/img/logo.png
  8. 0 116
      kaifain_v2/assets/styles/buefy.scss
  9. 0 208
      kaifain_v2/assets/styles/ext_aliyun_market.scss
  10. 0 1639
      kaifain_v2/assets/styles/ext_huawei_market.scss
  11. 0 1357
      kaifain_v2/assets/styles/ext_tencent_market.scss
  12. 0 40
      kaifain_v2/assets/styles/icon.scss
  13. 0 115
      kaifain_v2/assets/styles/main.scss
  14. 0 15
      kaifain_v2/assets/styles/vars.scss
  15. 0 215
      kaifain_v2/components/ApiDoc.vue
  16. 0 225
      kaifain_v2/components/ApiStatsChart.vue
  17. 0 163
      kaifain_v2/components/Carousel.vue
  18. 0 83
      kaifain_v2/components/CaseCell.vue
  19. 0 183
      kaifain_v2/components/CategoryNav.vue
  20. 0 86
      kaifain_v2/components/NavUserCell.vue
  21. 0 153
      kaifain_v2/components/Pagination.vue
  22. 0 158
      kaifain_v2/components/PanelApiCell.vue
  23. 0 28
      kaifain_v2/components/PanelApiEmpty.vue
  24. 0 112
      kaifain_v2/components/ParamsTable.vue
  25. 0 170
      kaifain_v2/components/SearchBox.vue
  26. 0 95
      kaifain_v2/components/SideSolutionCell.vue
  27. 0 193
      kaifain_v2/components/SolutionCell.vue
  28. 0 254
      kaifain_v2/components/Toolbar.vue
  29. 0 282
      kaifain_v2/components/Topnav.vue
  30. 0 493
      kaifain_v2/components/UserWidget.vue
  31. 0 8
      kaifain_v2/constant.ts
  32. 0 140
      kaifain_v2/helpers/apiDocHelper.ts
  33. 0 91
      kaifain_v2/helpers/seoHelper.ts
  34. 0 186
      kaifain_v2/mixins/solution.ts
  35. 0 25
      kaifain_v2/mixins/stats.js
  36. 0 66
      kaifain_v2/pages/dashboard/apis.vue
  37. 0 295
      kaifain_v2/pages/dashboard/home.vue
  38. 0 552
      kaifain_v2/pages/dashboard/inspector.vue
  39. 0 559
      kaifain_v2/pages/dashboard/layout.vue
  40. 0 240
      kaifain_v2/pages/dashboard/sms/templates.vue
  41. 0 269
      kaifain_v2/pages/index.vue
  42. 0 182
      kaifain_v2/pages/search.vue
  43. 0 664
      kaifain_v2/pages/solution.vue
  44. 0 4
      kaifain_v2/shims-vue.d.ts
  45. BIN
      kaifain_v2/static/favicon.ico
  46. 0 62
      kaifain_v2/store/apigateway.ts
  47. 0 80
      kaifain_v2/store/index.ts
  48. 0 5
      kaifain_v2/utils/bridge.ts
  49. 0 111
      kaifain_v2/utils/misc.ts
  50. 0 32
      kaifain_v2/utils/request.ts
  51. 0 61
      layouts/kaifain_v2.vue
  52. 0 2
      layouts/opacity_header_kf_tmp.vue
  53. 0 6
      nuxt.config.js
  54. 0 2
      package.json
  55. 1 12
      pages/kaifain/case/_tid.vue
  56. 1 13
      pages/kaifain/detail/_tid/index.vue
  57. 0 43
      plugins/seoRouter.js
  58. 0 6
      store/index.ts
  59. 0 2
      tsconfig.json
  60. 0 31
      yarn.lock

+ 13 - 10
components/multi-uploader.vue

@@ -4,6 +4,7 @@
       action="/upload_image"
       list-type="picture-card"
       :limit="9"
+      accept=".jpg,.jpeg,.png,.git,.JPG,.PNG,.JPEG,.GIF"
       ref="multiUploader"
       with-credentials
       :file-list="fileList"
@@ -17,7 +18,7 @@
     <el-dialog :visible.sync="dialogVisible">
       <img width="100%" :src="dialogImageUrl" alt/>
     </el-dialog>
-    <div slot="tip" class="el-upload__tip">最多添加9张作品图片2</div>
+    <div slot="tip" class="el-upload__tip">最多添加9张作品图片</div>
   </div>
 </template>
 
@@ -66,9 +67,13 @@ export default {
     beforeUpload(file) {
       console.log("beforeUpload", file);
       console.log("before", this.$refs.multiUploader);
-      let fileType = file.type ? file.type : file.raw.type;
+      let fileType = file.type ? file.type : (file.raw ? file.raw.type : "");
       if (fileType !== "image/png" && fileType !== "image/jpg" && fileType !== "image/jpeg" && fileType !== "image/gif") {
-        this.$message.error("文件类型不正确");
+        this.$message.error("请上传png,jpg格式的图片");
+        return false;
+      }
+      if (file.size / 1024 / 1024 > 2) {
+        this.$message.error("图片大小超过2M");
         return false;
       }
       return true;
@@ -85,13 +90,11 @@ export default {
       if (!response.error && response.filename) {
         console.log("上传成功");
         const list = [];
-        fileList.map(file => {
-          if (file.response.filename && !file.response.error) {
-            list.push({
-              name: file.name,
-              url: file.response ? file.response.filename : file.url
-            });
-          }
+        fileList.map(fileItem => {
+          list.push({
+            name: fileItem.name,
+            url: fileItem.response ? fileItem.response.filename : fileItem.url
+          });
         });
         this.fileList = list;
       } else {

+ 0 - 72
kaifain_v2/apis/apigateway.ts

@@ -1,72 +0,0 @@
-import request from '../utils/request'
-
-export const getUserInfo = async () => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getUserInfo'
-  })
-
-  return res.data.data
-}
-
-export const listUserApis = async () => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getUserQuotasList'
-  })
-
-  return res.data.data
-}
-
-export const pumpProxy = async (opts: {
-  query: any
-  body: any
-}) => {
-  const { query, body } = opts
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/pumpProxy',
-    query,
-    data: body,
-    dataType: 'json'
-  })
-
-  return res.data.data
-}
-
-export const listUserSMSTemplates = async () => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getUserModel',
-  })
-
-  return res.data.data
-}
-
-export const createSMSTemplate = async (params: {
-  name: string
-  signature: string
-  content: string
-}) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/createModel',
-    data: params
-  })
-
-  return res.data.data
-}
-
-export const deleteSMSTemplate = async (params: {
-  accountid: string
-  template_id: string
-}) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/deleteModel',
-    data: params
-  })
-
-  return res.data.data
-}
-

+ 0 - 13
kaifain_v2/apis/case.ts

@@ -1,13 +0,0 @@
-import request from '../utils/request'
-
-export const getCase = async (id: string) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifawu/get_public_case',
-    data: {
-      id
-    }
-  })
-
-  return res.data.data
-}

+ 0 - 44
kaifain_v2/apis/common.ts

@@ -1,44 +0,0 @@
-import request from '../utils/request'
-
-export const getInitParameters = async () => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getSearchCriteria'
-  })
-
-  return res.data.data
-}
-
-export const listBanners = async (type: number) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getBanner',
-    data: {
-      type
-    }
-  })
-
-  return res.data.data.list
-}
-
-export const listSearchKeywords = async () => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getKeyWord'
-  })
-
-  return res.data.data.list
-}
-
-export const listSearchHints = async (q: string, from: string) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/searchHint',
-    data: {
-      q,
-      from
-    }
-  })
-
-  return res.data.data
-}

+ 0 - 25
kaifain_v2/apis/contact.ts

@@ -1,25 +0,0 @@
-import request from '../utils/request'
-
-export const submitContact = async (opts: {
-  id?: string | number
-  name: string
-  phone: string
-  agent?: string
-  from: string
-}) => {
-  const { id, name, phone, agent, from } = opts
-  const res = await request({
-    method: 'POST',
-    url: '/api/user/create_not_login_user',
-    data: {
-      id,
-      providerID: id,
-      name,
-      phone,
-      agent,
-      from
-    }
-  })
-
-  return res.data
-}

+ 0 - 81
kaifain_v2/apis/solution.ts

@@ -1,81 +0,0 @@
-import request from '../utils/request'
-
-export const listSolutions = async (opts: {
-  page: number
-  size: number
-  uid?: string
-  city_id?: number | string
-  cat_id?: string
-  sort?: number
-  is_choice?: number
-  q?: string
-}) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getSolutionList',
-    data: opts
-  })
-
-  return res.data.data
-}
-
-export const getSolution = async (id: string, opts?: {
-  headers: any
-}) => {
-  const { headers } = opts || {}
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifawu/get_provider',
-    data: {
-      id
-    },
-    headers
-  })
-
-  return res.data.data
-}
-
-
-export const collectSolution = async (id: string) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/collection_center/create',
-    data: {
-      item_id: id,
-      type: 2
-    }
-  })
-
-  return res.data.data
-}
-
-export const listProviderSolution = async (params: {
-  uid: string
-  hash_id: string
-  page: number
-  size: number
-}, { headers }) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getSolutionByUid',
-    data: params,
-    headers
-  })
-
-  return res.data.data
-}
-
-export const listRelatedSolution = async (params: {
-  tags_ids: string // json array string
-  hash_id: string
-  size: number
-}, { headers }) => {
-  const res = await request({
-    method: 'POST',
-    url: '/api/kaifain/getRelevanceSolution',
-    data: params,
-    headers
-  })
-
-  return res.data.data
-}

BIN
kaifain_v2/assets/img/logo.png


+ 0 - 116
kaifain_v2/assets/styles/buefy.scss

@@ -1,116 +0,0 @@
-@import "./vars.scss";
-@import "~bulma/sass/utilities/_all";
-
-$fullhd: 1200px+(2 * $gap);
-$primary-invert: findColorInvert($primary);
-
-$dropdown-mobile-breakpoint: $tablet - 1;
-
-@import "~bulma";
-@import "~buefy/src/scss/buefy";
-
-html.has-navbar-fixed-top,
-body.has-navbar-fixed-top {
-  padding: 0 !important;
-}
-
-.container {
-  &.is-content {
-    max-width: 1000px;
-  }
-
-  &.is-wide {
-    max-width: 1080px;
-  }
-}
-
-.input {
-  &::-webkit-input-placeholder {
-    color: rgba(64, 64, 64, 0.6);
-  }
-}
-
-.button {
-  &.is-pure {
-    background: transparent;
-    border-color: transparent;
-  }
-}
-
-.tag {
-  &.is-choice {
-    background: #d1a26d;
-    color: #fff;
-  }
-
-  &.is-border {
-    color: #555;
-    background: #fafafa;
-    box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2);
-  }
-
-  &.is-link.is-light {
-    box-shadow: inset 0 0 1px rgba(33, 96, 196, 0.2);
-  }
-
-  &.is-success.is-light {
-    color: #288147;
-    box-shadow: inset 0 0 1px rgba(37, 121, 66, 0.2);
-  }
-
-  &:not(body).is-primary.is-light {
-    background: #eaf3ff;
-    color: $primary;
-
-    &.is-border {
-      background: rgba($primary, 0.06);
-      box-shadow: inset 0 0 1px rgba(36, 135, 255, 0.4);
-    }
-  }
-}
-
-.b-checkbox.checkbox {
-  .check {
-    box-shadow: none !important;
-  }
-}
-
-.pagination {
-  .pagination-previous,
-  .pagination-next,
-  .pagination-link {
-    min-width: 2rem;
-    height: 2rem;
-  }
-
-  .pagination-link {
-    background: #f4f4f5;
-    border-color: #f4f4f5;
-    font-weight: 500;
-
-    &.is-current {
-      background: $primary;
-      border-color: $primary;
-    }
-
-    &[disabled] {
-      pointer-events: none;
-    }
-  }
-}
-
-.modal-card {
-  background: #fff;
-  padding: 0.5rem;
-
-  .modal-card-head,
-  .modal-card-foot {
-    background: #fff;
-    border: 0;
-    border-radius: 0;
-  }
-
-  .modal-card-foot {
-    justify-content: flex-end;
-  }
-}

+ 0 - 208
kaifain_v2/assets/styles/ext_aliyun_market.scss

@@ -1,208 +0,0 @@
-.rich-text img {
-  max-width: 100%
-}
-
-.broderno h2 {
-  border-bottom: 0 !important
-}
-
-.param-table .title {
-  color: #000
-}
-
-.param-table .borderleft {
-  border-left: 0 !important
-}
-
-.param-table .borderright {
-  border-right: 0 !important
-}
-
-.param-table .pl20 {
-  padding-left: 20px
-}
-
-.r-product-detail .active-area {
-  position: relative;
-  padding: 20px 0
-}
-
-.r-product-detail .active-area img {
-  width: 100%
-}
-
-.r-product-detail .active-area a,
-.r-product-detail .active-area i {
-  position: absolute;
-  z-index: 10;
-  cursor: pointer
-}
-
-.r-product-detail .active-area a {
-  color: #fff;
-  border: 1px solid #fff;
-  line-height: 40px;
-  left: 400px;
-  top: 50px;
-  font-size: 16px;
-  padding: 0 20px
-}
-
-.r-product-detail .active-area i {
-  color: #69d3ff;
-  left: 400px;
-  top: 108px;
-  font-size: 14px
-}
-
-.r-product-detail .d-item h2 {
-  font-size: 14px;
-  font-weight: 700;
-  line-height: 32px;
-  margin-top: 30px;
-  margin-bottom: 10px;
-  border-bottom: 1px solid #eaeaea
-}
-
-.r-product-detail .param-table td {
-  border: 1px solid #eaeaea;
-  line-height: 32px;
-  height: 32px;
-  padding: 4px
-}
-
-.r-product-detail .status-list {
-  margin: 0;
-  padding: 0
-}
-
-.r-product-detail .status-list li {
-  width: 30%;
-  float: left;
-  margin-right: 3%;
-  background: #f5f5f5;
-  text-align: center
-}
-
-.r-product-detail .status-list li img {
-  max-width: 80%
-}
-
-.anli img {
-  max-width: 100% !important;
-  height: auto !important
-}
-
-.small-orange-font {
-  font-size: 18px;
-  color: #f60
-}
-
-.txt-right {
-  text-align: right
-}
-
-.nav-left h6 {
-  box-sizing: content-box !important
-}
-
-.ant-affix {
-  z-index: 2
-}
-
-.r-bg-gray {
-  background: #f5f5f5 !important
-}
-
-.ant-affix {
-  position: fixed
-}
-
-.r-bg-white {
-  background: #fff
-}
-
-.r-line {
-  height: 1px;
-  border-bottom: 1px solid #eee
-}
-
-.clear:after {
-  visibility: hidden;
-  display: block;
-  font-size: 0;
-  content: " ";
-  clear: both;
-  height: 0
-}
-
-.clear {
-  zoom: 1
-}
-
-.r-market-left {
-  width: 73%;
-  height: 100%;
-  position: relative;
-  z-index: 2;
-  overflow: hidden
-}
-
-.r-market-left .item-intro {
-  margin-top: 24px;
-  background: #fff;
-  overflow: hidden
-}
-
-.r-market-left .item-intro .box-icon {
-  padding: 0 40px;
-  margin-top: 20px
-}
-
-.r-market-left .item-intro .box-icon h5 {
-  color: #000;
-  font-size: 16px;
-  font-weight: 400;
-  height: 46px;
-  line-height: 46px;
-  border-bottom: 1px solid #eae8e8;
-  margin-bottom: 15px
-}
-
-.comment-page {
-  text-align: center;
-  padding: 20px 0
-}
-
-.r-market-right {
-  width: 25%
-}
-
-.r-fiexd {
-  position: fixed;
-  top: 110px
-}
-
-.r-ml10 {
-  margin-right: 10px !important
-}
-
-/* kaifain fix */
-
-.r-product-detail {
-  font-size: 13px;
-  color: #272727;
-  line-height: 1.35;
-
-  .slick-track {
-    width: auto !important;
-    transform: none !important;
-  }
-
-  .param-table {
-    .title {
-      font-size: inherit;
-      font-weight: inherit;
-    }
-  }
-}

File diff suppressed because it is too large
+ 0 - 1639
kaifain_v2/assets/styles/ext_huawei_market.scss


File diff suppressed because it is too large
+ 0 - 1357
kaifain_v2/assets/styles/ext_tencent_market.scss


+ 0 - 40
kaifain_v2/assets/styles/icon.scss

@@ -1,40 +0,0 @@
-@font-face {
-  font-family: 'progico';  /* project id 1895023 */
-  src: url('//at.alicdn.com/t/font_1895023_3n875b0emyx.eot');
-  src: url('//at.alicdn.com/t/font_1895023_3n875b0emyx.eot?#iefix') format('embedded-opentype'),
-  url('//at.alicdn.com/t/font_1895023_3n875b0emyx.woff2') format('woff2'),
-  url('//at.alicdn.com/t/font_1895023_3n875b0emyx.woff') format('woff'),
-  url('//at.alicdn.com/t/font_1895023_3n875b0emyx.ttf') format('truetype'),
-  url('//at.alicdn.com/t/font_1895023_3n875b0emyx.svg#progico') format('svg');
-}
-
-.progico {
-  font-family: "progico" !important;
-  font-style: normal;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-
-.progico-arrow:before {
-  content: "\e601";
-}
-
-.progico-plus-o:before {
-  content: "\e719";
-}
-
-.progico-api:before {
-  content: "\e738";
-}
-
-.progico-stats:before {
-  content: "\e662";
-}
-
-.progico-home:before {
-  content: "\e634";
-}
-
-.progico-debug:before {
-  content: "\e69a";
-}

+ 0 - 115
kaifain_v2/assets/styles/main.scss

@@ -1,115 +0,0 @@
-@import '@/kaifain_v2/assets/styles/icon.scss';
-
-.kaifain-view {
-  @import '@/kaifain_v2/assets/styles/buefy.scss';
-
-  font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, Helvetica, Segoe UI, Arial, Roboto, PingFang SC, Hiragino Sans GB, Microsoft Yahei, sans-serif;
-  background: #fff;
-
-  .container {
-    display: block;
-  }
-
-  .navbar {
-    &>.container {
-      display: flex;
-      flex-direction: row;
-
-      @media screen and (max-width: 1023px) {
-        display: block;
-      }
-    }
-  }
-
-  .main {
-    min-width: auto;
-    min-height: auto;
-    margin: 0;
-  }
-
-  .footer {
-    padding: 0 0 1rem;
-  }
-
-  .connectUs {
-    .toastBox .toastArea {
-      .title {
-        margin: 0;
-        width: auto;
-      }
-
-      .tips {
-        font-size: 12.5px;
-        color: #999;
-        margin: 4px 0 0;
-        width: auto;
-      }
-
-      .submitBtn {
-        margin-top: 24px;
-        width: auto;
-      }
-    }
-  }
-
-  .el-dropdown-menu {
-    padding: 6px 0;
-  }
-
-  .el-dropdown-menu__item {
-    padding: 0 18px 0 16px;
-  }
-
-  #proginn-footer {
-    .item-box {
-      width: 100%;
-    }
-  }
-
-  @media screen and (max-width: 767px) {
-    .container {
-      padding-left: 16px;
-      padding-right: 16px;
-    }
-
-    .columns {
-      margin: 0;
-    }
-
-    .solution-cell {
-      margin-left: -16px;
-      margin-right: -16px;
-    }
-  }
-}
-
-.scoped-view.kaifain {
-  #proginn-header,
-  .wx-header {
-    display: none !important;
-  }
-
-  #proginn-footer {
-    .item-box {
-      width: 100%;
-    }
-  }
-
-  .topArea {
-    padding-top: 80px;
-
-    @media screen and (min-width: 768px) {
-      .topContent {
-        padding-bottom: 32px;
-      }
-    }
-  }
-
-  .navbar {
-    &,
-    &>.container,
-    & .navbar-brand {
-      min-height: auto !important;
-    }
-  }
-}

+ 0 - 15
kaifain_v2/assets/styles/vars.scss

@@ -1,15 +0,0 @@
-$primary: #2487ff;
-$ink: #272727;
-
-$grey-lighter: #eaeaea;
-
-$tag-background-color: #f2f3f3;
-$tag-color: #3a3a3a;
-
-$checkbox-background-color: #fff;
-$checkbox-border-color: #cdcdcd;
-$checkbox-border-radius: 2px;
-$checkbox-border-width: 1px;
-
-$carousel-indicator-border: #fff;
-$carousel-indicator-color: #fff;

+ 0 - 215
kaifain_v2/components/ApiDoc.vue

@@ -1,215 +0,0 @@
-<template lang="pug">
-  .api-doc
-    .b-tabs(:class="{'is-vertical': !isMobile, 'is-mobile': isMobile}")
-      nav.tabs(v-show="routes.length > 1")
-        ul
-          li(
-            v-for="(route, idx) in routes"
-            :class="{'is-active': curIndex === idx}"
-            )
-            a(@click.stop="curIndex = idx") {{route.summary}}
-
-      section.tab-content
-        .tab-item.api-item(
-          v-for="(route, idx) in routes"
-          v-show="curIndex === idx"
-          )
-          h2 {{route.summary}}
-
-          .chunk.inline
-            .label 接口地址
-            .value
-              code {{route.url}}
-          .chunk.inline(v-if="route.produces && route.produces.length")
-            .label 支持格式
-            .value
-              template(v-for="(part, i) of route.produces")
-                code {{part}}
-                span(v-if="i < route.produces.length - 1") ,
-          .chunk.inline
-            .label 请求方法
-            .value
-              code {{route.method.toUpperCase()}}
-
-          .chunk(v-if="route.paramsMap.header")
-            .label 请求参数 (Headers)
-            .value
-              ParamsTable(:data="route.paramsMap.header")
-
-          .chunk(v-if="route.paramsMap.query")
-            .label 请求参数 (Query)
-            .value
-              ParamsTable(:data="route.paramsMap.query")
-
-          .chunk(v-if="route.paramsMap.body")
-            .label 请求参数 (Body)
-            .value
-              ParamsTable(:data="route.paramsMap.body")
-
-          .chunk(v-if="route.successResponse && route.successResponse.params")
-            .label 返回参数 (Body)
-            .value
-              ParamsTable(
-                :data="route.successResponse.params"
-                :show-required="false"
-                )
-
-          .chunk(v-if="route.successResponse && route.successResponse.example")
-            .label 请求返回示例
-            .value
-              pre
-                code(v-highlight) {{route.successResponse.example}}
-
-          .chunk(v-if="route.responses")
-            .label 错误码定义
-            .value
-              table.api-params-table
-                tbody
-                  tr
-                    th.center 错误码
-                    th 描述
-                  tr(v-for="(value, code) in route.responses")
-                    td.center {{code}}
-                    td
-                      pre.in-cell(v-if="isJsonString(value.description)")
-                        code {{formatJsonString(value.description)}}
-                      span(v-else) {{value.description}}
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import ParamsTable from './ParamsTable.vue'
-import { formatApiDocToRoutes, isJsonString, formatJsonString } from '../helpers/apiDocHelper'
-
-export default Vue.extend({
-  name: 'ApiDoc',
-  components: {
-    ParamsTable
-  },
-
-  props: {
-    data: {
-      type: Object,
-      default: () => {}
-    }
-  },
-
-  data() {
-    return {
-      curIndex: 0,
-      // @ts-ignore
-      isMobile: this.$deviceType.isMobile()
-    }
-  },
-
-  computed: {
-    routes(): any[] {
-      return formatApiDocToRoutes(this.data)
-    }
-  },
-
-  methods: {
-    isJsonString,
-    formatJsonString
-  }
-})
-</script>
-
-<style lang="scss">
-@import '../assets/styles/vars';
-
-.api-doc {
-  .b-tabs {
-    .tabs {
-      li {
-        font-size: 0.875rem;
-
-        // a {
-        //   // padding: 0.75rem 0 0.75em 1rem;
-        // }
-
-        &.is-active {
-          a {
-            color: $primary;
-            border-color: $primary;
-          }
-        }
-      }
-    }
-
-    .tab-content {
-      flex: 1;
-      overflow: hidden;
-    }
-
-    &.is-vertical {
-      .tabs {
-        margin-right: 1.5rem;
-        border-right: 1px solid #eaeaea;
-
-        a {
-          padding: 0.75rem 0 0.75em 1rem;
-          border: 0;
-        }
-      }
-    }
-
-    &.is-mobile {
-      .tab-content {
-        padding: 2em 0 0 0;
-      }
-    }
-  }
-
-  pre {
-    max-height: 240px;
-
-    &.in-cell {
-      max-width: calc(100vw - 10rem);
-      max-height: 112px;
-      padding: 1em;
-      background: #fafafa;
-
-      code {
-        background: inherit;
-        white-space: inherit;
-      }
-    }
-  }
-
-  h2 {
-    font-size: 1.25rem;
-    font-weight: 500;
-    margin-bottom: 2rem;
-  }
-
-  .chunk {
-    margin-bottom: 1rem;
-
-    .label {
-      font-size: 0.875rem;
-      font-weight: 500;
-      margin: 2rem 0 1rem;
-    }
-
-    .value {
-      font-size: 0.875rem;
-    }
-
-    &.inline {
-      margin-bottom: 0.5rem;
-
-      > * {
-        display: inline-block;
-      }
-
-      .label {
-        min-width: 64px;
-        margin: 0 4px 0 0;
-        font-weight: 400;
-      }
-    }
-  }
-}
-</style>

+ 0 - 225
kaifain_v2/components/ApiStatsChart.vue

@@ -1,225 +0,0 @@
-<template lang="pug">
-  .api-stats-chart(:id="`chart-${id}`")
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-const formatRow = (row: any, apiMap: any) => {
-  let {
-    api_id,
-    total,
-    called_at,
-    series
-  } = row
-
-  const api_name = apiMap[api_id] ? apiMap[api_id].title : api_id
-  const seriesList: any = []
-
-  total = Number(total)
-  called_at = Number(called_at)
-  series = total && JSON.parse(series) || null
-
-  if (series) {
-    for (const t in series) {
-      seriesList.push({
-        count: series[t],
-        time: Number(t) * 3600
-      })
-
-      seriesList.sort((a, b) => a.time - b.time)
-    }
-  }
-
-  return {
-    api_id,
-    api_name,
-    total,
-    called_at,
-    series: seriesList
-  }
-}
-
-const fillEmptyData = (output: any[], opts: {
-  api_name: string
-  start: number
-  end: number
-}) => {
-  let { api_name, start, end } = opts
-
-  while (start < end) {
-    output.push({
-      api_name,
-      count: 0,
-      time: new Date(start * 1000)
-    })
-
-    start += 3600
-  }
-}
-
-const genChartDataRow = (row: any, opts: {
-  from: number
-  to: number
-  apiMap: any
-}) => {
-  const output: any[] = []
-  const { from, to, apiMap } = opts
-  const {
-    api_name,
-    series
-  } = formatRow(row, apiMap)
-
-  let cursor = from
-
-  for (let i = 0, len = series.length; i < len; i++) {
-    const { count, time } = series[i]
-
-    // fill: before
-    if (cursor < time) {
-      fillEmptyData(output, {
-        api_name,
-        start: cursor,
-        end: time
-      })
-      cursor = time + 3600
-    }
-
-    output.push({
-      api_name,
-      count: count,
-      time: new Date(time * 1000)
-    })
-
-    // fill: after
-    if (i === len - 1 && time < to) {
-      fillEmptyData(output, {
-        api_name,
-        start: time + 3600,
-        end: to
-      })
-    }
-  }
-
-  return output
-}
-
-const genChartData = (params: {
-  list: any[]
-  from: number // s
-  to: number // s
-  apiMap: any
-}) => {
-  const { list, from, to, apiMap } = params
-  const output: any[] = []
-  const fromHourly = Math.ceil(from / 3600) * 3600
-
-  for (const row of list) {
-    output.push(...genChartDataRow(row, {
-      from: fromHourly,
-      to,
-      apiMap
-    }))
-  }
-
-  return output
-}
-
-export default Vue.extend({
-  name: 'ApiStatsChart',
-  props: {
-    list: {
-      type: Array,
-      default: () => []
-    },
-    from: {
-      type: Number
-    },
-    to: {
-      type: Number
-    }
-  },
-
-  data() {
-    return {
-      id: Math.random().toString(16).substr(2)
-    }
-  },
-
-  computed: {
-    isMobile(): boolean {
-      return process.client ? /(iPhone|Android)/i.test(navigator.userAgent) : false
-    }
-  },
-
-  methods: {
-    init() {
-      // @ts-ignore
-      const { id, list, from, to, isMobile } = this
-      // @ts-ignore
-      const { apiMap } = this.$store.state.kaifain || {}
-
-      // @ts-ignore
-      const chart = new G2.Chart({
-        container: `chart-${id}`,
-        forceFit: true,
-        height: isMobile ? 250 : 300,
-        padding: [ 32, 48, 52, 56],
-        data: genChartData({
-          list,
-          from,
-          to,
-          apiMap
-        }),
-        options: {
-          scales: {
-            time: {
-              type: 'time',
-              mask: 'MM-DD HH:mm',
-              tickInterval: isMobile ? 23 * 3600 * 1000 : null
-            },
-            count: {
-              min: 0,
-              minTickInterval: 1
-            }
-          },
-          geoms: [{
-            type: 'area',
-            position: 'time*count',
-            color: 'api_name',
-            opacity: 0.2
-          }, {
-            type: 'line',
-            position: 'time*count',
-            color: 'api_name'
-          }, {
-            type: 'point',
-            position: 'time*count',
-            color: 'api_name'
-          }],
-          axes: {
-            time: {
-              label: {
-                offset: 24
-              }
-            }
-          },
-          legends: {
-            api_name: {
-              position: 'top',
-              marker: 'circle'
-            }
-          }
-        }
-      })
-
-      chart.render()
-    }
-  },
-
-  mounted() {
-    // @ts-ignore
-    this.init()
-  }
-})
-</script>

+ 0 - 163
kaifain_v2/components/Carousel.vue

@@ -1,163 +0,0 @@
-<template lang="pug">
-  .carousel-wrapper#carousel
-    b-carousel(
-      v-model="curIndex"
-      :arrow="false"
-      :pause-hover="false"
-      :indicator="list.length > 1"
-      indicator-style="is-lines"
-      @change="onChange"
-      )
-      b-carousel-item(
-        v-for="(item, idx) in list"
-        :key="idx"
-        )
-        .pic(
-            :class="{clickable: item.jump_target && !item.button_text}"
-            :style="{backgroundImage: `url('${item.image_url}')`, backgroundColor: item.theme_color || 'transparent'}"
-            @click="onClick(item, false)"
-            )
-        .container.is-content(v-if="item.title || item.desc" :style="{textAlign: item.cont_position || 'left'}")
-          .text-content
-            .title {{item.title}}
-            .desc {{item.desc}}
-            .button.is-primary.is-inverted.is-outlined(
-              v-if="item.button_text"
-              @click.stop.prevent="onClick(item, true)"
-              ) {{item.button_text}}
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-const insertOrUpdateStyleTag = (item) => {
-  const id = `carousel-style`
-  const css = `.kaifain-view .carousel {background: ${item && item.theme_color || '#eee'}} .kaifain-view .carousel .carousel-item .text-content .button.is-primary:hover{color:${item && item.theme_color || '#20242d'}}`
-  let dom = document.getElementById(id)
-
-  if (!dom) {
-    const wrapper = document.querySelector('#carousel')
-
-    if (wrapper) {
-      dom = document.createElement('style')
-      dom.id = id
-      dom.innerHTML = css
-
-      wrapper.appendChild(dom)
-    }
-  } else {
-    dom.innerHTML = css
-  }
-}
-
-let lastClickedAt = 0
-
-export default Vue.extend({
-  name: 'Carousel',
-  components: {
-  },
-
-  props: {
-    list: Array
-  },
-
-  data() {
-    return {
-      curIndex: 1
-    }
-  },
-
-  methods: {
-    onClick(item: any, isButton: boolean) {
-      if (!isButton && item.button_text || !item.jump_target || Date.now() - lastClickedAt < 300) {
-        return false
-      }
-
-      const win = window.open(item.jump_target, '_blank')
-
-      if (win) {
-        lastClickedAt = Date.now()
-      }
-    },
-
-    onChange(idx: number) {
-      const item = this.list[idx]
-      item && insertOrUpdateStyleTag(item)
-    }
-  }
-
-})
-</script>
-
-<style lang="scss">
-.kaifain-view .carousel {
-  width: 100%;
-  height: 400px;
-  background: #eee;
-
-  .carousel-indicator {
-    margin-bottom: 16px;
-
-    .indicator-item {
-      .indicator-style.is-lines {
-        width: 48px;
-        height: 4px;
-        opacity: 0.2;
-      }
-
-      &.is-active .indicator-style {
-        opacity: 0.8;
-      }
-    }
-  }
-
-  .carousel-item {
-    width: 100%;
-    height: 400px;
-
-    .pic {
-      background-position: center center;
-      background-repeat: no-repeat;
-      background-size: auto 100%;
-      position: absolute;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-
-      &.clickable {
-        cursor: pointer;
-      }
-    }
-
-    .text-content {
-      position: relative;
-      z-index: 1;
-      margin-top: 140px;
-
-      > * {
-        color: #fff;
-      }
-
-      .desc {
-        opacity: 0.76;
-      }
-
-      .button {
-        margin-top: 44px;
-        min-width: 128px;
-        height: 2.572em;
-
-        &.is-primary {
-          font-size: 0.875rem;
-
-          &:hover {
-            color: #2487ff;
-          }
-        }
-      }
-    }
-  }
-}
-</style>

+ 0 - 83
kaifain_v2/components/CaseCell.vue

@@ -1,83 +0,0 @@
-<template lang="pug">
-  router-link.case-cell(:to="`/d/${data.hash_id}`")
-    .figure
-      img.logo(:src="data.logo")
-    .info
-      .title {{data.title}}
-      .subtitle 【{{solutionTitle}}】帮助【{{data.title}}】提供解决方案
-      .file
-        .icon
-        .filename {{data.title}}.pdf
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-export default Vue.extend({
-  name: 'CaseCell',
-
-  props: {
-    solutionTitle: String,
-    data: Object
-  }
-})
-</script>
-
-
-<style lang="less">
-.case-cell {
-  padding: 16px 8px;
-  display: flex;
-
-  &:hover {
-    text-decoration: none;
-  }
-
-  .figure {
-    .logo {
-      width: 112px;
-      height: 112px;
-      margin-right: 24px;
-    }
-  }
-
-  .info {
-    flex: 1;
-
-    .title {
-      font-size: 17px;
-      font-weight: 500;
-      margin: 0 !important;
-    }
-
-    .subtitle {
-      font-size: 14px;
-      margin: 10px 0 !important;
-    }
-  }
-
-  .file {
-    height: 26px;
-    display: flex;
-    align-items: center;
-    margin-top: 24px;
-
-    .icon {
-      width: 25px;
-      height: 25px;
-      background: url('~@/assets/img/kaifain/detail/icon_pdf@2x.png') no-repeat;
-      background-size: cover;
-    }
-
-    .filename {
-      margin-left: 7px;
-      height: 17px;
-      font-size: 12px;
-      font-weight: 600;
-      color: rgba(51, 51, 51, 1);
-      line-height: 17px;
-    }
-  }
-}
-</style>

+ 0 - 183
kaifain_v2/components/CategoryNav.vue

@@ -1,183 +0,0 @@
-<template lang="pug">
-  .category-nav.container.is-content
-    .columns
-      .column.label 解决方案
-      .column.tags
-        a.tag(
-          v-for="item in fullyClasses"
-          :class="topCatId === item.id ? ['is-primary', 'is-light'] : []"
-          :href="item.id !== '_' ? `/c/${item.id}` : '#'"
-          @click.stop.prevent="changeClass(item)"
-          ) {{item.name}}
-        .subnav(changeCategory
-          v-for="item in fullyClasses"
-          v-if="item.categories && item.categories.length"
-          v-show="topCatId === item.id"
-          )
-          a.tag.is-sub(
-            v-for="cat in item.categories"
-            :class="catId === cat.cat_id ? ['is-primary', 'is-light'] : []"
-            :href="cat.cat_id !== '_' ? `/c/${cat.cat_id}` : '#'"
-            @click.stop.prevent="changeCategory(item, cat)"
-            ) {{cat.alias || cat.name}}
-
-
-    .columns
-      .column.label 服务方式
-      .column.tags
-        #st-mark
-        .tag(
-          v-for="item in fullyServiceTypes"
-          :class="serviceType === item.hash_id ? ['is-primary', 'is-light'] : []"
-          @click="changeServiceType(item)"
-          ) {{item.alias || item.name}}
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-export default Vue.extend({
-  name: 'CategoryNav',
-  props: {
-    classes: {
-      type: Array,
-      default: () => [] as any[]
-    },
-    serviceTypes: {
-      type: Array,
-      default: () => [] as any[]
-    },
-    topCatId: {
-      type: String,
-      default: '_'
-    },
-    catId: {
-      type: String,
-      default: '_'
-    },
-    serviceType: {
-      type: String,
-      default: '_'
-    }
-  },
-
-  data() {
-    return {
-    }
-  },
-
-  computed: {
-    fullyClasses(): any[] {
-      return [{
-        id: '_',
-        name: '全部'
-      },
-      ...this.classes.map((row) => {
-        const { hash_id, name, categories } = row
-        const categoriesCopy = categories && categories.length ? [...categories] : []
-
-        if (categoriesCopy.length) {
-          categoriesCopy.unshift({
-            cat_id: '_',
-            name: '全部'
-          })
-        }
-
-        return {
-          id: hash_id,
-          name,
-          categories: categoriesCopy
-        }
-      })]
-    },
-
-    fullyServiceTypes(): any[] {
-      return [{
-        hash_id: '_',
-        name: '全部'
-      },
-      ...this.serviceTypes
-      ]
-    }
-  },
-
-  methods: {
-    changeClass(item) {
-      this.$emit('update:topCatId', item.id)
-      this.$emit('update:catId', '_')
-    },
-
-    changeCategory(topCat, cat) {
-      this.$emit('update:topCatId', topCat.id)
-      this.$emit('update:catId', cat.cat_id)
-    },
-
-    changeServiceType(item) {
-      this.$emit('update:serviceType', item.hash_id)
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.kaifain-view .category-nav {
-  padding: 2rem 0;
-
-  .column {
-    &.label {
-      font-size: 0.8125rem;
-      font-weight: 500;
-      flex: none;
-      margin: 4px 0 0;
-      user-select: none;
-    }
-  }
-
-  .tags {
-    &:last-child {
-      margin-bottom: -1rem;
-    }
-
-    > .tag {
-      margin-right: 0.75rem;
-    }
-  }
-
-  .tag {
-    font-size: 0.782rem;
-    min-width: 64px;
-    text-decoration: none !important;
-    cursor: pointer;
-    user-select: none;
-
-    &:not(.is-primary):hover {
-      background: #efeff0;
-    }
-
-    &.is-sub {
-      background: #f9f9fa;
-    }
-  }
-
-  .subnav {
-    background: #f9f9fa;
-    border-radius: 8px;
-    padding: 0.5rem 0.75rem 1px;
-    margin: 0.125rem 0 0.5rem;
-  }
-}
-
-.kaifain-view {
-  @media screen and (max-width: 767px) {
-    .category-nav {
-      padding: 0.75rem 0 1.5rem;
-
-      .column.label {
-        padding: 0.25rem 0.75rem 0.125rem;
-      }
-    }
-  }
-}
-</style>
-

+ 0 - 86
kaifain_v2/components/NavUserCell.vue

@@ -1,86 +0,0 @@
-<template lang="pug">
-  .nav-user-cell(:class="{clickable}")
-    a.nav-header(:href="clickable ? baseUrl+'/wo/work_todo' : '#'")
-      img.header-user(:src="userInfo.icon_url")
-      img.header-vip-icon(
-        v-if="userInfo.is_vip"
-        :src="baseUrl+`/Public/image/h5/vip_icon${vipImage}.png`"
-        alt="vip-icon"
-        )
-    span.nickname {{userInfo.nickname}}
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-export default Vue.extend({
-  props: {
-    userInfo: {
-      type: Object,
-      default: () => {}
-    },
-
-    clickable: {
-      type: Boolean,
-      default: true
-    }
-  },
-
-  computed: {
-    baseUrl(): string {
-      return this.$store.state.domainConfig.siteUrl
-    },
-
-    vipImage(): string {
-      switch (parseInt(this.userInfo.vip_type_id)) {
-        case 1:
-          return '_com'
-        case 3:
-          return '_premium'
-        default:
-          return ''
-      }
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-$imgWidth: 28px;
-
-.kaifain-view .nav-user-cell {
-  display: flex;
-  align-items: center;
-  padding-top: 1px;
-  font-size: 14px;
-  font-weight: 400;
-  padding: 0.5rem 0.75rem;
-  cursor: default;
-
-  &.clickable {
-    cursor: pointer;
-  }
-
-  .nav-header {
-    position: relative;
-    width: $imgWidth;
-    height: $imgWidth;
-    margin-right: 5px;
-  }
-  .nickname {
-    font-size: 14px;
-  }
-  .header-user {
-    width: $imgWidth;
-    height: $imgWidth;
-    border-radius: 20px;
-  }
-  .header-vip-icon {
-    position: absolute;
-    top: 16px;
-    left: 18px;
-    width: 16px;
-    height: 16px;
-  }
-}
-</style>

+ 0 - 153
kaifain_v2/components/Pagination.vue

@@ -1,153 +0,0 @@
-<template lang="pug">
-  .pagenav
-    b-pagination(
-      v-if="total > 0"
-      v-model="page"
-      :total="total"
-      :per-page="perPage"
-      :range-before="isMobile ? 1 : 3"
-      :range-after="isMobile ? 2 : 3"
-      order="is-centered"
-      aria-next-label="下一页"
-      aria-previous-label="上一页"
-      aria-page-label="页"
-      aria-current-label="当前页"
-      )
-      b-pagination-button(
-        slot-scope="props"
-        :page="props.page"
-        :id="`page${props.page.number}`"
-        tag="router-link"
-        :to="mergePagelink(props.page.number)"
-        ) {{props.page.number}}
-      b-pagination-button(
-        slot="previous"
-        slot-scope="props"
-        :page="props.page"
-        tag="router-link"
-        :to="props.page.number ? mergePagelink(props.page.number) : '#'"
-        )
-        i.progico.progico-arrow.left
-      b-pagination-button(
-        slot="next"
-        slot-scope="props"
-        :page="props.page"
-        tag="router-link"
-        :to="props.page.number <= totalPage ? mergePagelink(props.page.number) : '#'"
-        )
-        i.progico.progico-arrow
-
-    .hint-msg(v-else) 无相关解决方案
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import qs from 'qs'
-
-export default Vue.extend({
-  name: 'Pagination',
-  components: {
-  },
-
-  props: {
-    page: {
-      type: Number,
-      default: 1
-    },
-    querystring: {
-      type: String,
-      default: ''
-    },
-    list: Array,
-    total: {
-      type: Number,
-      default: 0
-    },
-    perPage: {
-      type: Number,
-      default: 10
-    },
-    path: {
-      type: String
-    },
-    mode: {
-      type: String,
-      default: 'params'
-    }
-  },
-
-  data() {
-    return {
-      // @ts-ignore
-      isMobile: this.$deviceType.isMobile()
-    }
-  },
-
-  computed: {
-    totalPage(): number {
-      return Math.ceil(this.total / this.perPage)
-    }
-  },
-
-  methods: {
-    mergePagelink(page) {
-      let path = this.path || this.$route.path
-      const query = Object.assign({}, this.$route.query)
-
-      if (this.mode === 'params') {
-        path += page
-      }
-      else {
-        query.page = page
-      }
-
-      return `${path}${Object.keys(query).length ? '?' + qs.stringify(query) : ''}`
-
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.kaifain-view {
-  .pagenav {
-    .hint-msg {
-      text-align: center;
-      font-size: 0.875rem;
-      color: #999;
-      padding: 2rem;
-    }
-  }
-
-  .pagination {
-    max-width: 800px;
-    margin: 0 auto;
-    justify-content: center;
-    padding: 3rem 0;
-
-    .pagination-previous {
-      flex-grow: unset;
-      order: 1;
-    }
-
-    .pagination-list {
-      flex-grow: unset;
-      order: 2;
-    }
-
-    .pagination-next {
-      flex-grow: unset;
-      order: 3;
-    }
-
-    .progico-arrow {
-      font-size: 0.75em;
-
-      &.left {
-        transform: rotate(180deg);
-      }
-    }
-  }
-}
-</style>

+ 0 - 158
kaifain_v2/components/PanelApiCell.vue

@@ -1,158 +0,0 @@
-<template lang="pug">
-  .panel-api-cell
-    template(v-if="!isSkeleton")
-      .figure
-        img.icon(:src="data.images")
-      .info
-        a.title(
-          :href="`/s/${data.hash_id}?from=brd`"
-          target="_blank"
-          @click="goSolutionPage($event, data)"
-          ) {{data.title}}
-        .metas
-          span 总次数 {{data.quota.toLocaleString()}}
-          span 剩余次数 {{Math.max(data.quota - data.usage, 0).toLocaleString()}}
-        .actions
-          //- router-link.button.is-small(:to="`/dashboard/stats?api_id=${data.api_id}`") 统计
-          router-link.button.is-small(:to="`/dashboard/inspector?api_id=${data.api_id}`") 调试
-          a.button.is-small(
-            :href="`/s/${data.hash_id}?from=brd#apidoc`"
-            target="_blank"
-            @click="goSolutionPage($event, data)"
-            ) 文档
-          a.button.is-small(
-            :href="`/s/${data.hash_id}?from=brd`"
-            target="_blank"
-            @click="goSolutionPage($event, data)"
-            ) 加购
-          router-link.button.is-small.is-link.is-light(
-            v-if="data.title === '短信'"
-            :to="`/dashboard/sms/templates`"
-            ) 模板管理
-
-    //- skeleton
-    template(v-else)
-      .figure
-        b-skeleton(
-          width="48px"
-          height="48px"
-          )
-      .info
-        b-skeleton(width="15%")
-        b-skeleton(width="30%")
-        b-skeleton(width="50%")
-
-</template>
-
-
-<script lang="ts">
-import Vue from 'vue'
-import bridge from '../utils/bridge'
-import { KAIFAIN_MOB_SITE } from '../constant'
-
-export default Vue.extend({
-  name: 'PanelApiCell',
-
-  props: {
-    data: {
-      type: Object,
-      default: () => {}
-    },
-
-    isSkeleton: {
-      type: Boolean,
-      default: false
-    }
-  },
-
-  methods: {
-    goSolutionPage(e: Event, data) {
-      if (process.client && bridge.isInApp) {
-        e.preventDefault()
-        e.stopPropagation()
-
-        bridge.load(`${KAIFAIN_MOB_SITE}/s/${data.hash_id}?from=brd`)
-        return
-      }
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.kaifain-view .panel-api-cell {
-  display: flex;
-  padding: 1.5em 0;
-  border-bottom: 1px solid #eee;
-
-  .figure {
-    margin: 2px 2em 0 0.5em;
-    flex: none;
-  }
-
-  .icon {
-    width: 3rem;
-    height: 3rem;
-    border-radius: 10px;
-  }
-
-  .info {
-    flex: 1;
-  }
-
-  .title {
-    color: #272727;
-    font-size: 1.0625em;
-    margin-bottom: 0.75em;
-    display: inline-block;
-  }
-
-  .metas {
-    color: #777;
-    font-size: 0.875em;
-    margin-bottom: 0.5em;
-
-    > * {
-      margin: 0 1em 0.5em 0;
-      display: inline-block;
-    }
-
-    span:last-child {
-      margin-right: 0;
-    }
-  }
-
-  .actions {
-    margin-bottom: -0.25em;
-  }
-
-  .button {
-    margin: 0 0.75em 0.75em 0;
-    height: 2.25em;
-  }
-
-  &:last-child {
-    border: 0;
-  }
-
-  @media screen and (max-width: 768px) {
-    font-size: 0.875em;
-  }
-
-  @media screen and (max-width: 480px) {
-    .figure {
-      margin-left: 0;
-      margin-right: 1.25em;
-    }
-
-    .icon {
-      width: 2.5rem;
-      height: 2.5rem;
-    }
-
-    .actions {
-      margin: 1em -1em 0 -4.25em;
-    }
-  }
-}
-</style>

+ 0 - 28
kaifain_v2/components/PanelApiEmpty.vue

@@ -1,28 +0,0 @@
-<template lang="pug">
-  .empty
-    p
-      | {{message}}
-      a.is-link(@click="goApiLandingPage") 前往购买
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import { BINSTD_PID } from '../constant'
-
-export default Vue.extend({
-  name: 'PanelApiEmpty',
-
-  props: {
-    message: {
-      type: String,
-      default: '还没有购入 API 接口,'
-    }
-  },
-
-  methods: {
-    goApiLandingPage() {
-      location.href = `/?pid=${BINSTD_PID}`
-    }
-  }
-})
-</script>

+ 0 - 112
kaifain_v2/components/ParamsTable.vue

@@ -1,112 +0,0 @@
-<template lang="pug">
-  table.api-params-table
-    tbody
-      tr
-        th 参数名
-        th(v-if="showType") 类型
-        th(v-if="showRequired") 是否必须
-        th 描述
-      tr(
-        v-for="item in flatRows"
-        :class="item.depth ? `depth-${item.depth}` : ''"
-        )
-        td
-          .sub-symbol(v-if="item.depth > 0")
-            span └
-            span.dash(v-for="idx in item.depth - 1") ─
-          span.key {{item.name}}
-        td(v-if="showType")
-          code(v-if="item.type" :style="{whiteSpace: item.type.length > 7 ? 'normal' : 'nowrap'}") {{item.type}}
-          code(v-if="item.items && item.items.type !== 'object'") <{{item.items.type}}>
-        td(v-if="showRequired") {{item.required ? '是' : '否'}}
-        td {{item.description}}
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-const pushRow = (array: any[], row: any, depth = 0) => {
-  row.depth = depth
-  array.push(row)
-
-  if (row.children) {
-    for (const child of row.children) {
-      pushRow(array, child, depth + 1)
-    }
-  }
-}
-
-export default Vue.extend({
-  name: 'ParamsTable',
-  props: {
-    data: {
-      type: Array,
-      default: () => []
-    },
-    showType: {
-      type: Boolean,
-      default: true
-    },
-    showRequired: {
-      type: Boolean,
-      default: true
-    }
-  },
-
-  computed: {
-    flatRows(): any[] {
-      const ret: any[] = []
-
-      // @ts-ignore
-      for (const row of this.data) {
-        pushRow(ret, row)
-      }
-
-      return ret
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.api-params-table {
-  min-width: 100%;
-  border: 1px solid #eaeaea;
-  border-collapse: collapse;
-  border-spacing: 0;
-  text-align: left;
-
-  th,
-  td {
-    padding: 8px 12px;
-    border-bottom: 1px solid #eaeaea;
-  }
-
-  th {
-    background: #f5f6f6;
-    font-weight: 500;
-  }
-
-  td {
-    word-break: break-word;
-  }
-
-  th,
-  code,
-  .key {
-    white-space: nowrap;
-  }
-
-  .center {
-    text-align: center;
-  }
-
-  .sub-symbol {
-    opacity: 0.3;
-    font-size: 0.75em;
-    margin: 0 6px 0 -2px;
-    display: inline;
-  }
-}
-</style>

+ 0 - 170
kaifain_v2/components/SearchBox.vue

@@ -1,170 +0,0 @@
-<template lang="pug">
-  .search-section
-    .container.is-content
-      .level.search-box
-        .level-item
-          input.input(
-            v-model="q"
-            type="text"
-            placeholder="输入行业领域、业务场景或服务类型等,搜索解决方案"
-            @keyup.enter.prevent="goSearch"
-            )
-          .button.is-primary(@click="goSearch") 搜索
-
-      .level.extension
-        .level-left
-          .hot-keywords
-            router-link.item(
-              v-for="item in hotKeywords"
-              :key="item.id"
-              :to="`/search?q=${item.word}&from=hkw`"
-              ) {{item.alias || item.word}}
-        .level-right.action
-          .button.is-pure.is-rounded(@click="onPublishClick")
-            i.progico.progico-plus-o
-            span 发布定制需求
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-export default Vue.extend({
-  name: 'SearchBox',
-  props: {
-    hotKeywords: {
-      type: Array,
-      default: () => []
-    }
-  },
-
-  data() {
-    return {
-      q: ''
-    }
-  },
-
-  methods: {
-    goSearch() {
-      if (!this.q) {
-        return
-      }
-      this.$router.push(`/search?q=${this.q}&from=sbl`)
-    },
-
-    onPublishClick() {
-      this.$emit('publish-click')
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.kaifain-view .search-section {
-  background: #20242d;
-  padding: 44px 0 8px;
-
-  .level {
-    margin: 0;
-  }
-
-  .search-box {
-    .input,
-    .button {
-      height: 3.25rem;
-    }
-
-    .input {
-      font-size: 0.875rem;
-      padding-left: 1.5rem;
-      padding-right: 1.5rem;
-      border-radius: 4px 0 0 4px;
-      margin: 0;
-    }
-
-    .button {
-      width: 116px;
-      font-weight: 500;
-      letter-spacing: 1px;
-      border-radius: 0 4px 4px 0;
-      flex: none;
-    }
-  }
-
-  .extension {
-    padding: 0.75rem 0;
-  }
-
-  .hot-keywords {
-    .item {
-      font-size: 0.8125rem;
-      color: rgba(255, 255, 255, 0.92);
-      margin-right: 22px;
-      display: inline-block;
-      cursor: pointer;
-
-      &::before {
-        content: '';
-        background: rgba(255, 255, 255, 0.3);
-        width: 5px;
-        height: 5px;
-        border-radius: 3px;
-        display: inline-block;
-        vertical-align: top;
-        margin: 7px 6px 0 0;
-      }
-
-      &:hover {
-        color: #fff;
-        font-weight: 500;
-      }
-    }
-  }
-
-  .action {
-    .button {
-      color: #fff;
-      font-size: 0.8125rem;
-      font-weight: 500;
-      text-align: right;
-      letter-spacing: 0.02em;
-      padding-left: 0.75em;
-      padding-right: 0.75em;
-
-      .progico-plus-o {
-        margin-right: 5px;
-      }
-
-      &:hover {
-        background: rgba(255,255,255, 0.1);
-      }
-    }
-  }
-}
-
-.kaifain-view {
-  @media screen and (max-width: 767px) {
-    .search-section {
-      padding: 44px 0 12px;
-
-      .level-right.action {
-        display: none;
-      }
-
-      .search-box {
-        .input,
-        .button {
-          height: 2.75rem;
-        }
-
-        .button {
-          width: 72px;
-        }
-      }
-
-      .extension {
-        padding: 1rem 0;
-      }
-    }
-  }
-}
-</style>

+ 0 - 95
kaifain_v2/components/SideSolutionCell.vue

@@ -1,95 +0,0 @@
-<template lang="pug">
-  a.side-solution-cell(:href="`/s/${data.hash_id}`")
-    .cover
-      img(:src="data.images")
-    .title {{data.title}}
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-export default Vue.extend({
-  props: {
-    data: Object
-  }
-})
-</script>
-
-<style lang="scss">
-@import '../assets/styles/vars';
-
-.side-solution-cell {
-  margin: 0.5rem 0;
-  padding: 0.375rem 0;
-  display: flex;
-  position: relative;
-
-  &::after {
-    content: '';
-    width: 100%;
-    width: calc(100% - 62px);
-    height: 1px;
-    background: #ddd;
-    display: block;
-    position: absolute;
-    bottom: 0;
-    right: 0;
-    transform: scale(1, 0.5);
-  }
-
-  .cover {
-    width: 48px;
-    height: 48px;
-    margin: 1px 16px 1px 1px;
-    overflow: hidden;
-    border-radius: 10px;
-    position: relative;
-    flex: none;
-
-    img {
-      width: 100%;
-      height: 100%;
-      object-fit: cover;
-      display: block;
-    }
-
-    &::after {
-      content: '';
-      width: 100%;
-      height: 100%;
-      position: absolute;
-      top: 0;
-      left: 0;
-      border: 1px solid rgba(0,0,0,0.08);
-      border-radius: 10px;
-    }
-  }
-
-  .title {
-    font-size: 0.875rem;
-    font-weight: 400;
-    margin: 0.375rem 0;
-    line-height: 1.35;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    -webkit-box-orient: vertical;
-    display: -webkit-box;
-    -webkit-line-clamp: 2;
-    max-height: 2.362rem;
-  }
-
-  &:hover {
-    text-decoration: none;
-
-    .title {
-      color: $primary;
-    }
-  }
-
-  &:last-child {
-    &::after {
-      display: none;
-    }
-  }
-}
-</style>

+ 0 - 193
kaifain_v2/components/SolutionCell.vue

@@ -1,193 +0,0 @@
-<template lang="pug">
-  .solution-cell
-    a.cell-block(:href="`/s/${data.hash_id}`")
-      .figure
-        img.cover(
-          :src="data.images"
-        )
-
-      .info
-        .title
-          span {{data.title}}
-          .tag.is-choice(v-if="data.is_choice == 1") 优选
-          .tag.is-success.is-light(v-if="data.type === 'gateway'") HTTPS
-        .desc {{data.description}}
-        .provider
-          span 服务商: {{data.company_name}}
-          span(v-if="data.type === 'gateway'") 交付方式:API接口 (即买即用)
-
-      .price
-        div(v-if="data.is_signing == 1 && data.min_price != null")
-          .free(v-if="Number(data.min_price) == 0")
-            .price-tag 0元用
-            .small 限时免费
-          .price-tag(v-else)
-            span ¥{{Number((data.min_price / 100).toFixed(2))}}
-        .price-tag(v-else) 咨询
-
-    .tags
-      .tag.is-primary.is-light.is-border(v-for="name in uniqueCatNames") {{name}}
-      .tag.is-border(
-        v-for="item in data.tags"
-        v-if="!uniqueCatNames.find((name) => name === item.name)"
-        ) {{item.name}}
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-export default Vue.extend({
-  name: 'SolutionCell',
-  components: {
-  },
-
-  props: {
-    data: Object,
-    default: () => {}
-  },
-
-  computed: {
-    uniqueCatNames(): any {
-      return this.data.cats && [...new Set(this.data.cats.map((item) => item.name))] || []
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-@import '../assets/styles/vars';
-
-.kaifain-view .solution-cell {
-  padding: 24px 32px 20px;
-  border-bottom: 1px solid #eee;
-
-  .figure {
-    margin: 4px 30px 0 0;
-    flex: none;
-
-    .cover {
-      width: 64px;
-      height: 64px;
-      display: block;
-      object-fit: cover;
-    }
-  }
-
-  .info {
-    font-size: 12px;
-    flex: 1;
-    overflow: hidden;
-  }
-
-  .price {
-    display: flex;
-    align-items: center;
-    padding: 1.5rem 1rem 0 5rem;
-
-    .price-tag {
-      color: $primary;
-      font-size: 1.125rem;
-      font-weight: 500;
-    }
-
-    .free {
-      display: flex;
-      flex-direction: column;
-      justify-content: center;
-      align-items: center;
-
-      .small {
-        font-size: 11px;
-        font-weight: 300;
-        color: #999;
-        margin-top: 6px;
-      }
-    }
-  }
-
-  .tag {
-    font-size: 0.6875rem;
-    cursor: default;
-  }
-
-  a.tag {
-    cursor: pointer;
-    text-decoration: none;
-  }
-
-  .title {
-    font-size: 1rem;
-    font-weight: 500;
-    color: $ink;
-    margin-bottom: 8px;
-
-    .tag {
-      margin-left: 8px;
-      height: 1.6em;
-      padding-left: 0.5em;
-      padding-right: 0.5em;
-    }
-  }
-
-  .desc,
-  .provider {
-    white-space: nowrap;
-    word-break: break-all;
-    text-overflow: ellipsis;
-    overflow: hidden;
-  }
-
-  .desc {
-    color: lighten($ink, 10%);
-    margin: 10px 0 12px;
-    font-size: 0.8125rem;
-  }
-
-  .provider {
-    color: lighten($ink, 42%);
-
-    span {
-      margin-right: 1.75rem;
-
-      &:last-child {
-        margin-right: 0;
-      }
-    }
-  }
-
-  .tags {
-    padding: 2px 0;
-    margin: 10px 0 0 94px;
-  }
-
-  &.card {
-    background: #fff;
-    margin: 10px 12px;
-    border-radius: 12px;
-  }
-
-  .cell-block {
-    display: flex;
-
-    &:hover {
-      .title span {
-        color: $primary;
-      }
-    }
-  }
-
-  @media screen and (max-width: 768px) {
-    padding-left: 24px;
-
-    .figure {
-      margin-right: 24px;
-    }
-
-    .price {
-      padding-right: 0;
-      padding-left: 1.5rem;
-    }
-  }
-}
-</style>

+ 0 - 254
kaifain_v2/components/Toolbar.vue

@@ -1,254 +0,0 @@
-<template lang="pug">
-  .toolbar
-    .container.is-content
-      .level.is-mobile
-        .level-left
-          .level-item
-            b-dropdown(
-              :triggers="[isMobile ? 'click' : 'hover']"
-              :append-to-body="isMobile"
-              )
-              .field.trigger(slot="trigger")
-                span {{sortType === 1 ? '最新发布' : '综合排序'}}
-                i.progico.progico-arrow
-              b-dropdown-item(
-                :focusable="false"
-                @click="changeSortType(0)"
-                ) 综合排序
-              b-dropdown-item(
-                :focusable="false"
-                @click="changeSortType(1)"
-                ) 最新发布
-
-          .level-item
-            b-dropdown.city-dropdown(
-              ref="city-dropdown"
-              :triggers="[isMobile ? 'click' : 'hover']"
-              :class="{'is-force-hide': forceHideCityMenu}"
-              :append-to-body="isMobile"
-              custom
-              )
-              .field.trigger(
-                slot="trigger"
-                @mouseenter="onCityTriggerHover"
-                )
-                span {{cityId && cityMap[cityId] && cityMap[cityId].name || '所在地区'}}
-                i.progico.progico-arrow
-              .city-menu
-                .row
-                  .tag.is-rounded(
-                    :class="!cityId || !cityMap[cityId] ? ['is-primary', 'is-light'] : []"
-                    @click="changeCity()"
-                    ) 不限城市
-                .split
-                .row.tags
-                  .tag.is-rounded(
-                    v-for="item in cities"
-                    :key="item.id"
-                    :class="cityId === item.id ? ['is-primary', 'is-light'] : []"
-                    @click="changeCity(item)"
-                    ) {{item.name}}
-
-          .level-item
-            .field
-              b-checkbox(
-                v-model="isChoiceCache"
-                @input="changeIsChoice"
-                ) 优选服务
-
-        .level-right
-          slot(name="right")
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-const enum SortType {
-  Default,
-  Recently
-}
-
-export default Vue.extend({
-  name: 'Toolbar',
-  props: {
-    cities: {
-      type: Array,
-      default: () => [] as any[]
-    },
-    sortType: {
-      type: Number,
-      default: SortType.Default
-    },
-    cityId: {
-      type: [Number, String],
-      default: null
-    },
-    isChoice: {
-      type: Boolean,
-      default: false
-    }
-  },
-
-  data() {
-    return {
-      isChoiceCache: false,
-      forceHideCityMenu: false,
-      // @ts-ignore
-      isMobile: this.$deviceType.isMobile()
-    }
-  },
-
-  computed: {
-    cityMap(): any {
-      return this.cities && this.cities.length ? this.cities.reduce((map, item) => {
-        map[item.id] = item
-        return map
-      }, {}) : {}
-    }
-  },
-
-  methods: {
-    onCityTriggerHover() {
-      this.forceHideCityMenu = false
-    },
-
-    changeSortType(type) {
-      if (type !== this.sortType) {
-        this.$emit('update:sortType', type)
-      }
-    },
-
-    changeCity(item) {
-      const id = item && item.id || null
-
-      if (id !== this.cityId) {
-        this.$emit('update:cityId', id)
-      }
-
-      if (this.isMobile) {
-        // @ts-ignore
-        this.$refs['city-dropdown'].toggle()
-      }
-
-      this.forceHideCityMenu = true
-    },
-
-    changeIsChoice(val) {
-      if (val !== this.isChoice) {
-        this.$emit('update:isChoice', val)
-      }
-    }
-  },
-
-  created() {
-    this.isChoiceCache = this.isChoice
-  }
-})
-</script>
-
-<style lang="scss">
-.kaifain-view {
-  .toolbar {
-    background: #f6f6f7;
-    height: 36px;
-
-    .level {
-      margin: 0 -0.75rem;
-    }
-
-    .level-item {
-      font-size: 0.75rem;
-      color: #777;
-      user-select: none;
-
-      .field {
-        height: 36px;
-        min-width: 86px;
-        padding: 0 0.75rem;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-
-        &.trigger:hover {
-          background: #fbfbfc;
-          color: #555;
-        }
-      }
-
-      .progico-arrow {
-        transform: rotate(90deg);
-        font-size: 10px;
-        margin: 2px 0 0 4px;
-        opacity: 0.86;
-      }
-    }
-
-    .dropdown-menu {
-      padding: 0;
-      margin-top: -4px;
-    }
-
-    .dropdown-content {
-      box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1);
-      border-radius: 0;
-    }
-
-    .dropdown-item {
-      font-size: 0.75rem;
-    }
-
-    @media screen and (max-width: 767px) {
-      .level {
-        margin: 0;
-      }
-
-      .level-left {
-        flex: 1;
-      }
-
-      .level-right {
-        display: none;
-      }
-    }
-  }
-
-  .city-dropdown {
-    .city-menu {
-      width: 392px;
-      padding: 0.5rem 0 0.5rem 1rem;
-
-      .split {
-        height: 1px;
-        background: #eee;
-        margin: 0.75rem 1rem 0.75rem 0;
-      }
-
-      .tag {
-        min-width: 68px;
-        background: transparent;
-        cursor: pointer;
-
-        &:not(.is-primary):hover {
-          background: #f2f3f3;
-        }
-      }
-
-      .tags > .tag {
-        margin: 0 0.25rem 0.3125rem 0;
-      }
-    }
-
-    &.is-mobile-modal {
-      @media screen and (max-width: 767px) {
-        .city-menu {
-          width: auto;
-        }
-      }
-    }
-  }
-
-  .dropdown.is-hoverable.is-force-hide .dropdown-menu {
-    display: none;
-  }
-}
-</style>

+ 0 - 282
kaifain_v2/components/Topnav.vue

@@ -1,282 +0,0 @@
-<template lang="pug">
-  b-navbar.topnav(
-    :fixed-top="fixed"
-    :transparent="true"
-    :active.sync="isActive"
-    :class="{'is-active': isActive}"
-    wrapper-class="container"
-    )
-    template(slot="brand")
-      b-navbar-item(href="/")
-        img.logo(src="../assets/img/logo.png" alt="开发屋")
-
-    template(slot="start")
-      b-navbar-item.search-box-lite(
-        v-show="fixed && showSearch"
-        tag="div"
-        )
-        b-field
-          input.input.is-small(
-            v-model="qSync"
-            placeholder="搜索服务或解决方案"
-            @keyup.enter.prevent="goSearch"
-            )
-          button.button.is-small.is-primary(@click="goSearch") 搜索
-
-    template(slot="end")
-      b-navbar-item(
-        v-show="fixed && showPublish"
-        @click="onPublishClick"
-        )
-        i.progico.progico-plus-o
-        span 发布需求
-      b-navbar-item(:href="`https://${MAIN_HOST}/otherpage/companyComplete${tail}`" target="_blank") 服务商入驻
-      b-navbar-item(:href="`https://${MAIN_HOST}/cat/${tail}`" v-show="!fixed") 程序员
-      b-navbar-dropdown(
-        label="更多"
-        :hoverable="true"
-        :arrowless="true"
-        :boxed="true"
-        :collapsible="isMobile"
-        )
-        b-navbar-item(:href="`https://${MAIN_HOST}/${tail}`") 客栈首页
-        b-navbar-item(:href="`https://${MAIN_HOST}/cat/${tail}`" v-show="fixed") 程序员
-        b-navbar-item(:href="`https://job.${MAIN_HOST}/${tail}`") 兼职招聘
-        b-navbar-item(:href="`https://${MAIN_HOST}/cloud${tail}`") 云端工作
-        b-navbar-item(:href="`https://${MAIN_HOST}/type/service${tail}`") 项目开发
-        b-navbar-item(:href="`https://jishuin.${MAIN_HOST}/${tail}`") 技术圈
-      .navbar-split
-      UserWidget(v-if="myInfo && myInfo.nickname")
-      template(v-else)
-        b-navbar-item(:href="`https://${MAIN_HOST}/index/app${tail}`") APP下载
-        b-navbar-item(:href="loginUrl") 登录
-        b-navbar-item(:href="`https://${MAIN_HOST}/user/register${tail}`") 注册
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import { MAIN_HOST } from '../constant'
-import UserWidget from './UserWidget.vue'
-
-export default Vue.extend({
-  name: 'Topnav',
-  components: {
-    UserWidget
-  },
-  props: {
-    fixed: {
-      type: Boolean,
-      default: false
-    },
-    q: {
-      type: String,
-      default: ''
-    },
-    showSearch: {
-      type: Boolean,
-      default: true
-    },
-    showPublish: {
-      type: Boolean,
-      default: true
-    }
-  },
-
-  data() {
-    return {
-      MAIN_HOST: MAIN_HOST,
-      tail: '?from=kaifain',
-      qSync: this.q,
-      loginUrl: '#',
-      isActive: false,
-      // @ts-ignore
-      isMobile: this.$deviceType.isMobile()
-    }
-  },
-
-  computed: {
-    myInfo(): any {
-      return this.$store.state.userinfo
-    },
-
-    baseUrl(): string {
-      return this.$store.state.domainConfig.siteUrl
-    }
-  },
-
-  methods: {
-    goSearch() {
-      const q = this.qSync
-
-      if (!q) {
-        return
-      }
-
-      this.$router.push(`/search?q=${q}&from=sbl`)
-      this.$emit('search-change', q)
-    },
-
-    onPublishClick() {
-      this.$emit('publish-click')
-    }
-  },
-
-  mounted() {
-    this.loginUrl = this.baseUrl + '/?loginbox=show&next=' + encodeURIComponent(location.href) || ''
-  }
-})
-</script>
-
-<style lang="scss">
-$theme-color: #20242d;
-
-.kaifain-view .topnav {
-  width: 100%;
-  height: 72px;
-  padding: 12px 0;
-  color: #fff;
-  background: transparent;
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-  z-index: 3;
-
-  .logo {
-    width: auto;
-    height: 44px;
-    max-height: none;
-    display: block;
-  }
-
-  .navbar-burger {
-    color: #fff;
-  }
-
-  .navbar-split {
-    background: #fff;
-    width: 1px;
-    height: 16px;
-    opacity: 0.3;
-    margin: 1px 12px 0;
-    align-self: center;
-  }
-
-  .navbar-menu {
-    &.is-active {
-      background: $theme-color;
-    }
-  }
-
-  .navbar-item,
-  .navbar-link {
-    background: transparent !important;
-    color: #fff;
-    font-size: 14px;
-    text-decoration: none !important;
-  }
-
-  .navbar-dropdown {
-    > a.navbar-item {
-      color: #444;
-    }
-  }
-
-  .navbar-brand {
-    .navbar-item {
-      padding: 0;
-    }
-  }
-
-  a.navbar-item {
-    color: inherit;
-  }
-
-  .progico-plus-o {
-    margin-right: 4px;
-  }
-
-  .search-box-lite {
-    margin: 0 1px;
-
-    .input.is-small {
-      border-radius: 4px 0 0 4px;
-      min-width: 256px;
-    }
-
-    .button.is-small {
-      border-radius: 0 4px 4px 0;
-      font-weight: 500;
-      border: 0;
-    }
-  }
-
-  &.is-active,
-  &.is-fixed-top {
-    background: $theme-color;
-  }
-
-  &.is-fixed-top {
-    padding: 0;
-    height: 54px;
-
-    // animation
-
-    .logo {
-      height: 36px;
-    }
-
-    .navbar-item,
-    .navbar-link {
-      font-size: 13px;
-    }
-
-    .user-widget,
-    .user-widget .nickname {
-      font-size: 13px;
-    }
-  }
-
-  @media screen and (max-width: 1023px) {
-    .logo {
-      height: 40px;
-    }
-
-    a.navbar-item:hover,
-    a.navbar-item.is-active {
-      background: darken(#20242d, 3%);
-      font-weight: 500;
-    }
-
-    .navbar-menu {
-      a.navbar-item {
-        color: inherit;
-      }
-
-      .navbar-split {
-        height: 1px;
-        width: auto;
-        margin: 8px 12px;
-        opacity: 0.2;
-      }
-    }
-  }
-
-  @media screen and (max-width: 767px) {
-    .navbar-burger {
-      margin-right: -16px;
-    }
-
-    .navbar-menu {
-      &.is-active {
-        margin: 0 -16px;
-      }
-    }
-
-    .progico-plus-o {
-      display: none;
-    }
-  }
-}
-</style>

+ 0 - 493
kaifain_v2/components/UserWidget.vue

@@ -1,493 +0,0 @@
-<template>
-  <div class="user-widget">
-    <b-navbar-item :href="`/dashboard`">
-      <i class="el-icon-monitor"></i> 控制台
-    </b-navbar-item>
-    <!-- <el-dropdown class="nav-dropdown">
-      <el-button type="text" class="dashboard-title">
-        <i class="el-icon-tickets"></i>工作台
-      </el-button>
-      <el-dropdown-menu slot="dropdown">
-        <el-dropdown-item>
-          <a class="workstation" :href="baseUrl+'/wo/work_todo'">
-            <i class="el-icon-edit"></i>我的待办
-          </a>
-        </el-dropdown-item>
-        <el-dropdown-item>
-          <a class="workstation" :href="baseUrl+'/wo/work_platform'">
-            <i class="el-icon-date"></i>我的项目
-          </a>
-        </el-dropdown-item>
-        <el-dropdown-item>
-          <a class="workstation" :href="baseUrl+'/wo/work_hire'">
-            <i class="el-icon-news"></i>我的雇佣
-          </a>
-        </el-dropdown-item>
-        <el-dropdown-item>
-          <a class="workstation" :href="baseUrl+'/wo/work_cloud'">
-            <i class="el-icon-service"></i>我的云端
-          </a>
-        </el-dropdown-item>
-      </el-dropdown-menu>
-    </el-dropdown> -->
-    <el-dropdown class="nav-dropdown">
-      <el-button type="text" class="message-box-title">
-        <i class="el-icon-message"></i>消息
-        <span
-          v-if="messageCount.total > 0"
-          class="message-count message-total"
-        >{{messageCount.total}}</span>
-      </el-button>
-      <el-dropdown-menu slot="dropdown">
-        <el-dropdown-item class="message-box" @click.native="clickMessages('/message/system')">
-          <i class="circle blue"></i>系统消息
-          <span v-if="messageCount.system" class="message-count">{{messageCount.system}}</span>
-        </el-dropdown-item>
-        <el-dropdown-item class="message-box" @click.native="clickMessages('/message/project')">
-          <i class="circle orange"></i>工作通知
-          <span v-if="messageCount.work" class="message-count">{{messageCount.work}}</span>
-        </el-dropdown-item>
-        <el-dropdown-item class="message-box" @click.native="clickMessages('/message/comment')">
-          <i class="circle red"></i>评论回复
-          <span v-if="messageCount.reply" class="message-count">{{messageCount.reply}}</span>
-        </el-dropdown-item>
-        <el-dropdown-item class="message-box" @click.native="clickMessages('/message/at')">
-          <i class="circle green"></i>@我的
-          <span v-if="messageCount.at" class="message-count">{{messageCount.at}}</span>
-        </el-dropdown-item>
-        <el-dropdown-item class="message-box" @click.native="clickMessages('/message/plus')">
-          <i class="circle pink"></i>赞及其它
-          <span
-            v-if="messageCount.community_other"
-            class="message-count"
-          >{{messageCount.community_other}}</span>
-        </el-dropdown-item>
-        <el-dropdown-item class="message-box" @click.native="clickMessages('/message/coin')">
-          <i class="circle yellow"></i>收支信息
-          <span v-if="messageCount.balance" class="message-count">{{messageCount.balance}}</span>
-        </el-dropdown-item>
-      </el-dropdown-menu>
-    </el-dropdown>
-    <el-popover class="nav-popover" placement="bottom" width="226" trigger="hover">
-      <div class="ref" slot="reference">
-        <a class="nav-header" :href="baseUrl+'/wo/work_todo'">
-          <img class="header-user" :src="myInfo.icon_url" />
-          <img
-            v-if="myInfo.is_vip"
-            class="header-vip-icon"
-            :src="baseUrl+`/Public/image/h5/vip_icon${vipImage}.png`"
-            alt="vip-icon"
-          />
-        </a>
-        <span class="nickname">{{myInfo.nickname}}</span>
-      </div>
-      <div class="menu">
-        <div v-if="myInfo.is_vip" class="vip-info vip-info-com">
-          <div class="vip-info-top">
-            <img
-              class="vip-icon"
-              :src="baseUrl+`/Public/image/h5/vip_icon${vipImage}.png`"
-              alt="vip-icon"
-            />
-            <span class="vip-content">
-              <span class="vip-title" :class="vipTextClass">{{vipText}}</span>
-              <br />
-              <span class="vip-end-date">{{vipInfo.endDate}}到期</span>
-            </span>
-          </div>
-          <div class="vip-arcs">
-            <a class="vip-arc" :class="vipTextClass" :href="baseUrl+'/type/vip/'+vipType">查看权益</a>
-            <a
-              class="vip-arc"
-              :class="vipTextClass"
-              :href="baseUrl+'/vip/pay?number=3&amp;product_id='+this.$store.state.userinfo.vip_type_id+'&amp;next=/type/vip/'+vipType"
-            >立即续费</a>
-          </div>
-        </div>
-        <div class="vip-items">
-          <a class="vip-item divider" :href="baseUrl+'/wo/work_platform'">
-            <i class="el-icon-date"></i>我的项目
-          </a>
-          <a class="vip-item" :href="baseUrl+'/wo/work_hire'">
-            <i class="el-icon-news"></i>我的雇佣
-          </a>
-          <a class="vip-item" :href="baseUrl+'/wo/work_cloud'">
-            <i class="el-icon-service"></i>我的云端
-          </a>
-          <a class="vip-item divider" :href="baseUrl+`/wo/manage_homepage/`">
-            <i class="el-icon-document"></i>我的主页
-          </a>
-          <a class="vip-item" :href="baseUrl+'/credit/pages'">
-            <i class="el-icon-credit"></i>技术信用
-          </a>
-          <a class="vip-item" :href="baseUrl+'/otherpage/user/collection'">
-            <i class="el-icon-collection"></i>收藏中心
-          </a>
-          <a class="vip-item divider" :href="baseUrl+'/index/app'">
-            <i class="el-icon-download-app"></i>APP下载
-          </a>
-          <a class="vip-item" @click="clickQuit">
-            <i class="el-icon-back" style="margin: 0 10px !important;"></i>退出
-          </a>
-        </div>
-      </div>
-    </el-popover>
-  </div>
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-
-export default Vue.extend({
-  data() {
-    return {
-      messageCount: {}
-    }
-  },
-
-  computed: {
-    baseUrl(): string {
-      return this.$store.state.domainConfig.siteUrl
-    },
-
-    myInfo(): any {
-      return this.$store.state.userinfo
-    },
-
-    vipInfo(): any {
-      let userinfo = this.$store.state.userinfo
-      return {
-        id: userinfo.vip_type_id,
-        endDate: userinfo.vip_end_date,
-      }
-    },
-
-    vipImage(): string {
-      switch (parseInt(this.$store.state.userinfo.vip_type_id)) {
-        case 1:
-          return '_com'
-        case 2:
-          return ''
-        case 3:
-          return '_premium'
-        default:
-          return ''
-      }
-    },
-    vipType(): string | undefined {
-      switch (parseInt(this.$store.state.userinfo.vip_type_id)) {
-        case 1:
-        case 3:
-          return 'enterprise'
-        case 2:
-          return 'developer'
-      }
-    },
-    vipTextClass(): string {
-      switch (parseInt(this.$store.state.userinfo.vip_type_id)) {
-        case 1:
-          return 'is-newly'
-        case 2:
-          return 'is-dev'
-        case 3:
-          return 'is-premium'
-        default:
-          return ''
-      }
-    },
-    vipText(): string {
-      switch (parseInt(this.$store.state.userinfo.vip_type_id)) {
-        case 1:
-          return '初创版会员'
-        case 2:
-          return '开发者会员'
-        case 3:
-          return '企业版会员'
-        default:
-          return ''
-      }
-    }
-  },
-
-  methods: {
-    clickMessages(url) {
-      location.href = this.baseUrl + url
-    },
-
-    clickQuit() {
-      location.href = this.baseUrl + '/user/quit'
-    },
-
-    async getMessageCount() {
-      // @ts-ignore
-      let res = await this.$axios.$get(
-        '/api/message/getUnreadCount',
-        {},
-        { neverLogout: true }
-      )
-      if (res) {
-        this.messageCount = res.data
-      }
-    }
-  },
-
-  mounted() {
-    if (this.myInfo && this.myInfo.nickname) {
-      this.getMessageCount()
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.kaifain-view .user-widget {
-  display: flex;
-  align-items: center;
-  padding-top: 1px;
-  font-size: 14px;
-  font-weight: 400;
-
-  .el-button {
-    font-size: inherit;
-    font-weight: 400;
-    color: #444;
-  }
-
-  .el-dropdown {
-    font-size: inherit;
-  }
-
-  > .nav-dropdown {
-    margin: 0 10px;
-  }
-
-  .nav-dropdown {
-    > .el-button {
-      color: #fff;
-      transition: none;
-    }
-  }
-
-  .nav-popover {
-    font-size: inherit;
-    margin-left: 8px;
-  }
-
-  .nav-item {
-    display: flex;
-    height: 83px;
-    align-items: center;
-    font-size: 15px;
-    color: #515151;
-    /* padding: 0 15px; */
-    box-sizing: border-box;
-  }
-  .nav-item:first-child {
-    padding: 0;
-  }
-  .nav-item:nth-child(n + 2):hover {
-    color: #1782d9;
-    border-top: 5px solid transparent;
-    border-bottom: 5px solid #1782d9;
-  }
-  .nav-dropdown,
-  .nav-popover {
-    --imgWidth: 28px;
-    height: 40px;
-    display: flex;
-    align-items: center;
-  }
-  .nav-popover > .ref {
-    display: flex;
-    align-items: center;
-  }
-  .nav-header {
-    position: relative;
-    width: var(--imgWidth);
-    height: var(--imgWidth);
-    margin-right: 5px;
-  }
-  .logo {
-    width: 140px;
-    height: auto;
-  }
-  .input {
-    width: 234px;
-    height: 40px;
-    border-radius: 20px;
-    background: #f6f6f6;
-    padding: 0 40px;
-    border: 1px solid #ebebeb;
-    font-size: 13px;
-  }
-  .message-count {
-    color: white;
-    margin-left: 4px;
-    display: block;
-    line-height: 18px;
-    padding: 0 8px;
-    border-radius: 9px;
-    background: grey;
-  }
-  .message-count.message-total {
-    position: absolute;
-    top: 0px;
-    right: -10px;
-    background: #d95c5c;
-  }
-  span.other-icon {
-    display: block;
-    margin-left: 30px;
-  }
-  .nickname {
-    font-size: 14px;
-  }
-  .header-user {
-    width: var(--imgWidth);
-    height: var(--imgWidth);
-    border-radius: 20px;
-  }
-  .header-vip-icon {
-    position: absolute;
-    top: 16px;
-    left: 18px;
-    width: 16px;
-    height: 16px;
-  }
-}
-</style>
-
-<style lang="scss" scoped>
-.el-icon-credit {
-  background: url("~@/assets/img/header/creditIconMine.png") no-repeat;
-  background-size: cover;
-  width: 16px;
-  height: 16px;
-  vertical-align: middle;
-  margin: 0 9px !important;
-}
-.el-icon-download-app {
-  background: url("~@/assets/img/header/download@2x.png") no-repeat;
-  background-size: cover;
-  width: 16px;
-  height: 16px;
-  vertical-align: middle;
-  margin: 0 9px !important;
-}
-i {
-  margin-right: 4px;
-}
-i.circle {
-  display: inline-block;
-  --width: 12px;
-  width: var(--width);
-  height: var(--width);
-  border-radius: calc(var(--width) / 2);
-}
-i.blue {
-  background: #3b83c0;
-}
-i.orange {
-  background: #e07b53;
-}
-i.red {
-  background: #d95c5c;
-}
-i.green {
-  background: #5bbd72;
-}
-i.pink {
-  background: #d9499a;
-}
-i.yellow {
-  background: #f2c61f;
-}
-.message-box {
-  position: relative;
-  display: flex;
-  align-items: center;
-}
-.workstation {
-  color: #444;
-}
-.account-ctrl {
-  color: #444;
-  font-size: 15px;
-}
-
-.vip-info {
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  align-items: center;
-  width: 206px;
-  height: 120px;
-}
-.vip-info-top {
-  display: flex;
-  width: 142px;
-}
-.vip-title {
-  color: #cb9d53;
-  font-size: 16px;
-  line-height: 36px;
-}
-.vip-icon {
-  width: 24px;
-  height: 24px;
-  margin: 10px 8px 0 0;
-}
-.vip-end-date {
-  font-size: 12px;
-  color: #999;
-}
-.vip-arcs {
-  display: flex;
-  justify-content: space-between;
-  width: 142px;
-  margin-top: 11px;
-}
-.vip-arc {
-  flex: 1;
-  font-size: 13px;
-  color: #cb9d53;
-  text-align: center;
-}
-.vip-arc:first-child {
-  border-right: 1px solid rgba(245, 245, 245, 1);
-}
-.vip-info-com .vip-title {
-  color: rgb(113, 177, 253);
-}
-.vip-info-com .vip-arc {
-  color: rgb(113, 177, 253);
-}
-.vip-items {
-  font-size: 14px;
-  display: flex;
-  flex-direction: column;
-}
-.vip-item {
-  line-height: 32px;
-  color: #606266;
-}
-.vip-item > i {
-  margin: 0 10px;
-}
-.divider {
-  border-top: 1px solid rgba(0, 0, 0, 0.05);
-  margin-top: 10px;
-  padding-top: 10px;
-  cursor: pointer;
-}
-.vip-info-com .is-dev {
-  color: #cb9d53;
-}
-.vip-info-com .is-newly {
-  color: #308eff;
-}
-
-.vip-info-com .is-premium {
-  color: #00c469;
-}
-</style>

+ 0 - 8
kaifain_v2/constant.ts

@@ -1,8 +0,0 @@
-export const MAIN_HOST = 'proginn.com'
-export const MAIN_ENDPOINT = process.env.NODE_ENV === 'development' ? 'https://web.test.proginn.com' : 'https://proginn.com'
-export const KAIFAIN_MOB_SITE = process.env.NODE_ENV === 'development' ? 'https://kaifain-m.test.proginn.com' : 'https://kaifain.m.proginn.com'
-export const KAIFAIN_API_CAT_ID = process.env.NODE_ENV === 'development' ? '71f9355f0130' : 'e66fca1ea675'
-export const BINSTD_PID = process.env.NODE_ENV === 'development' ? '667006' : '492803'
-export const enum DASHBOARD_SCENE_CODE {
-  PAID = '2001'
-}

+ 0 - 140
kaifain_v2/helpers/apiDocHelper.ts

@@ -1,140 +0,0 @@
-import SwaggerParser from 'swagger-parser'
-
-export const parseApiDocFile = async (remoteUrl: string) => {
-  let apiDoc
-
-  try {
-    // @ts-ignore
-    apiDoc = await SwaggerParser.parse(remoteUrl)
-  } catch (e) {
-    console.error('[parse api doc failed]', e)
-  }
-
-  return apiDoc
-}
-
-export const isJsonString = (input: string) => {
-  return input ? /^\{\s*".+}$/.test(input.trim()) : false
-}
-
-export const formatJsonString = (input: string) => {
-  let formatted: string
-
-  try {
-    formatted = JSON.stringify(JSON.parse(input), null, 2)
-  } catch (e) {
-    formatted = input.trim()
-  }
-
-  return formatted
-}
-
-const convertKeyValuePropertiesToArray = (obj: any) => {
-  if (!obj || !Object.keys(obj).length) {
-    return null
-  }
-
-  const params: any[] = []
-
-  if (obj) {
-    for (const key in obj) {
-      const row = obj[key]
-
-      if (row.properties || row.items && row.items.properties) {
-        row.children = convertKeyValuePropertiesToArray(row.properties || row.items.properties)
-      }
-
-      params.push({
-        name: key,
-        ...row
-      })
-    }
-  }
-
-  return params
-}
-
-export const formatApiDocToRoutes = (data: any, opts?: {
-  injectAccessKey?: boolean
-}) => {
-  const {
-    host = '',
-    basePath = '',
-    schemes,
-    paths
-  } = data
-  const {
-    injectAccessKey = true
-  } = opts || {}
-
-  const routes: any[] = []
-
-  if (paths) {
-    let index = 0
-
-    for (const path in paths) {
-      for (const method in paths[path]) {
-        const item = paths[path][method]
-        const url = `${schemes[schemes.length -1]}://${host}${basePath}${path}`.replace(/\/+$/, '')
-        const paramsMap: any = {}
-        let successResponse: any
-
-        if (injectAccessKey) {
-          paramsMap.query = [{
-            name: 'key',
-            in: 'query',
-            description: '请求 AccessKey, 请在控制台中查看',
-            required: true,
-            type: 'string',
-            _certif: true
-          }]
-        }
-
-        if (item.parameters && item.parameters.length) {
-          for (const param of item.parameters) {
-            // header, path, query, body
-            const _in = param.in
-
-            if (!_in) {
-              continue
-            }
-
-            if (!paramsMap[_in]) {
-              paramsMap[_in] = []
-            }
-
-            paramsMap[_in].push(param)
-          }
-        }
-
-        if (item.responses) {
-          for (const code in item.responses) {
-            const schema = item.responses[code].schema
-
-            if (/^20/.test(code) && schema) {
-              successResponse = {
-                schema,
-                params: convertKeyValuePropertiesToArray(schema.properties),
-                example: schema.example
-              }
-              break
-            }
-          }
-        }
-
-        routes.push({
-          index,
-          url,
-          method,
-          paramsMap,
-          successResponse,
-          ...item
-        })
-
-        index++
-      }
-    }
-  }
-
-  return routes
-}

+ 0 - 91
kaifain_v2/helpers/seoHelper.ts

@@ -1,91 +0,0 @@
-import { randomRange, log10 } from '../utils/misc'
-import murmurhash from 'murmurhash'
-
-export const genDocumentHeadData = (input: {
-  ctx: any
-  catName?: string
-}) => {
-  const { ctx, catName } = input || {}
-  const canonical: string = process.server ? `https://${ctx.req.headers.host}${ctx.req.url}` : location && location.href
-  let title: string
-  let keywords: string
-  let description: string
-
-  if (catName) {
-    title = `${catName} 软件、网站、APP、小程序开发及SaaS、PaaS、IaaS、API服务平台-开发屋`
-    keywords = `${catName}软件开发,${catName}APP开发,${catName}小程序开发,${catName}SaaS服务商`
-    description = `开发屋为${catName}中小型企业企业提供各行业软件、APP、小程序开发服务,并整合开发项目所需的各种SaaS、PaaS,LaaS以及API服务商供选择,全程解决开发需求!`
-  } else {
-    title = '开发屋-提供网站建设、APP软件、小程序开发及SaaS、PasS、IaaS服务'
-    keywords = '网站开发, 软件APP开发, SaaS, PaaS'
-    description = '开发屋为企业提供行业内领先的技术解决方案,包括行业定制化SaaS、PasS、API数据接口服务以及技术组织,保障企业在降低人力开发成本的同时,得到优质的项目开发实力。'
-  }
-
-  return {
-    title,
-    keywords,
-    description,
-    canonical
-  }
-}
-
-const scoreSubCatItem = ({path, topCatId, subCatId}) => {
-  const uni = murmurhash.v3(path)
-  const isRoot = path === '/'
-
-  return (item: any, idx: number) => {
-    let score = 0
-
-    if (topCatId && item.parent_id === topCatId) {
-      score += 100
-    }
-
-    if (subCatId && item.cat_id === subCatId) {
-      score -= 100
-    }
-
-    if (!isRoot && !score) {
-      score += log10(Math.abs(uni - murmurhash.v3(item.cat_id)))
-    }
-
-    return Object.assign({}, item, {
-      _score: score
-    })
-  }
-}
-
-const genFooterLinkItem = (name: string, hashId: string) => {
-  return {
-    name: `${name}技术开发`,
-    url: `/c/${hashId}`
-  }
-}
-
-export const genDocumentFooterData = (input: {
-  ctx: any
-  classes: any[]
-  topCatId?: string
-  subCatId?: string
-}) => {
-  const { ctx, classes, topCatId, subCatId } = input || {}
-  const host = (process.server ? ctx.req.headers.host : location.host) || ''
-  const path = process.server ? ctx.req.url : location.pathname || '/'
-  const baseLink = host && host.indexOf('local') > -1 ? `http://${host}` : `https://${host}`
-  const link = [{
-    name: '热门领域技术解决方案',
-    data: classes.map(topCat => genFooterLinkItem(topCat.name, topCat.hash_id))
-  }, {
-    name: '细分领域技术解决方案',
-    data: classes
-      .flatMap(topCat => topCat.categories || [])
-      .map(scoreSubCatItem({path, topCatId, subCatId}))
-      .sort((a, b) => b._score - a._score)
-      .slice(0, randomRange(20, 30))
-      .map(cat => genFooterLinkItem(cat.name, cat.cat_id))
-  }]
-
-  return {
-    baseLink,
-    link
-  }
-}

+ 0 - 186
kaifain_v2/mixins/solution.ts

@@ -1,186 +0,0 @@
-import Vue from 'vue'
-import { listSolutions } from '../apis/solution'
-import { genCatIdSearchSentence, getTopCatSubCatIds } from '../utils/misc'
-
-export const SolutionListMixin = Vue.extend({
-  data() {
-    return {
-      q: '',
-      page: 0,
-      size: 10,
-      solutionList: [],
-      solutionTotal: 0,
-      cityId: null,
-      sortType: 0,
-      isChoice: false,
-      topCatId: '_',
-      catId: '_',
-      serviceType: '_',
-      classes: [] as any[]
-    }
-  },
-
-  watch: {
-    topCatId(val) {
-      if (this.catId === '_') {
-        this.updateUrlPage(1, {
-          path: val !== '_' ? `/c/${val}` : '/',
-          params: {
-            cat_id: val
-          },
-          reset: true
-        })
-      }
-    },
-
-    catId(val) {
-      val = val !== '_' ? val : this.topCatId
-
-      this.updateUrlPage(1, {
-        path: val !== '_' ? `/c/${val}` : '/',
-        params: {
-          cat_id: val
-        },
-        reset: true
-      })
-    },
-
-    serviceType(val) {
-      this.getSolutionList({
-        query: {
-          st: val !== '_' ? val : undefined
-        }
-      })
-    },
-
-    cityId(val) {
-      this.getSolutionList({
-        query: {
-          city_id: val || undefined
-        }
-      })
-    },
-
-    sortType(val) {
-      this.getSolutionList({
-        query: {
-          sort: val || undefined
-        }
-      })
-    },
-
-    isChoice(val) {
-      this.getSolutionList({
-        query: {
-          is_choice: val ? 1 : undefined
-        }
-      })
-    }
-  },
-
-  methods: {
-    updateUrlPage(targetPage = 1, input: {
-      path?: string
-      params?: any
-      query?: any
-      reset?: boolean
-    }) {
-      const paramsPage = this.$route.params.page
-      const queryPage = this.$route.query.page
-      const curPage = ~~(paramsPage || queryPage)
-      let { path, params, query, reset } = input
-
-      if ((!curPage || curPage === targetPage) && !params && !query) {
-        return
-      }
-
-      params = params || {}
-      query = query || {}
-
-      const opts: any = {
-        path,
-        params: Object.assign({}, this.$route.params, params),
-        query: Object.assign({}, this.$route.query, query)
-      }
-
-      if (paramsPage || params) {
-        Object.assign(opts.params, {
-          page: targetPage
-        })
-      }
-
-      if (queryPage) {
-        Object.assign(opts.query, {
-          page: targetPage
-        })
-      }
-
-      if (reset) {
-        delete opts.query.sort
-        delete opts.query.city_id
-        delete opts.query.is_choice
-        delete opts.query.st
-      }
-
-      this.$router.replace(opts)
-    },
-
-    async getSolutionList(opts: {
-      page?: number
-      path?: string
-      params?: any
-      query?: any
-      reset?: boolean
-      updateUrl?: boolean
-    }) {
-      const {
-        page = 1,
-        path,
-        params = false,
-        query = false,
-        reset = false,
-        updateUrl = true
-      } = opts
-
-      if (reset) {
-        this.sortType = 0
-        this.cityId = null
-        this.isChoice = false
-        this.serviceType = '_'
-      }
-
-      if (updateUrl) {
-        this.updateUrlPage(page, {
-          path,
-          params,
-          query,
-          reset
-        })
-      }
-
-      let matchedCatIds: any[] = []
-
-      if (this.catId === '_') {
-        const topCat = this.classes.find((topCat) => topCat.hash_id === this.topCatId)
-
-        matchedCatIds = getTopCatSubCatIds(topCat)
-      } else {
-        matchedCatIds = [this.catId]
-      }
-
-      const solutionRes = await listSolutions({
-        cat_id: genCatIdSearchSentence(matchedCatIds, this.serviceType),
-        city_id: this.cityId || '',
-        sort: this.sortType || 0,
-        is_choice: this.isChoice && 1 || undefined,
-        q: this.q,
-        page,
-        size: 10
-      })
-
-      this.page = page
-      this.solutionList = solutionRes && solutionRes.list || []
-      this.solutionTotal = solutionRes && ~~solutionRes.total
-    }
-  }
-})

+ 0 - 25
kaifain_v2/mixins/stats.js

@@ -1,25 +0,0 @@
-const script = `var _hmt = _hmt || [];
-(function () {
-  var hm = document.createElement('script');
-  hm.src = 'https://hm.baidu.com/hm.js?18538c3e0283bcd9958ba8e0492a0d84';
-  var s = document.getElementsByTagName('script')[0];
-  s.parentNode.insertBefore(hm, s);
-  var bp = document.createElement('script');
-  var curProtocol = window.location.protocol.split(':')[0];
-  if (curProtocol === 'https') {
-    bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
-  } else {
-    bp.src = 'http://push.zhanzhang.baidu.com/push.js';
-  }
-  s.parentNode.insertBefore(bp, s);
-})();`
-
-export default {
-  head: {
-    script: [{
-      innerHTML: script,
-      body: true
-    }],
-    __dangerouslyDisableSanitizers: ['script']
-  }
-}

+ 0 - 66
kaifain_v2/pages/dashboard/apis.vue

@@ -1,66 +0,0 @@
-<template lang="pug">
-  .dashboard-apis
-    .page-header
-      h1.title 我的 API
-
-    .section.columns
-      .column
-        .card
-          div(v-if="apiListLoaded && apiList && apiList.length")
-            .api-list
-              PanelApiCell(
-                v-for="item in apiList"
-                :data="item"
-                :key="item.api_id"
-                )
-
-          .content(v-if="apiListLoaded && !apiList.length")
-            PanelApiEmpty
-
-          //- skeleton
-          .api-list(v-else-if="!apiListLoaded")
-            PanelApiCell(
-              v-for="i in 5"
-              :is-skeleton="true"
-              :key="i"
-              )
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import PanelApiCell from '../../components/PanelApiCell.vue'
-import PanelApiEmpty from '../../components/PanelApiEmpty.vue'
-
-export default Vue.extend({
-  name: 'Dashboard',
-  components: {
-    PanelApiCell,
-    PanelApiEmpty
-  },
-
-  layout: 'kaifain_v2',
-
-  data() {
-    return {
-      apiList: [],
-      apiListLoaded: false
-    }
-  },
-
-  async created() {
-    await this.$store.dispatch('apigateway:apilist:load')
-
-    this.apiList = this.$store.state.kaifain.apiList
-    this.apiListLoaded = true
-  }
-})
-</script>
-
-<style lang="scss">
-.dashboard-apis {
-  .section {
-    padding: 0;
-  }
-}
-</style>

+ 0 - 295
kaifain_v2/pages/dashboard/home.vue

@@ -1,295 +0,0 @@
-<template lang="pug">
-  .dashboard-home
-    .section.columns
-      .column
-        .card
-          .header
-            .caption 账户信息
-          .content.user
-            .profile(v-if="apiUser && myInfo")
-              .avatar
-                img(:src="myInfo.icon_url")
-              .info
-                .name Hi, {{myInfo.nickname}}
-                .meta
-                  span AccessKey:
-                  code {{apiUser.accessKey || '-'}}
-
-            //- skeleton
-            .profile(v-else)
-              .avatar
-                b-skeleton(circle)
-              .info
-                b-skeleton(width="20%")
-                b-skeleton(width="50%")
-
-      .column
-        .card
-          .header
-            .caption 资源状态
-          .content
-            .level.is-mobile.state-summary(v-if="apiListLoaded")
-              .level-item.has-text-centered
-                div
-                  p.heading 已购API
-                  p.title
-                    router-link(
-                      v-if="apiList && apiList.length > 0"
-                      to="/dashboard/apis"
-                      ) {{apiList.length}}
-                    span(v-else) 0
-              .level-item.has-text-centered
-                div
-                  p.heading 安全警告
-                  p.title 0
-              .level-item.has-text-centered
-                div
-                  p.heading 待支付
-                  p.title 0
-
-            //- skeleton
-            .level.is-mobile.state-summary(v-else)
-              .level-item.has-text-centered
-                .state-skeleton
-                  b-skeleton(width="45%")
-                  b-skeleton(width="30%" height="30px")
-              .level-item.has-text-centered
-                .state-skeleton
-                  b-skeleton(width="45%")
-                  b-skeleton(width="30%" height="30px")
-              .level-item.has-text-centered
-                .state-skeleton
-                  b-skeleton(width="45%")
-                  b-skeleton(width="30%" height="30px")
-
-    .section.columns
-      .column
-        .card
-          .header
-            .caption 我的API
-          div(v-if="apiListLoaded && apiList && apiList.length")
-            .api-list
-              PanelApiCell(
-                v-for="(item, i) in apiList"
-                v-if="i < 3"
-                :data="item"
-                :key="item.api_id"
-                )
-            router-link.view-all(to="/dashboard/apis")
-              span 查看我的所有API
-              b-icon(pack="progico" icon="progico-arrow")
-
-          .content(v-if="apiListLoaded && !apiList.length")
-            PanelApiEmpty
-
-          //- skeleton
-          .api-list(v-else-if="!apiListLoaded")
-            PanelApiCell(
-              v-for="i in 2"
-              :is-skeleton="true"
-              :key="i"
-              )
-
-    .section.columns
-      .column
-        .card
-          .header
-            .caption 近期调用趋势
-          ApiStatsChart(
-            v-if="apiList && apiList.length && stats && stats.count"
-            :list="stats.list"
-            :from="from"
-            :to="to"
-            )
-          .content(v-else)
-            .empty
-              p 最近24小时内无使用记录
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import { pumpProxy } from '../../apis/apigateway'
-import PanelApiCell from '../../components/PanelApiCell.vue'
-import PanelApiEmpty from '../../components/PanelApiEmpty.vue'
-import ApiStatsChart from '../../components/ApiStatsChart.vue'
-import { DASHBOARD_SCENE_CODE } from '../../constant';
-import { sleep } from '../../utils/misc'
-
-export default Vue.extend({
-  name: 'Dashboard',
-  components: {
-    PanelApiCell,
-    PanelApiEmpty,
-    ApiStatsChart
-  },
-
-  layout: 'kaifain_v2',
-
-  data() {
-    return {
-      apiUser: null as any,
-      apiList: [] as any[],
-      apiListLoaded: false,
-      stats: null as any,
-      from: 0,
-      to: 0
-    }
-  },
-
-  computed: {
-    myInfo(): any {
-      return this.$store.state.userinfo
-    }
-  },
-
-  async created() {
-    const { scene } = this.$route.query
-    const now = Math.floor(Date.now() / 1000)
-    const isPaidCallback = scene === DASHBOARD_SCENE_CODE.PAID
-
-    if (!this.$store.state.kaifain.apiUser) {
-      await this.$store.dispatch('apigateway:user:load')
-    }
-
-    this.apiUser = this.$store.state.kaifain.apiUser
-
-    if (this.apiUser && !this.apiUser.created) {
-      if (isPaidCallback) {
-        await sleep(720)
-      }
-
-      await this.$store.dispatch('apigateway:apilist:load', {
-        force: isPaidCallback
-      })
-
-      this.apiList = [...this.$store.state.kaifain.apiList].sort((a, b) => b.created_at - a.created_at)
-      this.apiListLoaded = true
-
-      this.from = now - 3600 * 24
-      this.to = now
-      this.stats = await pumpProxy({
-        query: {
-          action: 'GetLogs'
-        },
-        body: {
-          from: this.from,
-          to: this.to,
-          query: `* | select route_id as api_id, count(*) as total, max(started_at) as called_at, histogram(to_unixtime(date_trunc('hour', __time__))/3600) as series group by api_id order by total limit 20`
-        }
-      })
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-@import '../../assets/styles/vars';
-
-.dashboard-home {
-  .user {
-    .profile {
-      display: flex;
-      align-items: center;
-    }
-
-    .avatar {
-      flex: none;
-      margin-right: 1.25rem;
-      width: 64px;
-      height: 64px;
-
-      img,
-      .b-skeleton,
-      .b-skeleton-item {
-        width: 100%;
-        height: 100%;
-        border-radius: 50%;
-      }
-    }
-
-    .info {
-      flex: 1;
-    }
-
-    .name {
-      font-weight: 500;
-      margin: 0.5rem 0 0.25rem;
-    }
-
-    .meta {
-      font-size: 0.9375rem;
-
-      > * {
-        display: inline-block;
-      }
-
-      span {
-        margin: 8px 6px 8px 0;
-      }
-
-      code {
-        color: #666;
-        border-radius: 2px;
-      }
-    }
-  }
-
-  .state-summary {
-    .heading {
-      font-size: 12px;
-      margin-top: 0.5em;
-    }
-
-    .title {
-      font-weight: 500;
-      margin-bottom: -6px;
-
-      a {
-        color: inherit;
-      }
-    }
-
-    .state-skeleton {
-      width: 100%;
-
-      .b-skeleton {
-        align-items: center;
-        margin-top: 0.5rem;
-      }
-    }
-  }
-
-  @media screen and (max-width: 480px) {
-    padding: 1.25rem 1rem;
-
-    .user {
-      .avatar {
-        width: 36px;
-        height: 36px;
-        margin-right: 0.75rem;
-        margin-top: 0.25rem;
-        align-self: start;
-      }
-
-      .info {
-        .name{
-          font-size: 15px;
-        }
-
-        .meta {
-          span {
-            font-size: 12px;
-          }
-          code {
-            font-size: 13px;
-            padding-left: 3px;
-            padding-right: 3px;
-            margin-left: -1px;
-          }
-        }
-      }
-    }
-  }
-}
-</style>

+ 0 - 552
kaifain_v2/pages/dashboard/inspector.vue

@@ -1,552 +0,0 @@
-<template lang="pug">
-  .api-inspector
-    .page-header
-      h1.title API 调试
-
-    .section.columns(v-if="apiListLoad && (!apiList || !apiList.length)")
-      .column
-        b-notification(
-          type="is-warning"
-          role="alert"
-          :closable="false"
-          )
-            PanelApiEmpty(message="尚未购入任何 API 接口,无法调试。")
-
-    .section.columns.sticky-bar
-      .column
-        b-field(grouped)
-          b-field(label="接口")
-            b-select(
-              v-model="curApiId"
-              placeholder="选择接口"
-              @input="changeApi"
-              :loading="!apiListLoad"
-              )
-              option(
-                v-for="item in apiList"
-                :value="item.api_id"
-                :key="item.api_id"
-                ) {{ item.title }}
-
-          b-field(
-            label="子接口"
-            grouped
-            expanded
-            )
-            b-select(
-              v-model="curRouteIndex"
-              placeholder="选择子接口"
-              @input="changeRoute"
-              :loading="!apiDocLoad"
-              :disabled="!apiListLoad"
-              expanded
-              )
-              option(
-                v-for="(item, idx) in curApiRoutes"
-                :value="idx"
-                :key="idx"
-                ) {{ item.summary }}
-
-            b-button.is-primary.is-float-btn(
-              @click="send"
-              :loading="isRequesting"
-              :disabled="!apiDocLoad"
-              ) 发送请求
-
-    .section.columns
-      .column
-        b-field(label="请求 URL")
-          pre(v-if="curRoute")
-            code.hljs.http
-              span.hljs-keyword {{curRoute.method && curRoute.method.toUpperCase()}}
-              span.hljs-string  {{curRoute.url}}{{querystring}}
-
-          //- skeleton
-          b-skeleton(
-            v-else
-            width="100%"
-            height="54px"
-            )
-
-    .section.columns(ref="request")
-      .column
-        b-tabs(v-model="activeReqTab")
-          //- query
-          b-tab-item(label="Query Params")
-            b-table.common-table(
-              v-if="curRoute && curRoute.paramsMap.query"
-              :data="curRoute.paramsMap.query"
-              )
-              b-table-column(
-                width="18%"
-                field="name"
-                label="参数"
-                v-slot="props"
-                ) {{ props.row.name }}
-
-              b-table-column(
-                field="value"
-                width="35%"
-                label="值"
-                v-slot="props"
-              )
-                b-input(
-                  v-if="props.row._certif && props.row.name === 'key'"
-                  :value="apiUser.accessKey"
-                  size="is-small"
-                  disabled
-                  )
-                b-input(
-                  v-else
-                  v-model="mock.query[props.row.name]"
-                  size="is-small"
-                  @keyup.enter.native="send"
-                  )
-
-              b-table-column(
-                field="value"
-                label="说明"
-                v-slot="props"
-              )
-                span.desc(v-if="props.row._certif") 请求 AccessKey
-                span.desc(v-else) {{ props.row.description }}
-
-            //- skeleton
-            .b-table.common-table(v-else)
-              .table-wrapper.has-mobile-cards
-                table.table
-                  tr
-                    th(width="18%") 参数
-                    th(width="35%") 值
-                    th 说明
-                  tr(v-for="i in 3")
-                    td(v-for="i in 3")
-                      .skeleton-cell
-                        b-skeleton(width="50%")
-
-          //- body
-          b-tab-item(
-            label="Body"
-            v-if="curRoute && curRoute.paramsMap.body"
-            )
-            b-table.common-table(
-              :data="curRoute.paramsMap.body"
-              )
-              b-table-column(
-                width="18%"
-                field="name"
-                label="参数"
-                v-slot="props"
-                ) {{ props.row.name }}
-
-              b-table-column(
-                width="35%"
-                field="value"
-                label="值"
-                v-slot="props"
-              )
-                b-input(
-                  v-model="mock.body[props.row.name]"
-                  size="is-small"
-                  @keyup.enter.native="send"
-                  )
-
-              b-table-column(
-                field="value"
-                label="说明"
-                v-slot="props"
-              )
-                span.desc {{ props.row.description }}
-
-    .section.columns(ref="response")
-      .column
-        b-tabs(v-model="activeResTab")
-          b-tab-item(label="Body")
-            b-notification.pending-state(v-if="!response" :closable="false")
-              span(v-if="!apiListLoad || !apiDocLoad") 等待初始化...
-              span(v-else-if="isRequesting") 正在请求...
-              span(v-else) 点击 "发送请求" 开始测试
-              b-loading(
-                v-model="isRequesting"
-                :is-full-page="false"
-                :can-cancel="false"
-                )
-
-            pre(v-if="response")
-              code(v-highlight) {{response.data || null}}
-
-          b-tab-item(label="Headers")
-            b-notification.pending-state(v-if="!response" :closable="false")
-              span(v-if="!apiListLoad || !apiDocLoad") 等待初始化...
-              span(v-else-if="isRequesting") 正在请求...
-              span(v-else) 点击 "发送请求" 开始测试
-              b-loading(
-                v-model="isRequesting"
-                :is-full-page="false"
-                :can-cancel="false"
-                )
-
-            b-table.common-table(
-              v-if="response"
-              :data="responseHeaderList"
-              :mobile-cards="false"
-              )
-              b-table-column(
-                field="key"
-                label="键"
-                v-slot="props"
-                )
-                  span.key {{ props.row.key }}
-              b-table-column(
-                field="value"
-                label="值"
-                v-slot="props"
-                )
-                  span.value {{ props.row.value }}
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import qs from 'qs'
-import { pumpProxy } from '../../apis/apigateway'
-import { getSolution } from '../../apis/solution'
-import { parseApiDocFile, formatApiDocToRoutes } from '../../helpers/apiDocHelper'
-import PanelApiEmpty from '../../components/PanelApiEmpty.vue'
-
-let responseContEl: any
-
-export default Vue.extend({
-  name: 'inspector',
-  components: {
-    PanelApiEmpty
-  },
-
-  layout: 'kaifain_v2',
-
-  data() {
-    return {
-      activeReqTab: 0,
-      activeResTab: 0,
-      apiUser: null,
-      apiList: [] as any[],
-      apiListLoad: false,
-      apiDocLoad: false,
-      curRouteIndex: null as number | null,
-      curApiId: null as any,
-      curApi: null,
-      curApiRoutes: [] as any[],
-      curRoute: null,
-      mock: {
-        query: {},
-        body: {}
-      },
-      response: null,
-      responseHeaderList: [] as any[],
-      querystring: '',
-      isRequesting: false
-    }
-  },
-
-  watch: {
-    ['mock.query']: {
-      deep: true,
-      handler(query) {
-        query = {
-          ...query
-        }
-
-        // @ts-ignore
-        if (!query.key && this.apiUser.accessKey) {
-          // @ts-ignore
-          query.key = this.apiUser.accessKey
-        }
-
-        for (const key in query) {
-          if (!query[key]) {
-            delete query[key]
-          }
-        }
-
-        this.querystring = qs.stringify(query, {
-          addQueryPrefix: true
-        })
-      }
-    }
-  },
-
-  methods: {
-    resetMock() {
-      const query: any = {}
-
-      // @ts-ignore
-      if (!query.key && this.apiUser.accessKey) {
-        // @ts-ignore
-        query.key = this.apiUser.accessKey
-      }
-
-      this.response = null
-      this.mock = {
-        query: {},
-        body: {}
-      }
-    },
-
-    updateQuery(query) {
-      this.$router.replace({
-        path: this.$route.path,
-        query: {
-          ...this.$route.query,
-          ...query
-        }
-      })
-    },
-
-    async changeApi(id) {
-      this.changeRoute(0)
-
-      if (id) {
-        await this.setCurApi(id)
-        this.updateQuery({
-          api_id: id
-        })
-      }
-    },
-
-    changeRoute(index) {
-      this.resetMock()
-      this.curRoute = this.curApiRoutes[index]
-    },
-
-    notify(message: string) {
-      // @ts-ignore
-      this.$buefy.notification.open({
-        message,
-        type: 'is-danger',
-        position: 'is-top',
-        closable: false
-      })
-    },
-
-    scrollToResponseCont() {
-      responseContEl = responseContEl || this.$refs['response']
-
-      if (responseContEl) {
-        setTimeout(() => {
-          responseContEl.scrollIntoView({
-            behavior: 'smooth'
-          })
-        }, 32)
-      }
-    },
-
-    async setCurApi(id) {
-      const curApi = id && this.apiList ? this.apiList.find((item) => item.api_id === id) : null
-      let apiDoc: any
-
-      this.curApiId = id
-      this.apiDocLoad = false
-
-      if (!curApi) {
-        this.notify('查询接口规范失败')
-        return
-      }
-
-      let doc_path = curApi && curApi.doc_path
-
-      if (!doc_path && curApi.hash_id) {
-        const solution = await getSolution(curApi.hash_id)
-        doc_path = solution.doc_path
-      }
-
-      if (!doc_path) {
-        this.notify('无法获取对应接口规范')
-        return
-      }
-
-      apiDoc = await parseApiDocFile(doc_path)
-
-      if (!apiDoc) {
-        this.notify('对应接口解析异常')
-        return
-      }
-
-      this.curApi = curApi
-      this.curApiRoutes = formatApiDocToRoutes(apiDoc)
-      this.curRoute = this.curApiRoutes[0]
-      this.curRouteIndex = 0
-      this.apiDocLoad = true
-    },
-
-    async send() {
-      // @ts-ignore
-      const { method, url, paramsMap } = this.curRoute || {}
-      const { query, body } = this.mock
-      let res: any
-
-      this.response = null
-      this.isRequesting = true
-
-      try {
-        res = await pumpProxy({
-          query: {
-            action: 'InspectorMock'
-          },
-          body: {
-            url,
-            headers: {
-              'user-agent': navigator.userAgent
-            },
-            method,
-            query: {
-              ...query,
-              // @ts-ignore
-              key: this.apiUser.accessKey
-            },
-            body: !paramsMap || !paramsMap.body || !Object.keys(body).length ? undefined : body
-          }
-        })
-      } catch (e) {
-        console.error(e)
-        this.notify(e.message)
-      }
-
-      this.isRequesting = false
-
-      if (res) {
-        const responseHeaderList: any = []
-
-        if (res.headers) {
-          for (const key in res.headers) {
-            if (key === 'set-cookie') {
-              continue
-            }
-
-            responseHeaderList.push({
-              key,
-              value: res.headers[key]
-            })
-          }
-        }
-
-        this.response = res
-        this.responseHeaderList = responseHeaderList
-        this.scrollToResponseCont()
-      }
-    }
-  },
-
-  async created() {
-    const { query } = this.$route
-    let { api_id = null } = query || {}
-
-    if (!this.$store.state.kaifain.apiUser) {
-      await this.$store.dispatch('apigateway:user:load')
-    }
-
-    if (!this.$store.state.kaifain.apiList || !this.$store.state.kaifain.apiList.length) {
-      await this.$store.dispatch('apigateway:apilist:load')
-    }
-
-    const {
-      apiUser,
-      apiList
-    } = this.$store.state.kaifain
-
-    if (!apiList || !apiList.length) {
-      this.apiListLoad = true
-      return
-    }
-
-    if (!api_id) {
-      api_id = apiList[0].api_id
-      this.updateQuery({
-        api_id
-      })
-    }
-
-    this.apiUser = apiUser
-    this.apiList = apiList
-    this.apiListLoad = true
-
-    await this.setCurApi(api_id)
-  }
-})
-</script>
-
-<style lang="scss">
-$dashboard-bg: #f9f9fa;
-
-.api-inspector {
-  margin-bottom: 2rem;
-
-  .field {
-    .label {
-      font-size: 0.875rem;
-    }
-  }
-
-  .pending-state {
-    .media-content {
-      text-align: center;
-      font-size: 0.875rem;
-      color: #777;
-      padding: 0.5rem;
-    }
-  }
-
-  .notification.is-warning {
-    margin-bottom: 1rem;
-    padding-right: 1rem;
-
-    p {
-      color: inherit;
-    }
-  }
-
-  pre {
-    border-radius: 4px;
-    background: #f3f3f4;
-  }
-
-  code.http {
-    word-break: break-all;
-    white-space: pre-wrap;
-  }
-
-  code.hljs {
-    max-height: 48vh;
-  }
-
-  .column {
-    .tab-content {
-      padding: 1.5rem 0 0 0;
-    }
-  }
-
-  @media screen and (min-width: 768px) {
-    .field {
-      select {
-        min-width: 16rem;
-      }
-    }
-
-    .sticky-bar {
-      position: sticky;
-      top: 52px;
-      background: $dashboard-bg;
-      z-index: 999;
-    }
-  }
-
-  @media screen and (max-width: 480px) {
-    margin-bottom: 5rem;
-
-    .sticky-bar {
-      .field.is-grouped > .control.is-expanded {
-        margin-right: 0;
-      }
-    }
-  }
-}
-</style>

+ 0 - 559
kaifain_v2/pages/dashboard/layout.vue

@@ -1,559 +0,0 @@
-<template lang="pug">
-  .dashboard(:class="{'is-inapp': isInApp}")
-    client-only
-      .sidebar-page
-        .sidebar-layout
-          b-sidebar.brd-sidebar(
-            type="is-dark"
-            :mobile="expanded ? 'fullwidth' : 'reduce'"
-            :position="isInApp ? 'fixed' : 'static'"
-            :reduce="reduce"
-            :fullheight="true"
-            open
-            )
-            .inner
-              .brand(v-if="!isInApp")
-                .logo
-                .text
-                  span Dashboard
-                  sup Beta
-              .navbar-burger.burger(v-else @click="triggerSidebar")
-                span
-                span
-                span
-
-              b-menu.is-custom-mobile
-                b-menu-list
-                  b-menu-item(
-                    label="概览"
-                    icon-pack="progico"
-                    icon="progico-home"
-                    tag="router-link"
-                    to="/dashboard"
-                    :replace="isInApp"
-                    :active="curRoutePath === '/'"
-                    @click.native="onMenuClick"
-                    )
-                  b-menu-item(
-                    label="我的API"
-                    icon-pack="progico"
-                    icon="progico-api"
-                    tag="router-link"
-                    to="/dashboard/apis"
-                    :replace="isInApp"
-                    :active="curRoutePath === '/apis'"
-                    @click.native="onMenuClick"
-                    )
-                  //- b-menu-item(
-                    label="统计中心"
-                    icon-pack="progico"
-                    icon="progico-stats"
-                    tag="router-link"
-                    to="/dashboard/stats"
-                    :replace="isInApp"
-                    :active="curRoutePath === '/stats'"
-                    @click.native="onMenuClick"
-                    )
-                  b-menu-item(
-                    label="调试工具"
-                    icon-pack="progico"
-                    icon="progico-debug"
-                    tag="router-link"
-                    to="/dashboard/inspector"
-                    :replace="isInApp"
-                    :active="curRoutePath === '/inspector'"
-                    @click.native="onMenuClick"
-                    )
-
-          .dashboard-container
-            b-navbar(v-if="!isInApp")
-              template(slot="end")
-                b-navbar-item(href="/") 返回首页
-                .navbar-split
-                NavUserCell(
-                  v-if="userInfo"
-                  :user-info="userInfo"
-                  :clickable="false"
-                  )
-
-            router-view.dashboard-main
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import NavUserCell from '../../components/NavUserCell.vue'
-import bridge from '../../utils/bridge'
-
-export default Vue.extend({
-  layout: 'kaifain_v2',
-  components: {
-    NavUserCell
-  },
-
-  data() {
-    return {
-      reduce: false,
-      isInApp: false,
-      expanded: false
-    }
-  },
-
-  head: {
-    title: '控制台'
-  },
-
-  computed: {
-    userInfo(): any {
-      return this.$store.state.userinfo
-    },
-
-    curRoutePath(): string {
-      return this.$route.path.replace(/^\/dashboard\/?/, '/')
-    }
-  },
-
-  methods: {
-    triggerSidebar() {
-      this.expanded = !this.expanded
-    },
-
-    onMenuClick() {
-      if (this.expanded) {
-        setTimeout(() => {
-          this.expanded = false
-        }, 32)
-      }
-    }
-  },
-
-  created() {
-    if (process.client) {
-      // @ts-ignore
-      this.isInApp = bridge.isInApp || false
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-@import '../../assets/styles/vars';
-
-$dashboard-bg: #f9f9fa;
-
-.dashboard {
-  background: $dashboard-bg;
-
-  .page-header {
-    margin: -1.25rem 0.25rem 2rem 0.25rem;
-
-    .title {
-      font-size: 1.5rem;
-      margin: 0 !important;
-    }
-
-    .actions {
-      margin-bottom: -0.25rem;
-    }
-  }
-
-  .modal {
-    z-index: 42;
-  }
-
-  .sidebar-page {
-    display: flex;
-    flex-direction: column;
-    width: 100%;
-    min-height: 100%;
-
-    .sidebar-layout {
-      display: flex;
-      flex-direction: row;
-      min-height: 100%;
-    }
-  }
-
-  .navbar {
-    background: $dashboard-bg;
-    color: #777;
-    position: sticky;
-    top: 0;
-  }
-
-  .navbar-end {
-    padding-right: 1rem;
-  }
-
-  .navbar-item {
-    font-size: 0.875rem;
-    color: #777;
-  }
-
-  .navbar-split {
-    background: #e7e7e7;
-    width: 1px;
-    height: 16px;
-    margin: 1px 12px 0;
-    align-self: center;
-  }
-
-  .dashboard-container {
-    flex: 1;
-    overflow-y: scroll;
-    height: 100vh;
-  }
-
-  .dashboard-main {
-    padding: 2rem;
-  }
-
-  .section {
-    padding: 0;
-  }
-
-  .card {
-    background: #fff;
-    border-radius: 6px;
-    box-shadow: 0 1px 6px rgba(0,0,0,0.02);
-
-    .header {
-      padding: 1.5rem;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-
-      + .content {
-        padding-top: 0;
-      }
-    }
-
-    .caption {
-      color: $ink;
-      font-size: 1rem;
-      font-weight: 500;
-    }
-
-    .content {
-      padding: 1.5rem 1.5rem 2rem;
-      min-height: 6rem;
-
-      > .empty {
-        font-size: 0.875rem;
-        color: #999;
-        text-align: center;
-        padding: 1.5rem;
-      }
-
-      .is-link {
-        color: $primary;
-      }
-    }
-
-    .view-all {
-      color: #999;
-      font-size: 0.875rem;
-      padding: 1rem 1.75rem;
-      display: flex;
-      align-items: center;
-      border-top: 1px solid #eee;
-
-      .icon {
-        font-size: 0.8em;
-      }
-
-      &:hover {
-        color: $primary;
-      }
-    }
-  }
-
-  .api-list {
-    padding: 0 1.5rem;
-  }
-
-  .common-table {
-    .table {
-      font-size: 0.875rem;
-      line-height: 1.35;
-
-      td,
-      th {
-        vertical-align: middle;
-      }
-
-      th {
-        padding: 0.75em 1em;
-        border-bottom: 1px solid #eaeaea;
-      }
-
-      td {
-        padding: 0.5em 1em;
-        border-color: #f6f6f6;
-
-        &::before {
-          white-space: nowrap;
-          margin-right: 1rem;
-        }
-      }
-
-      .control {
-        padding-right: 1.5rem;
-      }
-    }
-
-    .skeleton-cell {
-      padding: 0.5rem 0;
-    }
-
-    .empty {
-      text-align: center;
-      color: #8c8c8c;
-      padding: 1rem;
-    }
-
-    .key {
-      color: #777;
-    }
-
-    .value {
-      word-break: break-all;
-    }
-
-    .desc {
-      font-size: 0.9em;
-      color: #777;
-      padding-bottom: 0.5em;
-      display: inline-block;
-      word-break: break-all;
-    }
-  }
-
-  &.is-inapp {
-    .page-header {
-      .title {
-        display: none;
-      }
-    }
-
-    .dashboard-container {
-      padding-left: 56px;
-    }
-  }
-
-  @media screen and (max-width: 1023px) {
-    .navbar-menu {
-      background: $dashboard-bg;
-      box-shadow: none;
-    }
-
-    .navbar-split {
-      height: 1px;
-      width: auto;
-      margin: 8px 12px;
-    }
-  }
-
-  @media screen and (max-width: 768px) {
-    .b-table .table-wrapper.has-mobile-cards {
-      .control {
-        width: 66%;
-      }
-
-      tr {
-        border-radius: 4px;
-        box-shadow: 0 1px 6px rgba(51, 49, 49, 0.03);
-      }
-    }
-
-    .common-table .table {
-      .control {
-        padding-right: 0;
-      }
-    }
-
-    .dashboard-main {
-      padding: 0.25rem 0.25rem 2rem;
-    }
-
-    .page-header {
-      margin: -0.25rem 1.25rem 1.5rem 1.25rem;
-    }
-
-    .card {
-      .header {
-        padding-top: 1.25rem;
-        padding-bottom: 1.25rem;
-      }
-
-      .header,
-      .content {
-        padding-left: 1rem;
-        padding-right: 1rem;
-      }
-
-      .caption {
-        font-size: 0.9375rem;
-      }
-    }
-  }
-
-  @media screen and (max-width: 480px) {
-    .is-float-btn {
-      position: fixed;
-      z-index: 30;
-      bottom: 0.5rem;
-      right: 16px;
-      width: calc(100% - 88px);
-    }
-
-    .api-list {
-      padding: 0 1.25rem;
-    }
-
-    .modal {
-      justify-content: flex-start;
-    }
-
-    &.is-inapp {
-      .page-header {
-        margin: 0;
-      }
-    }
-  }
-}
-
-.b-sidebar.brd-sidebar {
-  .sidebar-content {
-    width: 240px;
-
-    > .inner {
-      padding: 1em;
-    }
-
-    .navbar-burger {
-      color: #fff;
-      margin: -0.75rem -0.2rem 0.25rem -0.2rem;
-    }
-
-    &.is-dark {
-      background: $ink;
-      box-shadow: none;
-    }
-
-    &.is-fixed {
-      transition: width 0.25s ease;
-    }
-  }
-
-  .menu-list {
-    a {
-      margin-bottom: 0.5rem;
-      padding: 0.75em 0.875em;
-      color: #808080;
-      white-space: nowrap;
-
-      &.is-active {
-        background: $primary;
-        color: #fff;
-      }
-    }
-
-    .icon + span {
-      margin-left: 1rem;
-      font-size: 0.9375rem;
-    }
-  }
-
-  .brand {
-    display: flex;
-    align-items: center;
-    color: #fff;
-    margin: 0 0.5rem 2rem;
-
-    .logo {
-      background: url('../../assets/img/logo.png') center left no-repeat;
-      background-size: auto 100%;
-      width: 34px;
-      height: 34px;
-      opacity: 0.98;
-    }
-
-    .text {
-      font-weight: 600;
-      margin-left: 16px;
-
-      sup {
-        font-size: 0.625em;
-        font-weight: 500;
-        vertical-align: top;
-        margin: 0 -5px 0 5px;
-        color: lighten($primary, 4);
-        display: inline-block;
-        top: 0;
-      }
-    }
-  }
-
-  @media screen and (max-width: 768px) {
-    .sidebar-content {
-      > .inner {
-        padding-left: 0.375rem;
-        padding-right: 0.375rem;
-      }
-
-      &.is-fullwidth-mobile {
-        width: 224px;
-      }
-
-      &.is-mini-mobile {
-        width: 56px;
-
-        .brand {
-          margin: 0 0 1.5rem;
-          justify-content: center;
-
-          .logo {
-            width: 32px;
-            height: 32px;
-          }
-
-          .text {
-            display: none;
-          }
-        }
-
-        &:not(.is-mini-expanded),
-        &.is-mini-expanded:not(:hover) {
-          .menu-list {
-            li {
-              a {
-                text-align: center;
-                padding: 0.75em 0.5em;
-
-                span:nth-child(2) {
-                  display: none;
-                }
-              }
-
-              ul {
-                padding-left: 0;
-
-                li {
-                  a {
-                    display: inline-block;
-                  }
-                }
-              }
-            }
-          }
-
-          .menu-label:not(:last-child) {
-            margin-bottom: 0;
-          }
-        }
-      }
-    }
-  }
-}
-</style>

+ 0 - 240
kaifain_v2/pages/dashboard/sms/templates.vue

@@ -1,240 +0,0 @@
-<template lang="pug">
-  .sms-templates-panel
-    .content
-      .page-header
-        .level
-          .level-left
-              h1.title 短信模板管理
-          .level-right
-            .actions
-              b-button.is-primary.is-float-btn(
-                icon-pack="progico"
-                icon-left="progico-plus-o"
-                @click="modalVisible = true"
-                ) 新增模板
-
-      .columns
-        .column
-          b-table.common-table(
-            v-if="list"
-            :is-striped="true"
-            placeholder="还没有短信模板"
-            )
-            b-table-column(
-              width="80px"
-              field="id"
-              label="模板ID"
-              v-slot="props"
-              ) {{ props.row.id }}
-
-            b-table-column(
-              field="content"
-              label="模板内容"
-              v-slot="props"
-              ) {{ props.row.content }}
-
-            b-table-column(
-              width="128px"
-              field="addtime"
-              label="创建时间"
-              v-slot="props"
-              ) {{ formatTime(props.row.addtime * 1000, 'yyyy-MM-dd hh:mm') }}
-
-            b-table-column(
-              width="96px"
-              field="status"
-              label="审核状态"
-              v-slot="props"
-              )
-                .tag(v-if="props.row.status === 0") 待审核
-                .tag.is-success(v-if="props.row.status === 1") 审核通过
-
-            b-table-column(
-              width="96px"
-              field="actions"
-              label="操作"
-              v-slot="props"
-              )
-                button.button.is-small(@click="confirmToDeleteTmpl(props.row, props.index)") 删除
-
-            .empty(slot="empty") 还没有短信模板
-
-    b-modal(
-      v-model="modalVisible"
-      has-modal-card
-      trap-focus
-      :destroy-on-hide="false"
-      aria-role="dialog"
-      aria-modal
-      )
-        .modal-card
-          header.modal-card-head
-            p.modal-card-title 创建短信模板
-            button.delete(type="button" @click="closeModal")
-
-          section.modal-card-body
-            b-field(label="短信签名")
-              b-input(
-                v-model="formProps.signature"
-                placeholder="如公司名或品牌名称,3-6个字符"
-                required
-                )
-            b-field(label="模板内容")
-              b-input(
-                v-model="formProps.content"
-                placeholder="如需传入变量,请使用@符号作为占位符"
-                type="textarea"
-                maxlength="140"
-                required
-                )
-
-          footer.modal-card-foot
-            button.button(type="button" @click="closeModal") 取消
-            button.button.is-primary(@click="createTmpl") 创建
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import { formatTime } from 'proginn-lib'
-import { listUserSMSTemplates, createSMSTemplate, deleteSMSTemplate } from '../../../apis/apigateway'
-
-export default Vue.extend({
-  name: 'SMSTemplates',
-
-  layout: 'kaifain_v2',
-
-  data() {
-    return {
-      list: [] as any[],
-      modalVisible: false,
-      formProps: {
-        signature: '',
-        content: ''
-      }
-    }
-  },
-
-  async created() {
-    console.info('@templates:asyncData')
-    let list: any[]
-
-    try {
-      list = await listUserSMSTemplates()
-    } catch (e) {
-      if (e.status === -99) {
-        console.warn(e)
-        return
-      } else {
-        throw e
-      }
-    }
-
-    this.list = list
-  },
-
-  methods: {
-    formatTime,
-
-    closeModal() {
-      this.modalVisible = false
-    },
-
-    async createTmpl() {
-      const form = {
-        name: Math.random().toString(16).substr(2),
-        signature: this.formProps.signature,
-        content: this.formProps.content
-      }
-
-      try {
-        await createSMSTemplate(form)
-      } catch (e) {
-        // @ts-ignore
-        this.$buefy.notification.open({
-          message: e.message,
-          type: 'is-danger',
-          position: 'is-top',
-          closable: false
-        })
-      }
-
-      this.closeModal()
-
-      // @ts-ignore
-      this.list.unshift({
-        ...form,
-        addtime: Math.floor(Date.now() / 1000)
-      })
-
-      // @ts-ignore
-      this.$buefy.notification.open({
-        message: '模板创建成功!请等待审核',
-        type: 'is-success',
-        position: 'is-top',
-        closable: false
-      })
-    },
-
-    async deleteTmpl(item, idx) {
-      try {
-        await deleteSMSTemplate({
-          accountid: item.accountid,
-          template_id: item.id
-        })
-      } catch (e) {
-        // @ts-ignore
-        this.$buefy.notification.open({
-          message: e.message,
-          type: 'is-danger',
-          position: 'is-top',
-          closable: false
-        })
-      }
-
-      // @ts-ignore
-      this.list.splice(idx, 1)
-
-      // @ts-ignore
-      this.$buefy.notification.open({
-        message: '删除模板成功!',
-        type: 'is-success',
-        position: 'is-top',
-        closable: false
-      })
-    },
-
-    async confirmToDeleteTmpl(item, idx) {
-      // @ts-ignore
-      this.$buefy.dialog.confirm({
-        title: '删除短信模板',
-        message: `<p>你确定要<b>删除</b>此条短信模板吗?该操作无法撤销,请谨慎处理。<p><br><p>${item.content}</p>`,
-        cancelText: '取消',
-        confirmText: '确认删除',
-        type: 'is-danger',
-        hasIcon: false,
-        onConfirm: async () => await this.deleteTmpl(item, idx)
-      })
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.sms-templates-panel {
-
-  .template-table .table {
-    font-size: 0.875rem;
-  }
-
-  .modal-card {
-    width: auto;
-  }
-
-  @media screen and (min-width: 768px) {
-    .modal-card {
-      width: 480px;
-    }
-  }
-}
-</style>

+ 0 - 269
kaifain_v2/pages/index.vue

@@ -1,269 +0,0 @@
-<template lang="pug">
-  .view.home
-    Topnav(
-      :fixed="topnavFixed"
-      @publish-click="connectPopupVisible = true"
-      )
-    Carousel(:list="bannerList")
-    SearchBox(
-      :hot-keywords="hotKeywords"
-      @publish-click="connectPopupVisible = true"
-      )
-    CategoryNav(
-      :classes="classes"
-      :service-types="serviceTypes"
-      :top-cat-id.sync="topCatId"
-      :cat-id.sync="catId"
-      :service-type.sync="serviceType"
-      )
-    .main
-      Toolbar(
-        :cities="cities"
-        :city-id.sync="cityId"
-        :sort-type.sync="sortType"
-        :is-choice.sync="isChoice"
-        )
-        .result-msg(
-          v-if="!isMobile && (catName || topCatName)"
-          slot="right"
-          )
-          h1 {{(catName || topCatName).replace(/方案$/, '')}}解决方案
-          .total  ({{solutionList.length}})
-      #solution-list.list.container.is-content
-        SolutionCell(
-          v-for="row in solutionList"
-          :key="row.hash_id"
-          :data="row"
-          )
-      Pagination(
-        path="/page/"
-        mode="params"
-        :page="page || 1"
-        :total="solutionTotal"
-        )
-
-    KaifainFooter(:data="footer")
-    ConnectUs(
-      source="开发屋"
-      :isShowToast="connectPopupVisible"
-      @close="connectPopupVisible = false"
-      )
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import Topnav from '../components/Topnav.vue'
-import Carousel from '../components/Carousel.vue'
-import SearchBox from '../components/SearchBox.vue'
-import CategoryNav from '../components/CategoryNav.vue'
-import Toolbar from '../components/Toolbar.vue'
-import SolutionCell from '../components/SolutionCell.vue'
-import Pagination from '../components/Pagination.vue'
-import { listBanners, listSearchKeywords, getInitParameters } from '../apis/common'
-import { listSolutions } from '../apis/solution'
-import { SolutionListMixin } from '../mixins/solution'
-import { parseCatIdAndServiceType, genCatIdSearchSentence, scrollToElement } from '../utils/misc'
-import { genDocumentHeadData, genDocumentFooterData } from '../helpers/seoHelper'
-
-import ConnectUs from '@/components/common/connectUsKaifain.vue'
-import KaifainFooter from '@/components/SeoFooter.vue'
-
-export default SolutionListMixin.extend({
-  name: 'Home',
-  components: {
-    Topnav,
-    Carousel,
-    SearchBox,
-    CategoryNav,
-    Toolbar,
-    SolutionCell,
-    Pagination,
-    ConnectUs,
-    KaifainFooter
-  },
-
-  scrollToTop: false,
-  layout: 'kaifain_v2',
-
-  data() {
-    return {
-      topnavFixed: false,
-      connectPopupVisible: false,
-      topCatName: '',
-      catName: '',
-      // @ts-ignore
-      isMobile: this.$deviceType.isMobile()
-    }
-  },
-
-  head() {
-    const { title, keywords, description, canonical } = genDocumentHeadData({
-      ctx: this.$ssrContext,
-      catName: this.catName || this.topCatName
-    })
-
-    return {
-      title,
-      meta: [{
-        name: 'keywords',
-        content: keywords,
-      },
-      {
-        name: 'description',
-        content: description
-      }],
-      link: canonical ? [{
-        rel: 'canonical',
-        href: canonical
-      }] : undefined
-    }
-  },
-
-  async asyncData(ctx: any) {
-    const { app, store, params, query, error } = ctx
-    let {
-      page = 0,
-      cat_id,
-      pathMatch
-    } = params as any
-    const {
-      sort = 0,
-      city_id,
-      pid,
-      is_choice,
-      st
-    } = query as any
-
-    // TODO: temporarily fixed
-    if (pathMatch && (!page || !cat_id)) {
-      const matchedPage = /^\/page\/(\d+)$/.exec(pathMatch)
-      const matchedCatId = !matchedPage && /^\/c\/([0-9a-z]{8,12})$/.exec(pathMatch)
-
-      if (matchedPage) {
-        page = ~~matchedPage[1]
-      } else if (matchedCatId) {
-        cat_id = matchedCatId[1]
-      }
-    }
-
-    if (!store.state.kaifain.inited) {
-      await store.dispatch('parameters:load')
-      await store.dispatch('banners:load')
-      await store.dispatch('hotKeywords:load')
-    }
-
-    const {
-      cities,
-      classes,
-      serviceTypes,
-      bannerList,
-      hotKeywords
-    } = store.state.kaifain
-
-    const {
-      topCatId,
-      topCatName,
-      catId,
-      catName,
-      serviceType,
-      matchedCatIds
-    } = parseCatIdAndServiceType({
-      cat_id,
-      st,
-      classes,
-      serviceTypes
-    })
-
-    const solutionRes = await listSolutions({
-      cat_id: genCatIdSearchSentence(matchedCatIds, serviceType),
-      sort,
-      city_id,
-      uid: pid,
-      is_choice: is_choice ? 1 : undefined,
-      page: ~~page || 1,
-      size: 10
-    })
-
-    if (!solutionRes) {
-      throw error({ statusCode: 404, message: 'Post not found (no data)' })
-    }
-
-    const footer = genDocumentFooterData({
-      ctx,
-      classes,
-      topCatId,
-      subCatId: catId
-    })
-
-    return {
-      page: ~~page,
-      sortType: ~~sort,
-      topCatId,
-      topCatName,
-      catId,
-      catName,
-      serviceType,
-      cityId: city_id || null,
-      isChoice: !!is_choice || false,
-      bannerList,
-      hotKeywords,
-      cities,
-      classes,
-      serviceTypes,
-      solutionList: solutionRes.list || [],
-      solutionTotal: ~~solutionRes.total,
-      footer
-    }
-  },
-
-  methods: {
-    onScroll() {
-      // @ts-ignore
-      this.topnavFixed = window.scrollY > 560
-    }
-  },
-
-  mounted() {
-    // @ts-ignore
-    window.addEventListener('scroll', this.onScroll)
-
-    // @ts-ignore
-    if (this.page) {
-      this.$nextTick(() => {
-        scrollToElement('#st-mark')
-      })
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.kaifain-view {
-  .home {
-    .main {
-      min-height: 480px;
-
-      .result-msg {
-        color: #777;
-        font-size: 0.75rem;
-        font-weight: 400;
-        margin: 0 1rem 0 0;
-
-        > * {
-          display: inline-block;
-        }
-
-        .total {
-          margin-left: 4px;
-        }
-      }
-
-      h1 {
-        font-size: inherit;
-        font-weight: inherit;
-      }
-    }
-  }
-}
-</style>

+ 0 - 182
kaifain_v2/pages/search.vue

@@ -1,182 +0,0 @@
-<template lang="pug">
-  .view.search-result#view
-    Topnav(
-      :q="q"
-      :fixed="topnavFixed"
-      @search-change="onSearchChange"
-      @publish-click="connectPopupVisible = true"
-      )
-    .main
-      Toolbar(
-        :cities="cities"
-        :city-id.sync="cityId"
-        :sort-type.sync="sortType"
-        :is-choice.sync="isChoice"
-        )
-      .container.is-content
-        .hits-msg 为您找到 {{solutionTotal}} 个 "{{q}}" 解决方案
-      #solution-list.list.container.is-content
-        SolutionCell(
-          v-for="row in solutionList"
-          :key="row.hash_id"
-          :data="row"
-          )
-      Pagination(
-        mode="query"
-        :page="page || 1"
-        :total="solutionTotal"
-        )
-
-    KaifainFooter(:data="footer")
-    ConnectUs(
-      source="开发屋-搜索"
-      :isShowToast="connectPopupVisible"
-      @close="connectPopupVisible = false"
-      )
-
-</template>
-
-<script lang="ts">
-import Vue from 'vue'
-import Topnav from '../components/Topnav.vue'
-import Carousel from '../components/Carousel.vue'
-import SearchBox from '../components/SearchBox.vue'
-import CategoryNav from '../components/CategoryNav.vue'
-import Toolbar from '../components/Toolbar.vue'
-import SolutionCell from '../components/SolutionCell.vue'
-import Pagination from '../components/Pagination.vue'
-import { listBanners, listSearchKeywords, getInitParameters } from '../apis/common'
-import { listSolutions } from '../apis/solution'
-import { SolutionListMixin } from '../mixins/solution'
-import { scrollToElement } from '../utils/misc'
-import { genDocumentFooterData } from '../helpers/seoHelper'
-
-import ConnectUs from '@/components/common/connectUsKaifain.vue'
-import KaifainFooter from '@/components/SeoFooter.vue'
-
-export default SolutionListMixin.extend({
-  name: 'Search',
-  components: {
-    Topnav,
-    Carousel,
-    SearchBox,
-    CategoryNav,
-    Toolbar,
-    SolutionCell,
-    Pagination,
-    ConnectUs,
-    KaifainFooter
-  },
-
-  layout: 'kaifain_v2',
-
-  head() {
-    return {
-      title: `${this.q} - 开发屋搜索`
-    }
-  },
-
-  data() {
-    return {
-      topnavFixed: true,
-      connectPopupVisible: false
-    }
-  },
-
-  watch: {
-    ['$route.query.page'](val) {
-      if (val) {
-        this.getSolutionList({
-          page: ~~val,
-          updateUrl: false
-        })
-          .then(() => {
-            scrollToElement('#view')
-          })
-      }
-    }
-  },
-
-  async asyncData(ctx: any) {
-    const { store, query, error } = ctx
-    const {
-      q = '',
-      page = 0,
-      sort = 0,
-      city_id,
-      pid,
-      is_choice
-    } = query as any
-
-    if (!store.state.kaifain.inited) {
-      await store.dispatch('parameters:load')
-    }
-
-    const { cities, classes, serviceTypes } = store.state.kaifain
-    const solutionRes = await listSolutions({
-      cat_id: undefined,
-      q,
-      sort,
-      city_id,
-      uid: pid,
-      is_choice: is_choice ? 1 : undefined,
-      page: ~~page || 1,
-      size: 10
-    })
-
-    if (!solutionRes) {
-      throw error({ statusCode: 404, message: 'Post not found (no data)' })
-    }
-
-    const footer = genDocumentFooterData({
-      ctx,
-      classes
-    })
-
-    return {
-      q,
-      page: ~~page,
-      sortType: ~~sort,
-      cityId: city_id || null,
-      isChoice: !!is_choice || false,
-      cities,
-      classes,
-      serviceTypes,
-      solutionList: solutionRes.list || [],
-      solutionTotal: ~~solutionRes.total,
-      footer
-    }
-  },
-
-  methods: {
-    async onSearchChange(val) {
-      if (!val) {
-        return
-      }
-
-      this.q = val
-      await this.getSolutionList({
-        reset: true
-      })
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-.kaifain-view {
-  .search-result {
-    .main {
-      padding-top: 54px;
-      min-height: 720px;
-    }
-
-    .hits-msg {
-      color: #444;
-      font-size: 0.8125rem;
-      font-weight: 500;
-      padding: 1.25rem 0.75rem 0.75rem;
-    }
-  }
-}
-</style>

+ 0 - 664
kaifain_v2/pages/solution.vue

@@ -1,664 +0,0 @@
-<template lang="pug">
-  .view.solution-page
-    link(href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet")
-    Topnav(
-      :fixed="true"
-      :show-publish="false"
-      :show-search="topnavFunctional"
-      @publish-click="connectPopupVisible = true"
-      )
-
-    .summary(
-      v-if="data"
-      ref="summary"
-      )
-      .container.is-content.is-wide
-        .columns
-          .column.left
-            .cover
-              img(:src="data.images")
-          .column
-            .info
-              h1.title {{data.title}}
-              .extends
-                .tag.is-choice(v-if="data.is_choice == 1") 优选
-                .tag.is-link.is-light(v-if="data.type === 'gateway'") API
-                .tag.is-success.is-light(v-if="data.type === 'gateway'") HTTPS
-                span
-                  a.link(:href="`${siteUrl}/company/${data.uid}`") 服务商: {{data.company_info && data.company_info.name}}
-
-              //- desc
-              .desc(v-if="data.type === 'gateway' && data.is_signing == 1 && data.source == 5" v-html="data.description")
-              .desc(v-else) {{data.description}}
-
-              //- skus
-              .skus(v-if="skus")
-                .item(
-                  v-for="item in skus"
-                  :class="{cur: curSkuId === item.id, disabled: item.overlimit}"
-                  @click="changeSku(item)"
-                  ) {{item.label}}
-              .price(v-if="skus && curSkuId && skuMap[curSkuId]")
-                span.symbol ¥
-                span.value {{formatPrice(skuMap[curSkuId].price)}}
-                span.explain(v-show="!!skuMap[curSkuId].quota")  / {{Number(skuMap[curSkuId].quota).toLocaleString()}} {{skuMap[curSkuId].unit}}
-
-              .action
-                .button.is-primary.is-rounded(
-                  v-if="skus"
-                  @click="purchase") {{curSkuId && skuMap[curSkuId] && skuMap[curSkuId].price == 0 ? '免费开通' : '立即购买'}}
-                .button.is-primary.is-rounded(
-                  v-else
-                  @click="connectPopupVisible = true") 了解咨询
-
-    .page-nav
-      .container.is-content.is-wide
-        .tabs
-          ul
-            li(
-              v-for="(item, i) in navItems"
-              :class="{'is-active': curNavIndex === i}"
-              )
-              a(@click="changeNavTab(item.id, i)") {{item.label}}
-
-    .main
-      .container.is-content.is-wide(v-if="data")
-        .paper.columns
-          .column.is-9
-            .main-cont
-              //- api doc
-              ApiDoc#apidoc(
-                v-if="apiDoc"
-                :data="apiDoc"
-                v-observe-visibility="visibilityChanged"
-                )
-
-              //- details: aliyun
-              .details#details(
-                v-if="data.source == 2"
-                :class="detailsClass"
-                v-observe-visibility="visibilityChanged"
-                )
-                .d-item.rich-text(v-html="data.detail")
-              .details#details(
-                v-else
-                :class="detailsClass"
-                v-html="data.detail"
-                v-observe-visibility="visibilityChanged"
-                )
-
-              .case-list#case(v-if="data.successful_case")
-                .caption.bordered 成功案例
-                CaseCell(
-                  :solution-title="data.title"
-                  :data="data.successful_case"
-                  )
-
-          .column.is-3
-            .side-cont
-              .rcmd-list(v-if="providerSolutionList && providerSolutionList.length")
-                .caption 同服务商产品
-                SideSolutionCell.item(
-                  v-for="item in providerSolutionList"
-                  :key="item.hash_id"
-                  :data="item"
-                  )
-              .rcmd-list(v-if="relatedSolutionList && relatedSolutionList.length")
-                .caption 相似方案推荐
-                SideSolutionCell.item(
-                  v-for="item in relatedSolutionList"
-                  :key="item.hash_id"
-                  :data="item"
-                  )
-
-    KaifainFooter(:data="footer")
-    ConnectUs(
-      source="开发屋详情"
-      :isShowToast="connectPopupVisible"
-      @close="connectPopupVisible = false"
-      :sourceId="this.data && this.data.id"
-      )
-</template>
-
-<script lang="ts">
-import 'quill/dist/quill.core.css'
-import 'quill/dist/quill.snow.css'
-import Vue from 'vue'
-import Topnav from '../components/Topnav.vue'
-import { getSolution, listProviderSolution, listRelatedSolution } from '../apis/solution'
-import { genDocumentFooterData } from '../helpers/seoHelper'
-import SideSolutionCell from '../components/SideSolutionCell.vue'
-import CaseCell from '../components/CaseCell.vue'
-import ApiDoc from '../components/ApiDoc.vue'
-import ConnectUs from '@/components/common/connectUsKaifain.vue'
-import KaifainFooter from '@/components/SeoFooter.vue'
-import { formatPrice } from '../utils/misc'
-import { parseApiDocFile } from '../helpers/apiDocHelper'
-import { ObserveVisibility } from 'vue-observe-visibility'
-import { MAIN_ENDPOINT, DASHBOARD_SCENE_CODE } from '../constant'
-
-Vue.directive('observe-visibility', ObserveVisibility)
-
-export default Vue.extend({
-  name: 'Solution',
-  components: {
-    Topnav,
-    SideSolutionCell,
-    CaseCell,
-    ApiDoc,
-    ConnectUs,
-    KaifainFooter
-  },
-
-  layout: 'kaifain_v2',
-
-  head() {
-    // @ts-ignore
-    const { title = '' } = this.data || {}
-
-    return {
-      title: title ? `${title}介绍,功能,开发解决方案-开发屋` : '开发屋-开发解决方案',
-      meta: [
-        {
-          name: 'keywords',
-          content: title,
-        },
-        {
-          name: 'description',
-          content: `${title}详细介绍,包括不限于功能、接口、企业开发着对接和布局${title}的方法和详细的开发文档说明。`,
-        },
-        {
-          name: 'h1',
-          content: `${title}`,
-        }
-      ]
-    }
-  },
-
-  data() {
-    return {
-      topnavFunctional: false,
-      connectPopupVisible: false,
-      data: {},
-      curSkuId: null,
-      curNavIndex: 0,
-      primaryBtnOffsetY: 300,
-      cacheNavElMap: {}
-    }
-  },
-
-  computed: {
-    siteUrl(): string {
-      return this.$store.state.domainConfig.siteUrl
-    },
-
-    skus(): any[] | null {
-      // @ts-ignore
-      return this.data && this.data.is_signing == 1 && this.data.skus && this.data.skus.length ? this.data.skus.filter(item => !item.label.startsWith('test')).sort((a, b) => a.price - b.price) : null
-    },
-
-    skuMap() {
-      // @ts-ignore
-      return this.skus && this.skus.reduce((map, item) => {
-        map[item.id] = item
-        return map
-      }, {}) || {}
-    },
-
-    detailsClass() {
-      // @ts-ignore
-      const source = Number(this.data && this.data.source) || 0
-
-      switch (source) {
-        // aliyun
-        case 2:
-          return 'r-product-detail'
-
-        // tencent
-        case 3:
-          return 'mp__productguide-bd'
-
-        // huawei
-        case 4:
-          return 'detail-description-content product-description'
-
-        default:
-          return 'ql-editor'
-      }
-    }
-  },
-
-  async asyncData(ctx: any) {
-    const headers = ctx.req && {
-      cookie: ctx.req.headers.cookie
-    }
-    const data = await getSolution(ctx.params.id, { headers })
-
-    if (!data) {
-      return
-    }
-
-    let relatedSolutionList!: any[]
-    let apiDoc!: any
-
-    if (data.tags_ids && data.tags_ids !== '[]') {
-      relatedSolutionList = await listRelatedSolution({
-        tags_ids: data.tags_ids,
-        hash_id: data.hash_id,
-        size: 5
-      }, { headers })
-    }
-
-    const providerSolutionList = await listProviderSolution({
-      uid: data.uid,
-      hash_id: data.hash_id,
-      page: 1,
-      size: relatedSolutionList && relatedSolutionList.length ? 3 : 5
-    }, { headers })
-
-    // parse api doc
-    if (data.doc_path) {
-      apiDoc = await parseApiDocFile(data.doc_path)
-    }
-
-    if (!ctx.store.state.kaifain.inited) {
-      await ctx.store.dispatch('parameters:load')
-    }
-
-    const { classes } = ctx.store.state.kaifain
-
-    const footer = genDocumentFooterData({
-      ctx,
-      classes
-    })
-
-    const navItems = [{
-      id: 'details',
-      label: '产品介绍'
-    }]
-
-    if (apiDoc) {
-      navItems.unshift({
-        id: 'apidoc',
-        label: 'API文档'
-      })
-    }
-
-    if (data.successful_case) {
-      navItems.push({
-        id: 'case',
-        label: '成功案例'
-      })
-    }
-
-    return {
-      data,
-      providerSolutionList,
-      relatedSolutionList,
-      apiDoc,
-      footer,
-      navItems
-    }
-  },
-
-  methods: {
-    formatPrice,
-
-    changeNavTab(id, idx) {
-      // @ts-ignore
-      this.curNavIndex = idx
-      // @ts-ignore
-      let el = this.cacheNavElMap[id]
-
-      if (!el) {
-        el = document.querySelector(`#${id}`)
-        // @ts-ignore
-        this.cacheNavElMap[id] = el
-      }
-
-      if (el) {
-        el.scrollIntoView({
-          behavior: 'smooth'
-        })
-      }
-    },
-
-    changeSku(sku) {
-      if (sku.overlimit) {
-        return
-      }
-
-      // @ts-ignore
-      this.curSkuId = sku.id
-    },
-
-    getIndexByNavId(id: string, previous: boolean) {
-      // @ts-ignore
-      for (let i = 0, len = this.navItems.length; i < len; i++) {
-        // @ts-ignore
-        if (this.navItems[i].id === id) {
-          return previous ? Math.min(i - 1, 0) : i
-        }
-      }
-
-      return null
-    },
-
-    visibilityChanged(isVisible: boolean, { target }) {
-      // @ts-ignore
-      const idx = this.getIndexByNavId(target.id, !isVisible)
-
-      if (idx != null) {
-        // @ts-ignore
-        this.curNavIndex = idx
-      }
-    },
-
-    purchase() {
-      // @ts-ignore
-      window.location.href = `${MAIN_ENDPOINT}/pay?product_type=14&product_id=${this.curSkuId}&number=1&next=${encodeURIComponent('/kaifain/dashboard?scene=' + DASHBOARD_SCENE_CODE.PAID)}`
-    },
-
-    onScroll() {
-      // @ts-ignore
-      this.topnavFunctional = window.scrollY > (this.primaryBtnOffsetY || 300)
-    }
-  },
-
-  mounted() {
-    // @ts-ignore
-    window.addEventListener('scroll', this.onScroll)
-
-    this.$nextTick(() => {
-      const el = this.$refs['summary']
-
-      if (el) {
-        // @ts-ignore
-        const rect = el.getBoundingClientRect()
-        // @ts-ignore
-        this.primaryBtnOffsetY = rect.height - 80
-      }
-
-      // @ts-ignore
-      this.onScroll()
-    })
-  },
-
-  destroyed() {
-    // @ts-ignore
-    window.removeEventListener('scroll', this.onScroll)
-  },
-
-  created() {
-    // @ts-ignore
-    if (this.skus) {
-      // @ts-ignore
-      const availableSku = this.skus.find((item) => !item.overlimit)
-
-      if (availableSku) {
-        // @ts-ignore
-        this.curSkuId = availableSku.id
-      }
-    }
-  }
-})
-</script>
-
-<style lang="scss">
-@import '../assets/styles/vars';
-@import '../assets/styles/ext_aliyun_market';
-@import '../assets/styles/ext_tencent_market';
-@import '../assets/styles/ext_huawei_market';
-
-.solution-page {
-  .summary {
-    color: $ink;
-    padding: 128px 0 80px;
-
-    .column.left {
-      flex: none;
-    }
-
-    .cover {
-      width: 152px;
-      height: 152px;
-      border-radius: 32px;
-      margin-right: 40px;
-      overflow: hidden;
-      position: relative;
-
-      img {
-        width: 100%;
-        height: 100%;
-        object-fit: cover;
-      }
-
-      &::after {
-        content: '';
-        width: 100%;
-        height: 100%;
-        border: 1px solid rgba(0, 0, 0, 0.1);
-        border-radius: 32px;
-        position: absolute;
-        top: 0;
-        left: 0;
-      }
-    }
-
-    .title {
-      margin-bottom: 1rem;
-      line-height: 1.4;
-      margin-top: -3px;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      -webkit-box-orient: vertical;
-      display: -webkit-box;
-      -webkit-line-clamp: 2;
-    }
-
-    .extends {
-      font-size: 0.875rem;
-      margin-bottom: 1rem;
-      line-height: 1.4;
-
-      .tag {
-        margin-right: 0.5rem;
-
-        + span {
-          margin-left: 1.25rem;
-        }
-      }
-
-      a.link {
-        color: #888;
-      }
-    }
-
-    .desc {
-      font-size: 0.875rem;
-      margin-bottom: 1.5rem;
-      line-height: 1.4;
-    }
-
-    .price {
-      font-weight: 600;
-      margin-bottom: 1.75rem;
-
-      .symbol {
-        font-size: 1.25rem;
-        margin-right: 3px;
-      }
-      .value {
-        font-size: 1.625rem;
-      }
-      .explain {
-        font-weight: 400;
-        font-size: 0.875rem;
-        margin: 0 0 1px 2px;
-        opacity: 0.54;
-      }
-    }
-
-    .action {
-      .button {
-        font-size: 0.875rem;
-        font-weight: 500;
-        min-width: 106px;
-        height: 2.75em;
-        letter-spacing: 0.01em;
-      }
-    }
-  }
-
-  .skus {
-    margin: 0 -0.5rem 1rem 0;
-
-    .item {
-      color: #666;
-      font-size: 0.8125rem;
-      padding: 8px 12px;
-      border: 1px solid #dfdfdf;
-      border-radius: 2px;
-      display: inline-block;
-      margin: 0 1em 0.75em 0;
-      min-width: 64px;
-      text-align: center;
-      cursor: pointer;
-
-      &.cur {
-        color: $primary;
-        border-color: $primary;
-      }
-
-      &.disabled {
-        opacity: 0.6;
-        cursor: not-allowed;
-      }
-    }
-  }
-
-  .page-nav {
-    background: #fff;
-    height: 54px;
-    border: 1px solid #eaeaea;
-    border-left: 0;
-    border-right: 0;
-    position: sticky;
-    top: 52px;
-    z-index: 9;
-
-    .tabs {
-      font-weight: 500;
-
-      ul, a {
-        border: 0;
-      }
-
-      a {
-        color: $ink !important;
-        height: 54px;
-      }
-
-      li.is-active {
-        position: relative;
-
-        &::after {
-          content: '';
-          position: absolute;
-          bottom: 0;
-          left: 24%;
-          width: 52%;
-          height: 3px;
-          background: $primary;
-          border-radius: 4px;
-        }
-      }
-    }
-  }
-
-  .paper {
-    padding: 1.5rem 0 3rem;
-  }
-
-  .details {
-    padding-left: 0.5rem;
-    padding-right: 0.5rem;
-  }
-
-  .main-cont {
-    .caption {
-      font-size: 1.25rem;
-      font-weight: 500;
-      margin: 2rem 0.5rem 1rem;
-
-      &.bordered {
-        border-top: 1px solid #eaeaea;
-        padding-top: 2rem;
-      }
-    }
-  }
-
-  .side-cont {
-    color: $ink;
-
-    .caption {
-      font-weight: 500;
-      line-height: 1;
-      padding: 0.75rem 0;
-
-      &::before {
-        content: '';
-        background: $primary;
-        width: 3px;
-        height: 16px;
-        border-radius: 4px;
-        display: inline-block;
-        margin-right: 10px;
-        vertical-align: bottom;
-      }
-    }
-
-    .rcmd-list {
-      margin-bottom: 3rem;
-    }
-  }
-
-  @media screen and (min-width: 768px) {
-    .tabs li {
-      margin-right: 2em;
-    }
-
-    .main-cont {
-      padding-right: 1.5rem;
-    }
-
-    .side-cont {
-      padding-left: 1rem;
-    }
-
-    .summary {
-      .cover {
-        margin-left: 1rem;
-      }
-      .title {
-        margin-right: 2rem;
-      }
-      .info {
-        margin-right: 4rem;
-      }
-    }
-  }
-
-  @media screen and (max-width: 768px) {
-    .summary {
-      padding: 88px 0 64px;
-
-      .cover {
-        width: 112px;
-        height: 112px;
-        border-radius: 28px;
-      }
-    }
-  }
-}
-</style>

+ 0 - 4
kaifain_v2/shims-vue.d.ts

@@ -1,4 +0,0 @@
-declare module '*.vue' {
-  import Vue from 'vue';
-  export default Vue;
-}

BIN
kaifain_v2/static/favicon.ico


+ 0 - 62
kaifain_v2/store/apigateway.ts

@@ -1,62 +0,0 @@
-import { getUserInfo, listUserApis } from '../apis/apigateway'
-
-export const state = () => ({
-  apiUser: null,
-  apiList: [],
-  apiListLastUpdatedAt: 0,
-  apiMap: {}
-})
-
-export const actions = {
-  async ['apigateway:user:load']({ commit }) {
-    let user
-
-    try {
-      user = await getUserInfo()
-    } catch (e) {
-      if (e.status === -99) {
-        console.warn(e)
-        return
-      } else {
-        throw e
-      }
-    }
-
-    if (user) {
-      commit('apigateway:user:sync', user)
-    }
-  },
-
-  async ['apigateway:apilist:load']({ state, commit }, opts?: {
-    force: boolean
-  }) {
-    const { force = false } = opts || {}
-    if (!force && state.apiList && Date.now() - state.apiListLastUpdatedAt < 60000) {
-      return
-    }
-
-    commit('apigateway:apilist:sync', await listUserApis())
-  }
-}
-
-export const mutations = {
-  ['apigateway:user:sync'](state, user) {
-    if (user.key_credentials && user.key_credentials.length) {
-      user.accessKey = user.key_credentials[0].key
-    }
-
-    state.apiUser = user
-  },
-
-  ['apigateway:apilist:sync'](state, data) {
-    const apiMap: any = {}
-
-    for (const item of data) {
-      apiMap[item.api_id] = item
-    }
-
-    state.apiList = data
-    state.apiMap = apiMap
-    state.apiListLastUpdatedAt = Date.now()
-  }
-}

+ 0 - 80
kaifain_v2/store/index.ts

@@ -1,80 +0,0 @@
-import { listBanners, listSearchKeywords, getInitParameters } from '../apis/common'
-import * as apigateway from './apigateway'
-
-export const state = () => ({
-  inited: false,
-  cities: [],
-  classes: [],
-  serviceTypes: [],
-  bannerList: [],
-  hotKeywords: [],
-  ...apigateway.state
-})
-
-export const actions = {
-  async ['parameters:load']({ commit }) {
-    commit('parameters:sync', await getInitParameters())
-  },
-
-  async ['banners:load']({ commit }) {
-    commit('banners:sync', await listBanners(1))
-  },
-
-  async ['hotKeywords:load']({ commit }) {
-    commit('hotKeywords:sync', await listSearchKeywords())
-  },
-
-  ...apigateway.actions
-}
-
-export const mutations = {
-  ['parameters:sync'](state, { cities, classes, serviceTypes }) {
-    if (cities) {
-      state.cities = cities
-    }
-
-    if (classes) {
-      state.classes = classes
-      state.fullyClasses = [{
-        id: '_',
-        name: '全部'
-      },
-      ...classes.map((row) => {
-        const { hash_id, name, categories } = row
-        const categoriesCopy = categories && categories.length ? [...categories] : []
-
-        if (categoriesCopy.length) {
-          categoriesCopy.unshift({
-            cat_id: '_',
-            name: '全部'
-          })
-          categoriesCopy.forEach((cat) => {
-            cat.parent_id = hash_id
-          })
-        }
-
-        return {
-          id: hash_id,
-          name,
-          categories: categoriesCopy
-        }
-      })]
-    }
-
-    if (serviceTypes) {
-      state.serviceTypes = serviceTypes
-    }
-
-    state.inited = true
-  },
-
-  ['banners:sync'](state, data) {
-    state.bannerList = data
-  },
-
-  ['hotKeywords:sync'](state, data) {
-    state.hotKeywords = data
-  },
-
-  ...apigateway.mutations
-}

+ 0 - 5
kaifain_v2/utils/bridge.ts

@@ -1,5 +0,0 @@
-import { ProginnBridge } from 'proginn-lib'
-
-const bridge = process.client ? new ProginnBridge() : {} as any
-
-export default bridge

+ 0 - 111
kaifain_v2/utils/misc.ts

@@ -1,111 +0,0 @@
-export const randomRange = (min: number, max: number) => {
-  return Math.random() * (max - min) + min
-}
-
-export const log10 = (val: number) => {
-  return Math.log(val) / 10
-}
-
-export const sleep = (ms: number) => {
-  return new Promise((resolve) => {
-    setTimeout(resolve, ms)
-  })
-}
-
-export const scrollToElement = (selector: string) => {
-  const el = document.querySelector(selector)
-
-  if (el) {
-    setTimeout(() => {
-      el.scrollIntoView({
-        behavior: 'smooth'
-      })
-    }, 17)
-  }
-}
-
-export const findTopCatBySubCatId = (classes: any[], catId: string): any[] | null => {
-  for (const topCat of classes) {
-    const cats = topCat.categories
-    const matchedCat = cats && cats.length && cats.find((cat) => cat.cat_id === catId)
-
-    if (matchedCat) {
-      return [topCat, matchedCat]
-    }
-  }
-
-  return null
-}
-
-export const getTopCatSubCatIds = (topCat) => {
-  return topCat && topCat.categories && topCat.categories.map((cat) => cat.cat_id) || []
-}
-
-export const parseCatIdAndServiceType = (input: {
-  cat_id: string
-  st: string
-  classes: any[]
-  serviceTypes: any[]
-}) => {
-  const {
-    cat_id,
-    st,
-    classes = [],
-    serviceTypes = []
-  } = input
-
-  let topCatId = '_'
-  let catId = '_'
-  let serviceType = '_'
-  let matchedCatIds: string[] = []
-  let topCatName!: string
-  let catName!: string
-
-  if (cat_id) {
-    let topCat
-    let cat
-
-    if (cat_id.length === 8) {
-      topCat = classes.find((topCat) => topCat.hash_id === cat_id)
-      matchedCatIds = getTopCatSubCatIds(topCat)
-    } else {
-      [topCat, cat] = findTopCatBySubCatId(classes, cat_id) || []
-
-      if (cat) {
-        catId = cat_id
-        catName = cat.name
-        matchedCatIds = [catId]
-      }
-    }
-
-    if (topCat) {
-      topCatId = topCat.hash_id
-      topCatName = topCat.name
-    }
-  }
-
-  if (st) {
-    const matchedServiceType = serviceTypes.find((item) => item.hash_id === st)
-
-    if (matchedServiceType) {
-      serviceType = st
-    }
-  }
-
-  return {
-    topCatId,
-    topCatName,
-    catId,
-    catName,
-    serviceType,
-    matchedCatIds
-  }
-}
-
-export const genCatIdSearchSentence = (catIds: string[], serviceType: string) => {
-  return [catIds.join('|'), serviceType].filter((val) => !!val && val != '_').join('&&')
-}
-
-export const formatPrice = (input: number) => {
-  return Number((input / 100).toFixed(2))
-}

+ 0 - 32
kaifain_v2/utils/request.ts

@@ -1,32 +0,0 @@
-import { ProginnRequest } from 'proginn-lib'
-import { MAIN_ENDPOINT } from '../constant'
-
-class RequestError extends Error {
-  status: any
-  url!: string
-  method!: string
-  data!: any
-
-  constructor(msg: string, status: any, res: any) {
-    const { url, method, data } = res && res.config || {}
-    const trackID = res.data && res.data.trackID
-    const message = msg + (trackID ? ` [${trackID}]` : '')
-
-    super(message)
-    this.status = status
-    this.url = url
-    this.method = method
-    this.data = data
-
-    console.error(`${message}\n${method && method.toUpperCase()} ${url}\nData: ${data}\nResponse: ${res.data && JSON.stringify(res.data)}`)
-  }
-}
-
-const request = ProginnRequest.create({
-  baseURL: MAIN_ENDPOINT,
-  notifier(msg, status, res) {
-    throw new RequestError(msg, status, res)
-  }
-})
-
-export default request

+ 0 - 61
layouts/kaifain_v2.vue

@@ -1,61 +0,0 @@
-<template>
-  <nuxt />
-</template>
-
-<script>
-import Cookies from 'js-cookie'
-import Stats from '@/kaifain_v2/mixins/stats'
-
-const MOB_HOST = process.env.NODE_ENV === 'development' ? 'kaifain-m.test.proginn.com' : 'kaifain.m.proginn.com'
-const REM_RESET_STYLE = `font-size:16px !important;`
-
-const resetRem = () => {
-  const _rem_mark = document.querySelector('#rootsize')
-
-  if (_rem_mark) {
-    _rem_mark.innerHTML = `html{${REM_RESET_STYLE}}`
-    document.documentElement.style = REM_RESET_STYLE
-    document.body.style = REM_RESET_STYLE
-  }
-}
-
-export default {
-  head() {
-    return {
-      bodyAttrs: {
-        class: ['kaifain-view', 'non-rem']
-      },
-      ...Stats.head
-    }
-  },
-
-  created() {
-    if (process.client) {
-      if (Cookies.get('x_app')) {
-        const path = window.location.pathname
-        let target
-
-        if (/\/dashboard/.test(path)) {
-          return
-        } else if (/\/(s|d)\/[0-9a-f]+/.test(path)) {
-          target = path.replace(location.host, MOB_HOST)
-        } else {
-          target = `https://${MOB_HOST}/`
-        }
-
-        window.location.replace(target)
-      }
-    }
-  },
-
-  beforeMount() {
-    resetRem()
-  }
-}
-</script>
-
-<style lang="scss">
-:root {
-  font-size: 16px;
-}
-</style>

+ 0 - 2
layouts/opacity_header_kf_tmp.vue

@@ -12,7 +12,6 @@ import ProginnHeader from "@/components/header";
 import ProginnFooter from "@/components/footer";
 import WxHeader from "@/components/wx_header";
 import { mapState, mapMutations } from "vuex";
-import Stats from "@/kaifain_v2/mixins/stats";
 
 export default {
   components: {
@@ -20,7 +19,6 @@ export default {
     ProginnFooter,
     WxHeader
   },
-  mixins: [Stats],
   computed: {
     ...mapState(["isPC", "isWeixin", "deviceType", "noneCommonFooter", "scope"])
   },

+ 0 - 6
nuxt.config.js

@@ -136,7 +136,6 @@ module.exports = {
     "@/assets/css/common.css",
     "@/assets/css/special.css",
     "swiper/dist/css/swiper.css",
-    "@/kaifain_v2/assets/styles/main.scss"
   ],
 
   /*
@@ -257,11 +256,6 @@ module.exports = {
   modules: [
     "@nuxtjs/axios",
     "@nuxtjs/proxy",
-    ["nuxt-buefy", {
-      css: false,
-      materialDesignIcons: false
-    }],
-    'nuxt-highlightjs'
   ],
   router: {
     middleware: ["initialize"],

+ 0 - 2
package.json

@@ -36,8 +36,6 @@
     "moment": "^2.24.0",
     "murmurhash": "^1.0.0",
     "nuxt": "^2.14.0",
-    "nuxt-buefy": "^0.4.2",
-    "nuxt-highlightjs": "^1.0.1",
     "proginn-lib": "ssh://git@www.gitinn.com:proginn/proginn-lib.git",
     "qrcode": "^1.4.4",
     "qs": "^6.8.0",

+ 1 - 12
pages/kaifain/case/_tid.vue

@@ -1,8 +1,5 @@
 <template>
   <div :class="{kaifainPreviewCaseMobile: mobile, kaifainPreviewCase: !mobile}">
-    <div class="kaifain-view">
-      <Topnav :fixed="topnavFixed" @publish-click="isShowToast=true" />
-    </div>
     <div class="topArea">
       <div class="bannerBg">
         <img src="~@/assets/img/kaifain/detail/banner@2x.png" alt="" v-if="!mobile">
@@ -26,7 +23,6 @@
        </div>
      </div>
     </div>
-    <KaifainFooter style="margin-top: 30px;" :data="footer"/>
 
     <ConnectUs
       :source="'开发屋案例'"
@@ -44,12 +40,10 @@
   import ConnectUs from "@/components/common/connectUsKaifain.vue";
   import KaifainFooter from "@/components/SeoFooter.vue"
   import {HashIDUtil, GenType} from "../../../plugins/genHashId"
-  import Topnav from '@/kaifain_v2/components/Topnav.vue'
-  import { genDocumentFooterData } from '@/kaifain_v2/helpers/seoHelper'
 
   export default {
     layout: "opacity_header_kf_tmp",
-    components: {ConnectUs, KaifainFooter, Topnav},
+    components: {ConnectUs, KaifainFooter},
     head() {
       const { title = '' } = this.detail || {}
       return {
@@ -97,10 +91,6 @@
       }
 
       const { classes } = ctx.store.state.kaifain
-      const footer = genDocumentFooterData({
-        ctx,
-        classes
-      })
 
       let detail = {}
       let errInfo = ""
@@ -120,7 +110,6 @@
       }
       return {
         tid,
-        footer,
         mobile: params.app.$deviceType.isMobile(),
         detail,
         errInfo

+ 1 - 13
pages/kaifain/detail/_tid/index.vue

@@ -1,8 +1,5 @@
 <template>
   <div :class="{kaifainDetailMobile: mobile, kaifainDetail: !mobile}">
-    <div class="kaifain-view">
-      <Topnav :fixed="topnavFixed" @publish-click="isShowToast=true"/>
-    </div>
     <div class="topArea" :style="{backgroundImage: 'url(' + detail.bg_image + ')' }">
       <div class="topContent" :class="{noneMobileAPP: true}">
         <h1 class="title">{{detail.title}}</h1>
@@ -119,7 +116,6 @@
       @close="isShowToast=false"
       :sourceId="tid"
     ></ConnectUs>
-    <KaifainFooter style="margin-top: 30px;" :data="footer"/>
     <ChangeBgImage
       :pId="detail.id"
       :isShowToast="isShowToastChange"
@@ -136,12 +132,10 @@
   import ChangeBgImage from "@/components/kaifain/ChangeBgImage.vue";
   import KaifainFooter from "@/components/SeoFooter.vue";
   import {HashIDUtil, GenType} from "../../../../plugins/genHashId";
-  import Topnav from '@/kaifain_v2/components/Topnav.vue'
-  import {genDocumentFooterData} from '@/kaifain_v2/helpers/seoHelper'
 
   export default {
     layout: "opacity_header_kf_tmp",
-    components: {ConnectUs, KaifainFooter, ChangeBgImage, Topnav},
+    components: {ConnectUs, KaifainFooter, ChangeBgImage},
     head() {
       const {title = ''} = this.detail || {}
       let docTitle = title ? `${title}介绍,功能,开发解决方案-开发屋` : '开发屋-开发解决方案'
@@ -223,11 +217,6 @@
       }
 
       const {classes} = ctx.store.state.kaifain
-      const footer = genDocumentFooterData({
-        ctx,
-        classes
-      })
-
       let isSelf = false;
       try {
         let uid = params.store.state.userinfo.uid;
@@ -243,7 +232,6 @@
         errInfo,
         mobile: params.app.$deviceType.isMobile(),
         mobileApp: params.app.$deviceType.app,
-        footer
       };
     },
     data() {

+ 0 - 43
plugins/seoRouter.js

@@ -5,49 +5,6 @@ const extendRoutes = (routes, resolve) => {
   kaifainIndex && routes.splice(kaifainIndex, 1)
 
   routes.unshift(
-    // kaifain
-    ...[{
-      name: 'kaifain',
-      path: '/kaifain',
-      component: resolve(__dirname, '../kaifain_v2/pages/index.vue')
-    }, {
-      name: 'kaifainPage',
-      path: '/kaifain/page/:page',
-      component: resolve(__dirname, '../kaifain_v2/pages/index.vue')
-    }, {
-      name: 'kaifainCategory',
-      path: '/kaifain/c/:cat_id',
-      component: resolve(__dirname, '../kaifain_v2/pages/index.vue')
-    }, {
-      name: 'kaifainSearch',
-      path: '/kaifain/search',
-      component: resolve(__dirname, '../kaifain_v2/pages/search.vue')
-    }, {
-      name: 'kaifainSeoDetail',
-      path: '/kaifain/s/:id',
-      component: resolve(__dirname, '../kaifain_v2/pages/solution.vue')
-    }, {
-      name: 'kaifainCaseSeoDetail',
-      path: '/kaifain/d/:tid',
-      component: resolve(__dirname, '../pages/kaifain/case/_tid.vue')
-    }, {
-      path: '/kaifain/dashboard',
-      component: resolve(__dirname, '../kaifain_v2/pages/dashboard/layout.vue'),
-      children: [{
-        path: 'apis',
-        component: resolve(__dirname, '../kaifain_v2/pages/dashboard/apis.vue')
-      }, {
-        path: 'inspector',
-        component: resolve(__dirname, '../kaifain_v2/pages/dashboard/inspector.vue'),
-      }, {
-        path: 'sms/templates',
-        component: resolve(__dirname, '../kaifain_v2/pages/dashboard/sms/templates.vue')
-      }, {
-        path: '',
-        component: resolve(__dirname, '../kaifain_v2/pages/dashboard/home.vue'),
-      }]
-    }],
-
     // jishuin
     ...[{
       name: 'jishuinCollectedCID1',

+ 0 - 6
store/index.ts

@@ -1,5 +1,3 @@
-import * as kaifain from '../kaifain_v2/store'
-
 export const state = () => ({
   scope: null,
   isPC: -1,
@@ -74,7 +72,3 @@ export const actions = {
     commit("updateDeviceType", app.$deviceType || {});
   }
 };
-
-export const modules = {
-  kaifain
-}

+ 0 - 2
tsconfig.json

@@ -32,8 +32,6 @@
   },
   "include": [
     "store/**/*.ts",
-    "kaifain_v2/**/*.ts",
-    "kaifain_v2/**/*.vue"
   ],
   "exclude": [
     "node_modules",

+ 0 - 31
yarn.lock

@@ -3614,13 +3614,6 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.6.4, browserslist@^4.
     node-releases "^1.1.53"
     pkg-up "^2.0.0"
 
-buefy@^0.9.3:
-  version "0.9.3"
-  resolved "https://registry.npm.taobao.org/buefy/download/buefy-0.9.3.tgz#c33b3309e9458ca5fe3ef14955e4bc2df7a0e3e2"
-  integrity sha1-wzszCelFjKX+PvFJVeS8Lfeg4+I=
-  dependencies:
-    bulma "0.9.0"
-
 buffer-alloc-unsafe@^1.1.0:
   version "1.1.0"
   resolved "https://registry.npm.taobao.org/buffer-alloc-unsafe/download/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
@@ -3676,11 +3669,6 @@ builtin-status-codes@^3.0.0:
   resolved "https://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
   integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
 
-bulma@0.9.0:
-  version "0.9.0"
-  resolved "https://registry.npm.taobao.org/bulma/download/bulma-0.9.0.tgz#948c5445a49e9d7546f0826cb3820d17178a814f"
-  integrity sha1-lIxURaSenXVG8IJss4INFxeKgU8=
-
 bytes@3.0.0:
   version "3.0.0"
   resolved "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@@ -6356,11 +6344,6 @@ hex-color-regex@^1.1.0:
   resolved "https://registry.npm.taobao.org/hex-color-regex/download/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
   integrity sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=
 
-highlight.js@^10.1.2:
-  version "10.2.0"
-  resolved "https://registry.npm.taobao.org/highlight.js/download/highlight.js-10.2.0.tgz#367151bcf813adebc54822f1cb51d2e1e599619f"
-  integrity sha1-NnFRvPgTrevFSCLxy1HS4eWZYZ8=
-
 hljs@^6.2.3:
   version "6.2.3"
   resolved "https://registry.npm.taobao.org/hljs/download/hljs-6.2.3.tgz#d4d6208fa2a84f294956bc50f2c812e9cbd49bcc"
@@ -8298,20 +8281,6 @@ number-is-nan@^1.0.0:
   resolved "https://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
   integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
 
-nuxt-buefy@^0.4.2:
-  version "0.4.3"
-  resolved "https://registry.npm.taobao.org/nuxt-buefy/download/nuxt-buefy-0.4.3.tgz#2ecafd9256743f05d123a5487acc3488ea7023f4"
-  integrity sha1-Lsr9klZ0PwXRI6VIesw0iOpwI/Q=
-  dependencies:
-    buefy "^0.9.3"
-
-nuxt-highlightjs@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.npm.taobao.org/nuxt-highlightjs/download/nuxt-highlightjs-1.0.1.tgz#6809a9ccebfff8993d69a85a9095650069268d66"
-  integrity sha1-aAmpzOv/+Jk9aahakJVlAGkmjWY=
-  dependencies:
-    highlight.js "^10.1.2"
-
 nuxt@^2.14.0:
   version "2.14.0"
   resolved "https://registry.npm.taobao.org/nuxt/download/nuxt-2.14.0.tgz#2938600c93dbcc4f9628b61c1183468f01cef951"