huaisianhuang il y a 3 ans
Parent
commit
cff23cc7a6

+ 64 - 0
package-lock.json

@@ -4483,6 +4483,29 @@
         "safer-buffer": "^2.1.0"
       }
     },
+    "echarts": {
+      "version": "4.9.0",
+      "resolved": "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz",
+      "integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==",
+      "requires": {
+        "zrender": "4.3.2"
+      }
+    },
+    "echarts-amap": {
+      "version": "1.0.0-rc.6",
+      "resolved": "https://registry.npmjs.org/echarts-amap/-/echarts-amap-1.0.0-rc.6.tgz",
+      "integrity": "sha1-V4KnTa7lLtRM4/j2JXdWF4PwnhY="
+    },
+    "echarts-liquidfill": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/echarts-liquidfill/-/echarts-liquidfill-2.0.6.tgz",
+      "integrity": "sha512-p+AH0O9/BtwXMQQyhjJbMZo+GwRAgWG/DCyK5r27PQzpS0UWrgXu57MyEFc0A8Ub3sRuqEu08BuxwHICBkSWSQ=="
+    },
+    "echarts-wordcloud": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/echarts-wordcloud/-/echarts-wordcloud-1.1.3.tgz",
+      "integrity": "sha512-Et8D5xEAoYkidmHun+hEH+2lF9dhCt6D0JJ390vlr2r/1zwhhZAbcL01CEvG93QcMcJpSvSPK8vRiGkTbMHRxg=="
+    },
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -7212,6 +7235,11 @@
       "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
       "dev": true
     },
+    "numerify": {
+      "version": "1.2.9",
+      "resolved": "https://registry.npmjs.org/numerify/-/numerify-1.2.9.tgz",
+      "integrity": "sha512-X4QzQiytV5ZN3TVLhzbtFzjTarUNnaa1pgNDFqt7u7Nqhxe7FvY2eYrGt4WYHlYXDqgtfC/n/a5nJ2y0LijV8w=="
+    },
     "oauth-sign": {
       "version": "0.9.0",
       "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@@ -9725,6 +9753,11 @@
         "util.promisify": "~1.0.0"
       }
     },
+    "sweetalert2": {
+      "version": "11.0.6",
+      "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.0.6.tgz",
+      "integrity": "sha512-dP9MZ5+Rng5GVFMeYZjXKyHepj3K9JFwzttwjtNgq1p8SztqJMAalSNJpY9sE11Q63wgVsaoiLqgvC0PcF3NEQ=="
+    },
     "tapable": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
@@ -10324,6 +10357,11 @@
       "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=",
       "dev": true
     },
+    "utils-lite": {
+      "version": "0.1.10",
+      "resolved": "https://registry.npmjs.org/utils-lite/-/utils-lite-0.1.10.tgz",
+      "integrity": "sha512-jlHvdtI8MyWURF/3u+ufIjf1Cs5WjN6WZl9qO8dEkZsVjaI7X5YMUhaCFzkvB69ljt6fo4Dd7V/Oj2NJOFDFOQ=="
+    },
     "utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -10336,6 +10374,18 @@
       "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
       "dev": true
     },
+    "v-charts": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/v-charts/-/v-charts-1.19.0.tgz",
+      "integrity": "sha512-vm2HBUmxAsXK0ivwce9LytcpqrItDA5JSPLYVxZXtiuoyhcn80XX1/3dPJd/1GqG1OYv3jfBo1s9ra4q8GowqA==",
+      "requires": {
+        "echarts-amap": "1.0.0-rc.6",
+        "echarts-liquidfill": "^2.0.2",
+        "echarts-wordcloud": "^1.1.3",
+        "numerify": "1.2.9",
+        "utils-lite": "0.1.10"
+      }
+    },
     "validate-npm-package-license": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@@ -10508,6 +10558,15 @@
       "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.1.tgz",
       "integrity": "sha512-RRQNLT8Mzr8z7eL4p7BtKvRaTSGdCbTy2+Mm5HTJvLGYSSeG9gDzNasJPP/yOYKLy+/cLG/ftrqq5fvkFwBJEw=="
     },
+    "vue-simple-calendar": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/vue-simple-calendar/-/vue-simple-calendar-5.0.0.tgz",
+      "integrity": "sha512-UQl+Jn3TyRm2+6ao5DBIO3iwyk8peghkApogSrEruAA8wy+x5zheVQuhqnSDMTkFiLmpE9mlDDaHYvVTmOXsoA==",
+      "requires": {
+        "core-js": "^3.6.5",
+        "vue": "^2.6.12"
+      }
+    },
     "vue-style-loader": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
@@ -11379,6 +11438,11 @@
       "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz",
       "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==",
       "dev": true
+    },
+    "zrender": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.2.tgz",
+      "integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g=="
     }
   }
 }

+ 4 - 0
package.json

@@ -11,12 +11,16 @@
     "bootstrap": "^4.6.0",
     "bootstrap-vue": "^2.21.2",
     "core-js": "^3.6.5",
+    "echarts": "^4.9.0",
     "jquery": "^3.6.0",
     "popper.js": "^1.16.1",
+    "sweetalert2": "^11.0.6",
+    "v-charts": "^1.19.0",
     "vue": "^2.6.12",
     "vue-axios": "^3.2.4",
     "vue-loading-overlay": "^3.4.2",
     "vue-router": "^3.2.0",
+    "vue-simple-calendar": "^5.0.0",
     "vuex": "^3.4.0"
   },
   "devDependencies": {

+ 134 - 19
src/App.vue

@@ -1,16 +1,36 @@
 <template>
   <div id="app">
-     <nav class="navbar navbar-dark sticky-top flex-md-nowrap p-2">
-        <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">ChoozMo Marketing Cloud</a>
-        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
-          <li class="nav-item">
-            <span>Hello Username</span>
-          </li>
-        </ul>
+     <nav class="navbar navbar-dark navbar-expand-lg sticky-top p-2">
+        <a class="navbar-brand" href="#">Marketing Cloud</a>
+        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation" @click.prevent="navtoggler = !navtoggler">
+          <span class="navbar-toggler-icon" v-if="!navtoggler"></span>
+          <span class="navbar-close-icon" v-if="navtoggler"></span>
+        </button>
+        <div class="collapse navbar-collapse" id="navbarTogglerDemo02">
+          <ul class="navbar-nav mr-auto mt-2 mt-lg-0">
+            <li class="nav-item" :class="{'active': $route.name === 'Trends' }">
+              <a class="nav-link" @click="$router.push({ name: 'Trends' })">趨勢觀測<span class="sr-only">(current)</span></a>
+            </li>
+            <li class="nav-item" :class="{'active': $route.name === 'Usernews' }">
+              <a class="nav-link" @click="$router.push({ name: 'Usernews' })">商品熱度分析<span class="sr-only">(current)</span></a>
+            </li>
+            <!-- <li class="nav-item" :class="{'active': $route.name === 'Calendarview' }">
+              <a class="nav-link" @click="$router.push({ name: 'Calendarview' })">Calendar</a>
+            </li> -->
+            <li class="nav-item" :class="{'active': $route.name === 'Aivideo' }">
+              <a class="nav-link" @click="$router.push({ name: 'Aivideo' })">AI代言人</a>
+            </li>
+            <li class="nav-item" :class="{'active': $route.name === 'Calendarview' }"> 
+              <a class="nav-link" @click="$router.push({ name: 'Calendarview' })">AMP</a>
+            </li>
+          </ul>
+          <div class="">
+            <button class="btn btn-outline-light btn__genCal" @click.prevent="addToGcal">加入Google Calendar</button>
+          </div>
+        </div>
       </nav>
-      <div class="container-fluid">
-        <div class="row">
-          <nav class="col-md-2 d-none d-md-block bg-light sidebar">
+      <div class="container">
+          <!-- <nav class="col-md-2 d-none d-md-block bg-light sidebar">
                 <div class="sidebar-sticky">
                   <ul class="nav flex-column">
                     <li class="nav-item">
@@ -25,24 +45,119 @@
                         客群瀏覽
                       </a>
                     </li>
-                    <!-- <li class="nav-item">
-                      <a class="nav-link" href="#">
-                        <i class="fas fa-quote-left"></i>
-                        關鍵字建議
+                    <li class="nav-item">
+                      <a class="nav-link" @click="$router.push({ name: 'Usernews' })">
+                        <i class="fas fa-users"></i>
+                        商品熱度分析
                       </a>
-                    </li> -->
+                    </li>
+                    <li class="nav-item">
+                      <a class="nav-link" @click="$router.push({ name: 'Calendarview' })">
+                        <i class="fas fa-users"></i>
+                        Calendar
+                      </a>
+                    </li>
                   </ul>
                 </div>
                 <div class="footer__txt">ChoozMo 行銷雲</div>
-          </nav>
-              <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
-                <router-view />
-              </main>
+          </nav> -->
+        <main role="main" class="pt-3">
+          <router-view :userId="userId" :logselected="logselected" />
+        </main>
+      </div>
+      <div class="modal fade" id="addToGcalModal" tabindex="-1" role="dialog" aria-labelledby="addToGcalModalLabel" aria-hidden="true">
+        <div class="modal-dialog" role="document">
+          <div class="modal-content">
+            <div class="modal-header">
+              <h5 class="modal-title" id="addToGcalModal">將您訂閱的客群同步至您的Google Calendar</h5>
+              <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+              </button>
+            </div>
+            <div class="modal-body">
+              <div class="mb-3 text-left">
+                <span class="step">Step 1</span><p>前往您的Google Calendar的設定,並選擇自URL加入Calendar</p>
+              </div>
+              <div class="img_fr mb-3"><img src="./assets/addurl.png" alt=""></div>
+              <div class="mb-3 text-left">
+                <span class="step">Step 2</span><p>將下方URL輸入欄位,就可成功加入Calendar</p>
+              </div>
+              <div class="url_fr">
+                URL: {{ calUrl }}
+              </div>
+            </div>
+            <div class="modal-footer">
+              <button type="button" class="btn btn__close" data-dismiss="modal">Close</button>
+            </div>
+          </div>
         </div>
       </div>
   </div>
 </template>
 
+<script>
+import $ from 'jquery';
+
+export default {
+  data() {
+    return {
+      userId: 20,
+      username: 'Ana Huang',
+      logselected: false,
+      calUrl: '',
+      cookie: '',
+      navtoggler: false,
+    }
+  },
+  methods: {
+    examineType() {
+      this.$http.get('http://www.googo.org:8050/api/user_groups_data/20').then(res => {
+        if(res.data.length == 0) {
+          this.logselected = false;
+        } else{
+          this.logselected = true;
+        }
+      });
+    },
+    addToGcal() {
+      this.$http.get('http://www.googo.org:8050/api/calendar/gen_ics/20').then(res => {
+        //console.log(res.data);
+        if(res.data.status === 'success') {
+          this.calUrl = res.data.url;
+        }
+        $('#addToGcalModal').modal('show');
+      });
+    },
+    getCookie(name) {
+      const value = `; ${document.cookie}`;
+      const parts = value.split(`; ${name}=`);
+      if (parts.length === 2) { return parts.pop().split(';').shift() };
+    },
+    examineUser() {
+      this.cookie = this.getCookie('token');
+      this.$http.get('http://www.googo.org:8050/api/auth/user_status', { 
+        headers: {
+          'Authorization' : this.cookie
+        }
+      }).then(res => {
+        this.userId = res.data.data.user_id;
+        this.username = res.data.data.username;
+      });
+    }
+  },
+  created() {
+    this.examineType();
+    /* this.$http.get('http://www.googo.org:8050/api/auth/user_status', { 
+      headers: {
+        'Authorization' : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyMCwiZXhwIjoxNjIwNzg5Mzc4LCJzdWIiOjIwfQ.C-S2gPHkZ0RnejcfCFVoYKiwsNuMVH5QZdNqSKvZPZs"
+      }
+    }).then(res => {
+        
+      }); */
+  }
+  
+}
+</script>
 <style lang="scss">
 @import '@/assets/scss/all.scss';
 #app {

BIN
src/assets/Labinaagu.png


BIN
src/assets/addurl.png


BIN
src/assets/alberto-castillo-q-mx4mSkK9zeo-unsplash.jpg


BIN
src/assets/checked.png


BIN
src/assets/girl1.png


BIN
src/assets/girl2.png


BIN
src/assets/girl3.png


BIN
src/assets/jarek-ceborski-jn7uVeCdf6U-unsplash.jpg


BIN
src/assets/kelsey-dody-mt2QzllH814-unsplash.jpg


BIN
src/assets/patrick-perkins-3wylDrjxH-E-unsplash.jpg


+ 4 - 0
src/assets/scss/all.scss

@@ -1,4 +1,8 @@
 @import '~bootstrap/scss/functions';
 @import './variables.scss';
 @import '~bootstrap/scss/bootstrap';
+@import './reset.scss';
+@import './utilities.scss';
+@import './mixins.scss';
 @import './style.scss';
+

+ 15 - 0
src/assets/scss/mixins.scss

@@ -0,0 +1,15 @@
+@mixin medium {
+    @media screen and (max-width: 992px) {
+          @content;
+    }
+  }
+  @mixin small {
+    @media screen and (max-width: 768px) {
+          @content;
+    }
+  }
+  @mixin x-small {
+    @media screen and (max-width: 576px) {
+          @content;
+    }
+  }

+ 48 - 0
src/assets/scss/reset.scss

@@ -0,0 +1,48 @@
+/* http://meyerweb.com/eric/tools/css/reset/ 
+   v2.0 | 20110126
+   License: none (public domain)
+*/
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed, 
+figure, figcaption, footer, header, hgroup, 
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+	margin: 0;
+	padding: 0;
+	border: 0;
+	font-size: 100%;
+	font: inherit;
+	vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure, 
+footer, header, hgroup, menu, nav, section {
+	display: block;
+}
+body {
+	line-height: 1;
+}
+ol, ul {
+	list-style: none;
+}
+blockquote, q {
+	quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+	content: '';
+	content: none;
+}
+table {
+	border-collapse: collapse;
+	border-spacing: 0;
+}

+ 709 - 226
src/assets/scss/style.scss

@@ -1,283 +1,766 @@
-/* http://meyerweb.com/eric/tools/css/reset/ 
-   v2.0 | 20110126
-   License: none (public domain)
-*/
-
-html, body, div, span, applet, object, iframe,
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,
-a, abbr, acronym, address, big, cite, code,
-del, dfn, em, img, ins, kbd, q, s, samp,
-small, strike, strong, sub, sup, tt, var,
-b, u, i, center,
-dl, dt, dd, ol, ul, li,
-fieldset, form, label, legend,
-table, caption, tbody, tfoot, thead, tr, th, td,
-article, aside, canvas, details, embed, 
-figure, figcaption, footer, header, hgroup, 
-menu, nav, output, ruby, section, summary,
-time, mark, audio, video {
-	margin: 0;
-	padding: 0;
-	border: 0;
-	font-size: 100%;
-	font: inherit;
-	vertical-align: baseline;
-}
-/* HTML5 display-role reset for older browsers */
-article, aside, details, figcaption, figure, 
-footer, header, hgroup, menu, nav, section {
-	display: block;
-}
-body {
-	line-height: 1;
-}
-ol, ul {
-	list-style: none;
-}
-blockquote, q {
-	quotes: none;
-}
-blockquote:before, blockquote:after,
-q:before, q:after {
-	content: '';
-	content: none;
-}
-table {
-	border-collapse: collapse;
-	border-spacing: 0;
-}
 @import url('https://fonts.googleapis.com/css2?family=Work+Sans:wght@400;500;600&display=swap');
+
 body {
-    font-family: 'Work Sans', sans-serif;
+  font-family: 'Work Sans', sans-serif;
 }
-/* body background */
+
 .color__grey {
-    background-color: #f5f5f5;
+  background-color: #f5f5f5;
 }
 
-
 .row {
-    height: 100vh;
-}
-.page-footer {
-    padding-bottom: 20px;
+  height: auto;
 }
 
 .navbar {
-    background-color: #e57373;
+  background-color: #e57373;
+}
+
+.navbar-dark .navbar-toggler {
+  border: none;
+  .navbar-close-icon {
+    display: inline-block;
+    width: 1.5rem;
+    height: 1.5rem;
+    vertical-align: middle;
+    position: relative;
+    &::before {
+      content: "";
+      width: 1.5rem;
+      height: 2px;
+      background-color: white;
+      left: 0;
+      display: inline-block;
+      position: absolute;
+      top: 8px;
+      transform: rotate(45deg);
+  }
+  &::after {
+      content: "";
+      width: 1.5rem;
+      height: 2px;
+      background-color: white;
+      left: 0;
+      display: inline-block;
+      position: absolute;
+      top: 8px;
+      transform: rotate(-45deg);
+  }
+  }
 }
 
 .nav-link {
-    color: rgb(99, 97, 97);
-    padding: 1rem .75rem;
-    cursor: pointer;
+  color: rgb(99, 97, 97);
+  padding: 1rem .75rem;
+  cursor: pointer;
 }
 .nav-link:hover {
-    color: rgb(27, 27, 27);
+  color: $black;
 }
 .table tbody th, .table tbody td {
-    padding: 1rem;
+  padding: 1rem;
 }
 
-td[colspan = '2'] {
-    background-color: rgb(160, 245, 245);
-}
 .span {
-    display: block;
-    margin-bottom: .4rem;
+  display: block;
+  margin-bottom: .4rem;
 }
 
+.badge {
+  margin: .1rem;
+}
+.highTrend {
+  color: $white;
+  background-color: $bg-color;
+}
 
-
-.chart-wrapper {
-    max-width: 1150px;
-    padding: 0 10px;
-    margin: 0 auto;
-  }
-  
-  
-  /* CHART-VALUES
-  –––––––––––––––––––––––––––––––––––––––––––––––––– */
-  .chart-wrapper .chart-values {
-    position: relative;
-    display: flex;
-    margin-bottom: 20px;
-    font-weight: bold;
-    font-size: 1.2rem;
+.btn__kw {
+  padding: .75rem;
+  background-color: $bg-color-lighten-2;
+  border: none;
+  outline: none;
+  border-radius: 5px;
+  transition: all .2s;
+  &:hover {
+    background-color: $bg-color-lighten-1;
   }
-  
-  .chart-wrapper .chart-values li {
-    flex: 1;
-    min-width: 80px;
-    text-align: center;
-  }
-  
-  .chart-wrapper .chart-values li:not(:last-child) {
-    position: relative;
-  }
-  
-  .chart-wrapper .chart-values li:not(:last-child)::before {
-    content: '';
-    position: absolute;
-    right: 0;
-    height: 510px;
-    border-right: 1px solid var(--divider);
-  }
-  
-  
-  /* CHART-BARS
-  –––––––––––––––––––––––––––––––––––––––––––––––––– */
-  .chart-wrapper .chart-bars li {
-    position: relative;
-    color: var(--white);
-    margin-bottom: 15px;
-    font-size: 16px;
-    border-radius: 20px;
-    padding: 10px 20px;
-    width: 0;
-    opacity: 0;
-    transition: all 0.65s linear 0.2s;
-  }
-  
-  @media screen and (max-width: 600px) {
-    .chart-wrapper .chart-bars li {
-      padding: 10px;
-    }
-  }
-  
-  
-  /* FOOTER
-  –––––––––––––––––––––––––––––––––––––––––––––––––– */
-  .page-footer {
-    font-size: 0.85rem;
-    padding: 10px;
-    text-align: right;
-    color: var(--black);
-  }
-  
-  .page-footer span {
-    color: #e31b23;
+  &:focus {
+    outline: none;
   }
+}
 
-  .dark-2 {
-    background-color: #da3e3e;
-  }
-  .dark-1 {
-    background-color: #dd6565;
-  }
-  .lighten-1 {
-    background-color: #e29595;
-  }
-  .lighten-2 {
-    background-color: #ddacac;
-  }
+.badge {
+  font-size: 1rem;
+}
+.card-img-top {
+  width: 150px;
+  height: 200px;
+}
 
-  .badge {
-      margin: .1rem;
+.btn__del {
+  display: inline-block;
+  width:35px;
+  height: 35px;
+  position: absolute;
+  top: 6px;
+  right: 6px;
+  outline: none;
+  border: none;
+  border-radius: 50%;
+  padding: 10px;
+  background-color: red;
+  color: $white;
+  transition: all .3s;
+  box-shadow: 0 0 6px rgb(179, 179, 179);
+  &:hover {
+    background-color: rgb(176, 238, 228);
   }
-  .highTrend {
-      color: white;
+  i {
+    font-size: 1.1rem;
+    line-height: 1rem;
   }
+}
 
-  .btn__kw {
-      padding: .75rem;
-      background-color: #ddacac;
-      border: none;
-      outline: none;
-      border-radius: 5px;
-      transition: all .2s;
+.btn__sub {
+  display: inline-block;
+  position: absolute;
+  top: 6px;
+  right: 6px;
+  outline: none;
+  border: none;
+  border-radius: 10px;
+  padding: 10px 16px;
+  transition: all .3s;
+  color: black;
+  background-color: rgb(224, 221, 221);
+  box-shadow: 0 0 6px rgb(179, 179, 179);
+  &:hover {
+    color: $white;
+    background-color: gray;
   }
-  .btn__kw:hover {
-    background-color: #e29595;
+}
+.group__row {
+  height: auto;
+  margin-bottom: 2rem;
+}
+.card__subsribed {
+  position: relative;
+}
+.text-muted {
+  letter-spacing: 1px;
+  font-size: 1.3rem;
+}
+.words__block {
+  height: 3.5rem;
+  overflow: hidden;
+}
+.autoHeight {
+  height: auto;
+}
+
+.group__title {
+  text-align: left;
+}
+.footer__txt {
+  position: fixed;
+  bottom: 1rem;
+  left: 3rem;
+  opacity: 0.7;
+}
+.form-group-center {
+  width: 90%;
+  position: absolute;
+  top: 30%;
+
+}
+.group__tag {
+  background-color: $bg-color-lighten-1;
+  width: 10rem;
+  color: #f5f5f5;
+  height: 3rem;
+  font-size: 1.5rem;
+  line-height: 2.5rem;
+  border-radius: 10px 10px 0 0 ;
+}
+
+.btn__genCal {
+  color: white;
+  &:hover {
+    color: black;
   }
-  .btn__kw:focus {
-      outline: none;
+}
+
+.btn__close {
+  background-color: $bg-color !important;
+  color: #f5f5f5 !important;
+}
+
+.img_fr {
+  width: 100%;
+  height: 12rem;
+  img {
+    width: 100%;
+    height: 100%;
   }
+}
 
-  .badge {
-      font-size: 1rem;
+.url_fr {
+  padding: 0.5rem;
+  border: 2px solid grey;
+  border-radius: 5px;
+}
+.step {
+  display: inline-block;
+  padding: 6px 12px;
+  background-color: $bg-color;
+  color: white;
+  border-radius: 15px;
+}
+
+.search__form {
+  width: 90%;
+  max-width: 38rem;
+  position: relative;
+  border-bottom: 2px solid gray;
+  margin-top: 2rem;
+  margin-bottom: 1rem;
+  &:hover {
+    transform: scale(1.05);
   }
-  .card-img-top {
-    width: 150px;
-    height: 200px;
+  .search__bar {
+    border: none;
+    transition: all .3s;
+    width: 75%;
+    @include x-small {
+      width: 67%;
+    }
+    &:focus {
+      outline: none;
+    }
   }
-  .btn__del {
-    display: inline-block;
-    width:35px;
-    height: 35px;
+  .search__btn {
     position: absolute;
-    top: 6px;
-    right: 6px;
-    outline: none;
+    right: 0px;
+    top: 0px;
+    background: transparent;
     border: none;
-    border-radius: 50%;
-    padding: 10px;
-    background-color: red;
-    color: white;
+    outline: none;
+    color: black;
     transition: all .3s;
-    box-shadow: 0 0 6px rgb(179, 179, 179);
+    font-size: 1.2rem;
+    @include x-small {
+      font-size: 1rem;
+    }
+    &:hover {
+      color: $bg-color;
+      transform: scale(1.01);
+    }
   }
-  .btn__del:hover {
-    background-color: rgb(176, 238, 228);
+  .warnmsg {
+    position: absolute;
+    color: red;
+    font-size: 1rem;
+    top: 100%;
+    left: 0%;
   }
-  .btn__sub {
-    display: inline-block;
+}
+
+.usernews__table__title {
+  display: inline-block;
+  font-size: 1.5rem;
+  margin-bottom: 1.5rem;
+  font-weight: 400;
+  position: relative;
+  text-align: left;
+  &::after {
     position: absolute;
-    top: 6px;
-    right: 6px;
-    outline: none;
-    border: none;
-    border-radius: 10px;
-    padding: 10px 16px;
-    transition: all .3s;
-    color: black;
-    background-color: rgb(224, 221, 221);
-    box-shadow: 0 0 6px rgb(179, 179, 179);
+    left: 30%;
+    bottom: -10px;
+    width: 80%;
+    height: 1.5rem;
+    content: " ";
+    background-color: $bg-color-lighten-2;
+    z-index: -1;
   }
-  .btn__sub:hover {
-    color: white;
-    background-color: gray;
+}
+
+.col-card {
+  @include medium {
+    margin-bottom: 1.5rem;
   }
-  .group__row {
-    height: auto;
+}
+
+.col-table {
+  @include medium {
     margin-bottom: 2rem;
   }
-  .card__subsribed {
-    position: relative;
+}
+
+.card {
+  box-shadow: 0px 0px 8px rgb(211, 211, 211);
+}
+
+.card-body {
+  padding: 0.5rem;
+}
+
+.btn__searchedWord {
+  border: 1px solid grey !important;
+  border-radius: 10rem !important;
+  margin-right: 1rem;
+  @include x-small {
+    font-size: .9rem;
+    padding: .2rem .3rem !important;
   }
-  .text-muted {
-    letter-spacing: 1px;
-    font-size: 1.3rem;
+  .btn__delete {
+    display: inline-block;
+    margin-left: 1rem;
+    @include x-small {
+      margin-left: .5rem;
+    }
   }
-  .words__block {
-    height: 3.5rem;
-    overflow: hidden;
+}
+
+.history__block {
+  margin-bottom: 4rem;
+}
+
+.calendar-parent {
+  height: 85vh;
+  margin-bottom: 4rem;
+  box-shadow: 0px 0px 5px rgb(211, 211, 211);;
+}
+
+.cv-item {
+  height: 2rem;
+}
+.cv-item.isHovered {
+  white-space: normal;
+  word-wrap: break-word;
+  height: 4rem;
+}
+
+.group__box {
+  display: flex;
+  align-items: center;
+  .select {
+    width: 12rem;
+    .selector {
+      border-radius: 10px;
+      border: 1px solid $bg-color;
+      padding: 6px;
+      width: 12rem;
+      &:focus-visible {
+        border: none;
+      }
+    }
+  }
+}
+.group__btn {
+  border-radius: 10px;
+}
+.btn-group .btn__date {
+  color: $bg-color;
+  border: 1px solid $bg-color;
+  background-color: transparent;
+  padding: .5rem;
+  width: 4rem;
+  transition: all .4s;
+}
+
+.btn-group .btn__date:nth-of-type(1) {
+  border-radius: 5px 0  0 5px;
+}
+.btn-group .btn__date:nth-of-type(3) {
+  border-radius: 0 5px 5px 0;
+}
+.btn-group .btn__date:hover {
+  background-color: $bg-color;
+  color: $white;
+}
+
+.btn-group .btn__date.active {
+  background-color: $bg-color;
+  color: $white;
+}
+
+.cv-header {
+  &-day {
+    background-color: transparent !important;
   }
-  .autoHeight {
-    height: auto;
+  background-color: $bg-color-lighten-1 !important;
+  border-color: $bg-color-lighten-1 !important;
+  padding: .5rem;
+  .cv-header-nav {
+    border: $white;
+    border-radius: 10px;
+    button {
+      padding: 10px;
+      background-color: white;
+      transition: all .2s;
+      &:hover {
+        background-color: rgb(141, 140, 140);
+        color: $white;
+      }
+    }
+    .previousYear {
+      border: 1px solid $white;
+      border-radius: 10px 0 0 10px;
+    }
+    .nextYear {
+      border: 1px solid $white;
+      border-radius: 0 10px 10px 0;
+    }
+    .previousPeriod {
+      border-right: none;
+      border-top-color: white;
+      border-bottom-color: white;
+    }
+    .nextPeriod {
+      border-left: none;
+      border-top-color: white;
+      border-bottom-color: white;
+    }
+    .currentPeriod {
+      border-top-color: white;
+      border-bottom-color: white;
+    }
   }
+}
 
-.group__title {
-  text-align: left;
+.periodLabel {
+  color: $white;
 }
-.footer__txt {
-  position: fixed;
-  bottom: 1rem;
-  left: 3rem;
-  opacity: 0.7;
+
+.today {
+  background-color: $white !important;
+  .cv-day-number {
+    color: $white;
+    background-color: $bg-color;
+    border-radius: 50%;
+  }
 }
-.form-group-center {
-  width: 90%;
+
+.theme-default .cv-item {
+  border-color: $bg-color !important;
+  background-color: #fae5e5 !important;
+  border-radius: 5px !important;
+}
+
+.b-table-sticky-header {
+  max-height: 400px;
+}
+
+.step__text {
+  margin-right: 2rem;
+  color: white;
+  font-size: 1.4rem;
+  background-color: #1266f1;
+  box-shadow: 1px 1px 3px 1px rgb(168, 168, 168);
+  padding: .5rem .75rem;
+  border-radius: 3.5rem;
+}
+/* search bar */
+.text_input {
+  margin: 1.5rem;
+  padding-top: 2rem;
+  padding-bottom: 2rem;
+}
+/* .search__form {
+  width: 45rem;
+  margin: 2rem 1.5rem;
+} */
+.text__bar {
+  width: 420px;
+  height: 150px;
+  padding: .5rem;
+  transition: all .3s;
+  border: 3px solid rgb(187, 187, 187);
+  border-radius: 10px;
+}
+input[type="radio"] {
+  display: none;
+}
+input[type="radio"]:checked + label {
+  outline: 4px solid #1266f1;
+}
+
+/* .search__btn {
+  padding: 8px 24px;
+} */
+
+.submit.disabled {
+  pointer-events: none;
+  background-color: rgb(148, 147, 147);
+
+}
+.search__form .text__bar:focus {
+  box-shadow: 1px 1px 3px 1px #1266f1;
+  border-radius: 10px;
+}
+
+.h3 {
+  font-size: 2rem;
+}
+
+.characs {
+  margin: 2rem 1.5rem;
+}
+.characs_fr {
+  width: 120px;
+  height: 150px;
+  object-fit: cover;
+}
+.characs_fr > img {
+  width: 100%;
+  height: 100%;
+} 
+
+.back_fr {
+  width: 180px;
+  height: 150px;
+  object-fit: cover;
+}
+.back_fr > img {
+  width: 100%;
+  height: 100%;
+} 
+.submit {
+  color: white;
+  font-size: 1.4rem;
+  background-color: #1266f1;
+  box-shadow: 1px 1px 3px 1px rgb(168, 168, 168);
+  padding: .75rem 2rem;
+  border-radius: 3.5rem;
+  outline: none;
+  transition: all .3s;
+}
+.submit:hover {
+  transform: scale(1.05);
+}
+/* card */
+.card{
+  transition: all .3s;
+  cursor: pointer;
+}
+.card:hover {
+  transform: scale(1.05);
+}
+.card.card__notHover {
+  transform: scale(1);
+}
+.card-title {
+  font-size: 1.3rem;
+}
+/* top card */
+.card__grback {
+  background-image: linear-gradient(105deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.9) 75%, #1266f1 75%, #1266f1 100%);
+  background-position: center;
+  background-size: contain;
+  margin-top: 2rem;
+}
+.card__left {
+  width: 75%;
+}
+.card__url {
+  font-size: 1.8rem;
+  margin-bottom: 1.5rem;
+}
+.card__url__icon {
+  display: inline-block;
+  margin-right: 1rem;
+  font-size: 1.4rem;
+}
+.card__intro {
+  font-size: .9rem;
+  line-height: 1.5rem;
+}
+.intro_text {
+  padding-top: .5rem;
+  padding-bottom: .5rem;
+  padding-left: 4rem;
+}
+.intro_text:nth-of-type(2) {
+  padding-left: 3rem;
+}
+.intro_text:nth-of-type(3) {
+  padding-left: 2rem;
+}
+.intro_text:nth-of-type(4) {
+  padding-left: 1rem;
+}
+.intro_num {
+  display: inline-block;
+  background-color: lightblue;
+  width: 20px;
+  height: 20px;
+  border-radius: 50%;
+  text-align: center;
+  line-height: 20px;
+  position: relative;
+  z-index: 2;
+}
+.intro_num::after{
+  content: " ";
   position: absolute;
-  top: 30%;
+  top: 100%;
+  left: 0;
+  width: 100%;
+  height: 22px;
+  border-left: 2px solid gray;
+  transform: rotate(25deg);
+  z-index: 1;
+}
+.intro_num_last::after {
+  display: none;
+}
+.download {
+  margin-top: 1.5rem;
+  transition: all .3s;
+}
+.download:hover {
+  background-color: #1266f1;
+  color: white;
+}
+/* rank card */
+.card__rank__title {
+  font-weight: 500;
+}
+.card__rank__title i {
+  display: inline-block;
+  margin-right: .5rem;
+  font-size: 1.2rem;
+}
+.rank__mark {
+  font-size: 1.4rem;
+  line-height: 1.4rem;
+}
+.rank_num {
+  font-size: 2rem;
+}
+/* chart */
+.chart {
+  width: 600px;
+  height:400px;
+  margin:1.5rem auto;
+}
+.animate_fade{
+  opacity: 0;
+  transform: translateY(-30%);
+  transition: all 1.2s;
+}
+.fade_up{
+  transform: translateY(0%);
+  opacity: 1;
+}
+.intro__last {
+  width: 8rem;
+  height: auto;
+  text-align: center;
+  line-height: 1.5rem;
+}
+.youtube__icon {
+  display: block;
+  font-size: 2rem;;
+}
+.animate_in {
+  opacity: 0;
+  transform: translateX(-30%);
+  transition: all 1s;
+}
+.animate_in:nth-of-type(2) {
+  transition-delay: 1s;
+}
+.animate_in:nth-of-type(3) {
+  transition-delay: 2s;
+}
+.fade_in{
+  transform: translateX(0%);
+  opacity: 1;
+}
 
+.popular__card {
+  color: gray;
+  text-decoration: none;
+  font-weight: 600;
+  .card {
+    padding: 1rem;
+    .popular__word {
+      font-size: 1.2rem;
+      color: gray;
+      margin-left: 1.5rem;
+      margin-right: 2rem;
+      @include small {
+        font-size: 1rem;
+        color: gray;
+        margin-left: .5rem;
+        margin-right: .5rem;
+      }
+    }
+    @include small {
+      padding: .5rem;
+    }
+  }  
+  &:hover {
+    text-decoration: none;
+    color: $black;
+    .popular__word {
+      color: $black;
+    }
+  }
 }
-.group__tag {
-  background-color: #e29595;
-  width: 10rem;
-  color: #f5f5f5;
-  height: 3rem;
-  font-size: 1.5rem;
-  line-height: 2.5rem;
-  border-radius: 10px 10px 0 0 ;
+
+.btn__showmore {
+  background-color: white;
+  border: none;
+  outline: none;
+  box-shadow: 0 0 6px 2px rgb(179, 179, 179);
+  border-radius: 3rem;
+  padding: .4rem 2.5rem;
+  letter-spacing: 1px;
+  transition: all .3s;
+  &:hover {
+    transform: scale(1.05);
+    background-color: $bg-color;
+    color: $white;
+  }
+}
+
+.badge {
+  font-size: 1rem !important;
 }
+
+.kw {
+  &__title {
+    display: inline-block;
+    margin-right: 2rem;
+  }
+  &__query {
+    display: inline-block;
+    font-size: 1.5rem;
+    margin-right: 1rem;
+  }
+  &__icon {
+    font-size: 1.1rem;
+    &__up {
+      color: green;
+    }
+    &__down {
+      color: red;
+    }
+  }
+}
+
+.reltopic {
+  .card-body {
+    padding: .5rem;
+    margin-bottom: 0;
+    font-size: 1.2rem;
+  }
+  &__title {
+    display: inline-block;
+    margin-right: .5rem;
+    font-size: 1.2rem;
+  }
+}
+

+ 5 - 0
src/assets/scss/utilities.scss

@@ -0,0 +1,5 @@
+$black: rgba(27,27,27);
+$white: white;
+$bg-color: #dd6565;
+$bg-color-lighten-1: #e29595;
+$bg-color-lighten-2: #ddacac;

+ 1 - 1
src/assets/scss/variables.scss

@@ -64,7 +64,7 @@ $colors: map-merge(
   $colors
 );
 
-$primary:       #11787A;
+$primary:       #dd6565;
 $primary-darken: #34495E;
 $secondary:     #E67E22;
 $success:       $green !default;

+ 33 - 3
src/main.js

@@ -5,14 +5,15 @@ import 'bootstrap';
 import Loading from 'vue-loading-overlay';
 import 'vue-loading-overlay/dist/vue-loading.css';
 import { BootstrapVue, IconsPlugin } from 'bootstrap-vue';
+import VCharts from 'v-charts'
 import App from './App.vue';
 import router from './router';
 import store from './store';
+import Swal from 'sweetalert2';
 
-Vue.config.productionTip = false;
+Vue.use(VCharts);
 Vue.use(VueAxios, axios);
 Vue.component('Loading', Loading);
-
 import 'bootstrap/dist/css/bootstrap.css'
 import 'bootstrap-vue/dist/bootstrap-vue.css'
 
@@ -26,4 +27,33 @@ new Vue({
   router,
   store,
   render: (h) => h(App),
-}).$mount('#app');
+}).$mount('#app');
+
+function getCookie(name) {
+  const value = `; ${document.cookie}`;
+  const parts = value.split(`; ${name}=`);
+  if (parts.length === 2) return parts.pop().split(';').shift();
+}
+
+router.beforeEach((to, from, next) => {
+  if (to.meta.requiresAuth) {
+    console.log('pass');
+    next();
+    /* axios.get('http://www.googo.org:8050/api/auth/user_status', { 
+      headers: {
+        'Authorization' : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyMCwiZXhwIjoxNjIwNzg5Mzc4LCJzdWIiOjIwfQ.C-S2gPHkZ0RnejcfCFVoYKiwsNuMVH5QZdNqSKvZPZs"
+      }
+    }).then(res => {
+        let userid = res.data.data.user_id;
+        axios.get('http://www.googo.org:8050/api/user_groups_data/20').then(res => {
+          if(res.data.length === 0){
+            next({ path: '/serviceselection'});
+          }else {
+            next();
+          }
+        });
+      }); */
+  } else {
+    next()
+  }
+})

+ 40 - 4
src/router/index.js

@@ -1,14 +1,27 @@
 import Vue from 'vue'
 import VueRouter from 'vue-router'
 import Home from '../views/Home.vue'
+import ServiceSelection from '../views/ServiceSelection.vue'
+import Usernews from '../views/Usernews.vue'
+import Calendarview from '../views/Calendarview.vue'
+import Aivideo from '../views/Aivdeo.vue'
+import Trends from '../views/Trends.vue'
 
 Vue.use(VueRouter)
 
 const routes = [
   {
-    path: '/',
+    path: '/serviceselection',
+    name: 'ServiceSelection',
+    component: ServiceSelection,
+    props: true,
+  },
+  {
+    path: '/cal',
     name: 'Home',
-    component: Home
+    component: Home,
+    props: true,
+    meta: { requiresAuth: true }
   },
   {
     path: '/group_browse',
@@ -16,11 +29,34 @@ const routes = [
     // route level code-splitting
     // this generates a separate chunk (about.[hash].js) for this route
     // which is lazy-loaded when the route is visited.
-    component: () => import(/* webpackChunkName: "about" */ '../views/Groupbrowse.vue')
-  }
+    component: () => import(/* webpackChunkName: "about" */ '../views/Groupbrowse.vue'),
+    props: true,
+    meta: { requiresAuth: true }
+  },
+  {
+    path: '/usernews',
+    name: 'Usernews',
+    component: Usernews,
+  },
+  {
+    path: '/calendarview',
+    name: 'Calendarview',
+    component: Calendarview,
+  },
+  {
+    path: '/aivideo',
+    name: 'Aivideo',
+    component: Aivideo,
+  },
+  {
+    path: '/',
+    name: 'Trends',
+    component: Trends,
+  },
 ]
 
 const router = new VueRouter({
+  linkActiveClass: 'active',
   routes
 })
 

+ 163 - 0
src/views/Aivdeo.vue

@@ -0,0 +1,163 @@
+<template>
+    <div>
+        <div class="container">
+            <div class="row">
+                <div class='col-12'>
+                    <div class="card card__grback mb-5">
+                        <div class="card-body card__left">
+                        <!-- 根據搜尋內容顯示網站標題及網站內容簡介 -->
+                        <h5 class="card-title card__url" id="sitetitle"><i class="fas fa-book-open card__url__icon"></i>如何使用</h5>
+                        <div class="d-flex align-items-center justify-content-between">
+                            <div class="mr-4 animate_in">
+                            <div>
+                                <i class="fas fa-exclamation"></i>
+                                連結Telegram 帳號
+                            </div>
+                            <a class="btn download" href="https://telegram.org/">下載Telegram</a>
+                            </div>
+                            <div class="card-text card__intro animate_in" id="descriptions">
+                            <div class="intro_text pl-4"><span class="intro_num">1</span> 選擇人物 </div>
+                            <div class="intro_text pl-3"><span class="intro_num">2</span> 選擇背景</div>
+                            <div class="intro_text pl-2"><span class="intro_num">3</span> 輸入腳本文字 </div>
+                            <div class="intro_text"><span class="intro_num intro_num_last">4</span> 完成</div>
+                            </div>
+                            <div class="d-flex align-items-center animate_in">
+                            <div style="width:7rem;height:12rem;">
+                                <img src="../assets/Labinaagu.png" alt="" style="width:100%;height:100%;">
+                            </div>
+                            <div class="intro__last"><i class="fas fa-check-circle" style="font-size:1.4rem;color: green;display: block;margin-bottom: 1rem;"></i>等待影片連結傳送至手機</div>
+                            </div>
+                            <!-- <div><i class="fab fa-youtube youtube__icon"></i></div> -->
+                        </div>
+                    <!--  <a href="#" class="btn btn-primary" id="globalrank2"></a> -->
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="text_input animate_fade">
+        <div class="step d-flex align-items-center">
+          <h3 class='step__text'>Step 1</h3>
+          <hr style="width:8rem;border-top:1.5px dotted grey;margin-right:.5rem;">
+          <span>選擇人物</span>
+        </div>
+        <div class='characs d-flex w-100'>
+          <div class="row justify-content-around">
+            <div class="col-sm-12 col-md-4">
+              <input type="radio" id="num1" name="characs" value="num1" checked>
+              <label for="num1"><div class="card characs_fr"><img src="../assets/girl1.png" alt=""></div></label>
+            </div>
+            <div class="col-sm-12 col-md-4">
+              <input type="radio" id="num2" name="characs" value="num2">
+              <label for="num2"><div class="card characs_fr"><img src="../assets/girl2.png" alt=""></div></label>
+            </div>
+            <div class="col-sm-12 col-md-4">
+              <input type="radio" id="num3" name="characs" value="num3">
+              <label for="num3"><div class="card characs_fr"><img src="../assets/girl3.png" alt=""></div></label>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="text_input animate_fade">
+        <div class="step d-flex align-items-center">
+          <h3 class='step__text'>Step 2</h3>
+          <hr style="width:8rem;border-top:1.5px dotted grey;margin-right:.5rem;">
+          <span>選擇背景</span>
+        </div>
+        <div class='characs d-flex w-100'>
+          <div class="row justify-content-around">
+            <div class="col-sm-12 col-md-3">
+              <input type="radio" id="back1" name="back" value="back1" checked>
+              <label for="back1"><div class="card back_fr"><img src="../assets/patrick-perkins-3wylDrjxH-E-unsplash.jpg" alt=""></div></label>
+            </div>
+            <div class="col-sm-12 col-md-3">
+              <input type="radio" id="back2" name="back" value="back2">
+              <label for="back2"><div class="card back_fr"><img src="../assets/alberto-castillo-q-mx4mSkK9zeo-unsplash.jpg" alt=""></div></label>
+            </div>
+            <div class="col-sm-12 col-md-3">
+              <input type="radio" id="back3" name="back" value="back3">
+              <label for="back3"><div class="card back_fr"><img src="../assets/jarek-ceborski-jn7uVeCdf6U-unsplash.jpg" alt=""></div></label>
+            </div>
+            <div class="col-sm-12 col-md-3">
+              <input type="radio" id="back4" name="back" value="back4">
+              <label for="back4"><div class="card back_fr"><img src="../assets/kelsey-dody-mt2QzllH814-unsplash.jpg" alt=""></div></label>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="text_input animate_fade">
+        <div class="step d-flex align-items-center">
+          <h3 class='step__text'>Step 3</h3>
+          <hr style="width:8rem;border-top:1.5px dotted grey;margin-right:.5rem;">
+          <span>輸入您的專屬影片的腳本文字</span>
+        </div>
+        <form id="searchform" class="d-flex input-group search__form">
+          <textarea form="searchform" class="text__bar" placeholder="輸入腳本文字" aria-label="Domain Name" id="search_query"></textarea>
+          <!-- <button class="btn btn-primary search__btn" type="button" data-mdb-ripple-color="dark" id="search__btn">
+              完成
+          </button> -->
+        </form>
+      </div>
+      <div class="text_input text-center">
+        <button type="submit" class="submit disabled">送出</button>
+      </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'Aivideo',
+    data() {
+        return {
+            submit: true,
+        }
+    },
+    methods: {
+        onloadFadein() {
+            const animate_in = document.querySelectorAll('.animate_in');
+            window.onload = function() {
+                for(let i = 0;i < animate_in.length;i++) {
+                    animate_in[i].classList.add('fade_in');
+                }
+            }
+        },
+        scrolling() {
+            const text_input = document.querySelectorAll('.text_input');
+            for(let i = 0;i < text_input.length;i++){
+                const scrollPos = window.innerHeight + window.scrollY;
+                if(scrollPos >= text_input[i].offsetTop){
+                    text_input[i].classList.add('fade_up');
+                }
+            }
+        }
+    },
+    mounted() {
+        this.onloadFadein();
+        window.addEventListener('scroll', this.scrolling);
+    },
+    destroyed() {
+        window.removeEventListener('scroll', this.scrolling);
+    },
+    created() {
+
+    }
+}
+/* const input = document.getElementById("search_query");
+const search__btn = document.getElementById("search__btn");
+const submit__btn = document.querySelector('.submit');
+const search__bar = document.querySelector('.search__bar');
+
+
+search__bar.addEventListener('mouseenter', function() {
+  if(search__bar.value) {
+    submit__btn.classList.remove('disabled');
+  }
+});
+search__bar.addEventListener('mouseleave', function() {
+  if(search__bar.value) {
+    submit__btn.classList.remove('disabled');
+  }
+});
+ */
+
+</script>

+ 276 - 0
src/views/Calendarview.vue

@@ -0,0 +1,276 @@
+<template>
+    <div class="container">
+        <div class="calendar-control mb-3 d-flex align-items-center justify-content-between">
+            <div class='group__box'>
+                <label class="label mb-0 mr-3">客群</label>
+				<div class="control">
+					<div class="select">
+					    <select v-model="group" class="selector">
+							<option selected>服裝配件</option>
+							<option>美妝</option>
+							<option>旅遊</option>
+						</select>
+					</div>
+				</div>
+            </div>
+           <!--  <div class='group__box'>
+                <label class="label mb-0 mr-2">範圍</label>
+				<div class="control">
+					<div class="select">
+					    <select v-model="dateRange" class="selector">
+							<option>月</option>
+							<option>雙週</option>
+							<option>單週</option>
+						</select>
+					</div>
+				</div>
+            </div> -->
+            <div class="btn-group group__btn" role="group" aria-label="date-buttons">
+                <button type="button" class="btn__date" @click.prevent="periodChange('week', 1)" :class="{'active': displayPeriodUom === 'week' && displayPeriodCount === 1 }">單週</button>
+                <button type="button" class="btn__date" @click.prevent="periodChange('week', 2)" :class="{'active': displayPeriodUom === 'week' && displayPeriodCount === 2 }">雙週</button>
+                <button type="button" class="btn__date" @click.prevent="periodChange('month', 1)" :class="{'active': displayPeriodUom === 'month'}">月</button>
+            </div>
+        </div>
+        <div class="calendar-parent">
+			<calendar-view
+				:items="items"
+				:show-date="showDate"
+				:time-format-options="{ hour: 'numeric', minute: '2-digit' }"
+				:enable-drag-drop="true"
+				:disable-past="disablePast"
+				:disable-future="disableFuture"
+				:show-times="showTimes"
+				:display-period-uom="displayPeriodUom"
+				:display-period-count="displayPeriodCount"
+				:starting-day-of-week="startingDayOfWeek"
+				:class="themeClasses"
+				:period-changed-callback="periodChanged"
+				:current-period-label="useTodayIcons ? 'icons' : ''"
+				:displayWeekNumbers="displayWeekNumbers"
+				:enable-date-selection="true"
+				:selection-start="selectionStart"
+				:selection-end="selectionEnd"
+                :itemContentHeight='itemContentHeight'
+				@date-selection-start="setSelection"
+				@date-selection="setSelection"
+				@date-selection-finish="finishSelection"
+				@drop-on-date="onDrop"
+				@click-date="onClickDay"
+				@click-item="onClickItem"
+			>
+				<calendar-view-header
+					slot="header"
+					slot-scope="{ headerProps }"
+					:header-props="headerProps"
+					@input="setShowDate"
+				/>
+			</calendar-view>
+		</div>
+    </div>
+</template>
+
+<script>
+import $ from 'jquery';
+/* import "../../node_modules/vue-simple-calendar/dist/style.css"
+import "../../node_modules/vue-simple-calendar/static/css/default.css"
+import "../../node_modules/vue-simple-calendar/static/css/holidays-us.css" */
+import { CalendarView, CalendarViewHeader, CalendarMathMixin } from "vue-simple-calendar"
+require("vue-simple-calendar/static/css/default.css")
+// require("vue-simple-calendar/static/css/holidays-us.css")
+
+export default {
+    components: {
+        CalendarView,
+        CalendarViewHeader
+    },
+	mixins: [CalendarMathMixin],
+	data() {
+		return {
+			/* Show the current month, and give it some fake items to show */
+			showDate: this.thisMonth(10),
+			message: "",
+			startingDayOfWeek: 0,
+			disablePast: false,
+			disableFuture: false,
+			displayPeriodUom: "week",
+			displayPeriodCount: 1,
+			displayWeekNumbers: false,
+			showTimes: true,
+			selectionStart: null,
+			selectionEnd: null,
+			newItemTitle: "",
+			newItemStartDate: "",
+			newItemEndDate: "",
+			useDefaultTheme: true,
+			useHolidayTheme: true,
+            useTodayIcons: false,
+            itemContentHeight: '2rem',
+            group: '服裝配件',
+            dateRange: '單週',
+			items: [
+				{
+					id: "e0",
+					startDate: "2018-01-05",
+				},
+				{
+					id: "e1",
+					startDate: this.thisMonth(15, 18, 30),
+				},
+				{
+					id: "e2",
+					startDate: this.thisMonth(15),
+					title: "Single-day item with a long title",
+                },
+                /*
+				{
+					id: "e3",
+					startDate: this.thisMonth(7, 9, 25),
+					endDate: this.thisMonth(10, 16, 30),
+					title: "Multi-day item with a long title and times",
+				},
+				{
+					id: "e4",
+					startDate: this.thisMonth(20),
+					title: "My Birthday!",
+					classes: "birthday",
+					url: "https://en.wikipedia.org/wiki/Birthday",
+				},
+				{
+					id: "e5",
+					startDate: this.thisMonth(5),
+					endDate: this.thisMonth(12),
+					title: "Multi-day item",
+					classes: "purple",
+				},
+				{
+					id: "foo",
+					startDate: this.thisMonth(29),
+					title: "Same day 1",
+				},
+				{
+					id: "e6",
+					startDate: this.thisMonth(29),
+					title: "Same day 2",
+					classes: "orange",
+				},
+				{
+					id: "e7",
+					startDate: this.thisMonth(29),
+					title: "Same day 3",
+				},
+				{
+					id: "e8",
+					startDate: this.thisMonth(29),
+					title: "Same day 4",
+					classes: "orange",
+				}, */
+				{
+					id: "e9",
+					startDate: this.thisMonth(29),
+					title: "Same day 5",
+				},
+				{
+					id: "e10",
+					startDate: this.thisMonth(29),
+					title: "Same day 6",
+					classes: "orange",
+				},
+				{
+					id: "e11",
+					startDate: this.thisMonth(29),
+					title: "Same day 7",
+				},
+			],
+		}
+	},
+	computed: {
+		userLocale() {
+			return this.getDefaultBrowserLocale
+		},
+		dayNames() {
+			return this.getFormattedWeekdayNames(this.userLocale, "long", 0)
+		},
+		themeClasses() {
+			return {
+				"theme-default": this.useDefaultTheme,
+				"holiday-us-traditional": this.useHolidayTheme,
+				"holiday-us-official": this.useHolidayTheme,
+			}
+        },
+	},
+	mounted() {
+        document.querySelector('.calendar-parent').addEventListener('mousemove', this.mouse);
+		this.newItemStartDate = this.isoYearMonthDay(this.today())
+        this.newItemEndDate = this.isoYearMonthDay(this.today())
+    },
+    destroyed() {
+        document.querySelector('.calendar-parent').removeEventListener('mousemove', this.mouse);
+    },
+	methods: {
+        mouse() {
+            $('.cv-item').mouseenter(function(){
+                $(this).nextAll().css({'transform': 'translateY(2rem)'});
+                console.log('test');
+            });
+            $('.cv-item').mouseleave(function(){
+                $(this).nextAll().css({'transform': 'translateY(0rem)'});
+            });
+        },
+        periodChange(period, num) {
+            this.displayPeriodUom = period;
+            this.displayPeriodCount = num;
+        },
+		periodChanged() {
+			// range, eventSource) {
+			// Demo does nothing with this information, just including the method to demonstrate how
+			// you can listen for changes to the displayed range and react to them (by loading items, etc.)
+			//console.log(eventSource)
+			//console.log(range)
+		},
+		thisMonth(d, h, m) {
+			const t = new Date()
+			return new Date(t.getFullYear(), t.getMonth(), d, h || 0, m || 0)
+		},
+		onClickDay(d) {
+			this.selectionStart = null
+			this.selectionEnd = null
+			this.message = `You clicked: ${d.toLocaleDateString()}`
+		},
+		onClickItem(e) {
+            this.message = `You clicked: ${e.title}`
+            e.classes.push('clicked');
+		},
+		setShowDate(d) {
+			this.message = `Changing calendar view to ${d.toLocaleDateString()}`
+			this.showDate = d
+		},
+		setSelection(dateRange) {
+			this.selectionEnd = dateRange[1]
+			this.selectionStart = dateRange[0]
+		},
+		finishSelection(dateRange) {
+			this.setSelection(dateRange)
+			this.message = `You selected: ${this.selectionStart.toLocaleDateString()} -${this.selectionEnd.toLocaleDateString()}`
+		},
+		onDrop(item, date) {
+			this.message = `You dropped ${item.id} on ${date.toLocaleDateString()}`
+			// Determine the delta between the old start date and the date chosen,
+			// and apply that delta to both the start and end date to move the item.
+			const eLength = this.dayDiff(item.startDate, date)
+			item.originalItem.startDate = this.addDays(item.startDate, eLength)
+			item.originalItem.endDate = this.addDays(item.endDate, eLength)
+		},
+		clickTestAddItem() {
+			this.items.push({
+				startDate: this.newItemStartDate,
+				endDate: this.newItemEndDate,
+				title: this.newItemTitle,
+				id: "e" + Math.random().toString(36).substr(2, 10),
+			})
+			this.message = "You added a calendar item!"
+		},
+    },
+    created() {
+    }
+}
+</script>

+ 52 - 59
src/views/Groupbrowse.vue

@@ -1,5 +1,10 @@
 <template>
   <div>
+    <Loading :active.sync="isLoading" :opacity="0.8">
+      <template slot="default">
+        <img src="../assets/ajax-loader.gif">
+      </template>
+    </Loading>
     <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3">
         <h1 class="h2">客群瀏覽</h1>
     </div>
@@ -7,9 +12,9 @@
     <div class="row group__row">
         <div class="col-3 mb-2" v-for="(group, idx) in user_groups" :key="idx">
             <div class='card p-3 card__subsribed'>
-                <button class="btn__del"><i class="fas fa-trash-alt"></i></button>
+                <button class="btn__del" @click.prevent="unsubscribe(group.group_id)"><i class="fas fa-trash-alt"></i></button>
                 <img class="card-img-top d-block mx-auto" src="../assets/man.svg" alt="">
-                <h4 class='text-center'>{{ group.groups.group_chinese_name }}</h4>
+                <h4 class='text-center'>{{ group.group.group_chinese_name }}</h4>
             </div>
         </div>
     </div>
@@ -65,15 +70,19 @@ export default {
         user_groups: [],
         types: [],
         allGroup: [],
-        unSubgroup: []
+        unSubgroup: [],
+        isLoading: false,
       }
   },
+  props: [
+    'userId'
+  ],
   methods: {
-    getGroup() {
+    getGroup(id) {
         const vm = this;
+        vm.isLoading = true;
         this.$http.get('http://www.googo.org:8050/api/groups').then(res => {
             this.groups = res.data;
-            console.log(this.groups);
             let arr = [];
             this.groups.forEach((item, idx) => {
                 arr.push(item.group_type);
@@ -82,7 +91,6 @@ export default {
                 return arr.indexOf(el) === idx;
             })
             this.types = arr;
-            console.log(this.types);
             let temparr = [];
             this.types.forEach((item, i) => {
                 let tempgrp = vm.groups.filter((el, idx) => {
@@ -91,73 +99,58 @@ export default {
                 temparr.push({group_type: item, data: [...tempgrp] });
             });
             this.allGroup = temparr;
-            console.log(temparr);
-        });
+            let tempgrps = [...res.data];
+            return vm.$http.get(`http://www.googo.org:8050/api/user_groups/${id}`);
+        }).then(res => {
+            vm.user_groups = res.data;
+                let subedArr = vm.user_groups.map((item, idx) => { return item.group_id});
+                let allgrpArr = vm.groups.map((item, idx) => { return item.id});
+                let indexArr = [];
+                allgrpArr.forEach((item, idx) => {
+                    if(!subedArr.includes(item)){
+                        indexArr.push(item);
+                    }
+                })
+                let unsub = [];
+                vm.groups.forEach((item,i) => {
+                    indexArr.forEach((el, i) => {
+                        if(el === item.id) {
+                            unsub.push(item);
+                        }
+                    })
+                });
+                vm.unSubgroup = unsub;
+                vm.isLoading = false;
+        })
+            
     },
-    getUsergroup() {
+    getUsergroup(id) {
         const vm = this;
-        this.$http.get('http://www.googo.org:8050/api/user_groups_data/1').then(res => {
+        this.$http.get(`http://www.googo.org:8050/api/user_groups/${id}`).then(res => {
             this.user_groups = res.data;
-            let arr = [];
-        /* vm.user_groups.forEach((item, idx) => {
-            let temparr = Object.assign({}, item.groups);
-            arr.push(temparr);
-        });
-        console.log(arr);
-        let tempgrps = [...vm.groups];
-        console.log(vm.groups);
-        tempgrps.forEach((item, idx) => {
-            arr.forEach((d, i) => {
-                if(d.id == item.id){
-                    tempgrps.splice(idx, 1);
-                }
-            })
-        }); */
         })
     },
-    getUnsub() {
-        const vm = this;
-        this.$http.get('http://www.googo.org:8050/api/groups').then(res => {
-            let tempgrps = [...res.data];
-            // console.log(tempgrps);
-            // console.log(vm.user_groups);
-            let arr = [];
-            vm.user_groups.forEach((item, idx) => {
-            let temparr = Object.assign({}, item.groups);
-            arr.push(temparr);
-            });
-            console.log(arr);
-            arr.forEach((item, idx) => {
-                tempgrps.forEach((d, i) => {
-                    if(d.id === item.id){
-                        tempgrps.splice(i, 1);
-                    }
-                })
-            });
-            this.unSubgroup = tempgrps;
-            console.log(this.unSubgroup);
-        });
-    },
     subscribe(id) {
         const vm = this;
-          this.$http.post('http://www.googo.org:8050/api/users_groups/1',
+          this.$http.post(`http://www.googo.org:8050/api/users_groups/${this.userId}`,
            { group_ids: [id] }).then(res => {
-            console.log(res.data);
-            vm.getGroup();
-            vm.getUsergroup();
-            vm.getUnsub();
+            vm.getGroup(this.userId);
+            vm.getUsergroup(this.userId);
           })
     },
-    showtab(tab) {
-        bootstrap.Tab.getInstance(document.querySelector(`#${tab}-tab`)).show();
+    unsubscribe(id) {
+        const vm = this;
+          this.$http.delete(`http://www.googo.org:8050/api/users_groups/${this.userId}?group_id=${id}`).then(res => {
+            vm.getGroup(this.userId);
+            vm.getUsergroup(this.userId);
+          })
     }
  },
  computed: {
  },
  created() {
-    this.getGroup();
-    this.getUsergroup();
-    this.getUnsub();
-    }
+    this.getUsergroup(this.userId);
+    this.getGroup(this.userId);
+}
 }
 </script>

+ 64 - 88
src/views/Home.vue

@@ -1,22 +1,11 @@
 <template>
   <div>
-     <div class="form-group form-group-center" v-if="!table_show">
-      <label for="exampleFormControlSelect1" class="mb-2">請選擇您的產業別</label>
-      <select class="form-control mb-3" id="exampleFormControlSelect1" v-model="serviceSelected">
-        <option disabled value>產業別</option>
-        <option v-for="li in servicelist" :key="li.id" :value="li.name">{{ li.name }}</option>
-      </select>
-      <button @click.prevent="submit_type" class="btn__kw">送出</button>
-      </div>
-      <div>
-        <p>產業別: <span>{{ serviceSelected }}</span></p>
-      </div>
     <Loading :active.sync="isLoading" :opacity="0.8">
       <template slot="default">
         <img src="../assets/ajax-loader.gif">
       </template>
     </Loading>
-    <template v-if="serviceSelected && table_show">
+    <template v-if="table_show">
        <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center
       pb-2 mb-3">
       <h1 class="h2">近一季行銷建議</h1>
@@ -43,23 +32,17 @@
           <tbody>
             <tr v-for="item in customData" :key="`gr-${item.id}`">
               <th>{{ item.groups.group_chinese_name }}</th>
-              <td v-for="(t,idx) in item.groups.trends[i]" :key="idx">
+              <td v-for="(t,idx) in item.groups.trends[i]" :key="`tr-${idx}`">
                 <button type="button" class="btn__kw" data-toggle="modal"
                 data-target="#exampleModalCenter"
-                @click.prevent="showModal(item.groups.data_suggests)">關鍵字</button>
-                <div class="highTrend dark-1 p-2 mt-2" v-if="check(t.popularity, item.groups)">Popular</div>
+                @click.prevent="showModal(item.groups.data_suggests)" v-b-tooltip.hover.righttop="'點選查看常用關鍵字組'">關鍵字</button>
+                <div class="highTrend dark-1 p-2 mt-2" v-b-tooltip.hover.righttop="'該客群的搜尋次數高於歷史平均值'" variant="primary" v-if="check(t.popularity, item.groups)">Popular</div>
               </td>
             </tr>
-           <!--  <tr v-for="(item ,it) in json" :key="it">
-              <th>{{ item.group }}</th>
-              <td v-for="(t, idx) in item.orgData[i]" :key="idx">
-                <div class="p-2 mt-2">{{ t.data }}</div>
-              </td>
-            </tr> -->
           </tbody>
       </table>
-    </div>
-    <div class="table-responsive mb-3" v-for="(month, i) in month" :key="i" v-if='selected == i'> <!-- eslint-disable-line-->
+    
+    
       <h3 class="">2019-20行銷事項參考</h3>
       <table class="table">
         <thead>
@@ -114,11 +97,16 @@
 <script>
 // @ is an alias to /src
 import $ from 'jquery';
+import axios from 'axios';
 
 export default {
   name: 'Home',
   components: {
   },
+  props: [
+    'userId',
+    'logselected'
+  ],
   data() {
     return {
       group_datas: [],
@@ -132,7 +120,7 @@ export default {
       customData: [],
       servicelist: [],
       serviceSelected: '',
-      table_show: false
+      table_show: true,
     };
   },
   methods: {
@@ -166,9 +154,7 @@ export default {
             }
         },
         getcalData() {
-          this.isLoading = true;
           this.$http.get('http://www.googo.org:8050/api/get_2020_marketing_cal').then(res => {
-                console.log(res.data);
                 this.json = res.data;
                 this.json.splice(34);
                 this.json.forEach((item, idx) => {
@@ -185,64 +171,36 @@ export default {
                     });
                     item['orgData'].splice(0, 1);
                 })
-                this.isLoading = false;
             });
         },
-        getCustomData() {
-          this.$http.get('http://www.googo.org:8050/api/user_groups_data/1').then(res => {
-                this.customData = res.data;
-                /* this.customData.forEach((el, i) => {
-                  let dateArr = [];
-                  el.groups.data_suggests.forEach((item, idx) => {
-                    dateArr.push(item.start);
-                  });
-                 //console.log(dateArr);
-                  let dateset = new Set(dateArr);
-                  console.log(Array.from(dateset));
-                  dateset = Array.from(dateset);
-                  console.log(dateset);
-
-                }); */
-                
-                /* this.customData.forEach((item, idx) => {
-                  let arr = [];
-                  item.groups.data_suggests.forEach((d, i) => {
-                    if(d['data_type'] == 'suggests'){
-                      arr.push({start: d.start, end: d.end, words: d.data.data});
-                    } else {
-                      item.groups.trends = d.data.data;
-                    }
-                  });
-                  arr.reverse();
-                  item.groups.suggests = arr;
-                }); */
-                this.customData.forEach((item, idx) => {
-                  const temp = this.GetObjVal(item.groups.data_trends);
-                  let newD = [];
-                  item.groups.data_trends.forEach((k, i) => {
-                    if(i%3===0){
-                      newD.push([]);
-                    }
-                    const page = parseInt(i/3);
-                    newD[page].push(k);
-                    item.groups.trends = newD;
-                });
-                console.log(this.customData);
+        getCustomData(id) {
+          const vm = this;
+          vm.isLoading = true;
+          this.$http.get(`http://www.googo.org:8050/api/user_groups_data/${id}`).then(res => {
+                vm.customData = res.data;
+                vm.customData.forEach((item, idx) => {
+                  if(item.groups.data_trends) {
+                    let newD = [];
+                    item.groups.data_trends.forEach((k, i) => {
+                      if(i%3===0){
+                        newD.push([]);
+                      }
+                      const page = parseInt(i/3);
+                      newD[page].push(k);
+                    });
+                  item.groups.trends = newD;
+                  }else {
+                     item.groups.trends = [
+                      [{popularity: 0}, {popularity: 0}, {popularity: 0}],
+                      [{popularity: 0}, {popularity: 0}, {popularity: 0}],
+                      [{popularity: 0}, {popularity: 0}, {popularity: 0}],
+                      [{popularity: 0}, {popularity: 0}, {popularity: 0}]
+                    ]
+                  }
             });
+            vm.isLoading = false;
           });
         },
-        mergeData() {
-            this.user_groups.forEach(item => {
-                this.group_datas.forEach(d => {
-                    if(d['data_type'] == 'suggests') {
-                        item.suggests = d.data.data;
-                    };
-                    if(d['data_type'] == 'trends') {
-                        item.trends = d.data.data;
-                    }
-                })
-            });
-        },
         GetObjVal(val) {
             return Object.values(val);
         },
@@ -262,7 +220,6 @@ export default {
         },
         getServTypeLi() {
           this.$http.get('http://www.googo.org:8050/api/service_type/').then(res => {
-            console.log(res.data);
             this.servicelist = res.data;
           });
         },
@@ -270,13 +227,33 @@ export default {
           // console.log(this.serviceSelected);
           const vm = this;
           vm.table_show = true;
-          /* this.$http.post('http://www.googo.org:8050/api/users_groups/1',
-           { service_type: this.serviceSelected }).then(res => {
-            console.log(res.data);
-            vm.table_show = true;
-          }) */
-        }
+          this.getCustomData();
+          this.getcalData();
+        },
+        examineLog() {
+          if(this.logselected) {
+            this.getCustomData();
+          }else {
+            this.table_show = false;
+          }
+        },
   },
+ /*  beforeRouteEnter (to, from, next) {
+    axios.get('http://www.googo.org:8050/api/auth/user_status', { 
+      headers: {
+        'Authorization' : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyMCwiZXhwIjoxNjIwNzg5Mzc4LCJzdWIiOjIwfQ.C-S2gPHkZ0RnejcfCFVoYKiwsNuMVH5QZdNqSKvZPZs"
+      }
+    }).then(res => {
+        let userid = res.data.data.user_id;
+        axios.get('http://www.googo.org:8050/api/user_groups_data/20').then(res => {
+          if(res.data.length === 0){
+            next({ path: '/serviceselection'});
+          }else {
+            next();
+          }
+        });
+      });
+  }, */
   created() {
     const d = new Date();
     const m = d.getMonth();
@@ -289,10 +266,9 @@ export default {
     } else {
       this.selected = 3;
     };
+    this.getCustomData(this.userId);
     this.getcalData();
-   // $('#enterModalCenter').modal('show');
     this.getServTypeLi();
-    this.getCustomData();
   }
 };
 

+ 47 - 0
src/views/ServiceSelection.vue

@@ -0,0 +1,47 @@
+<template>
+    <div>
+        <div class="form-group form-group-center">
+            <label for="exampleFormControlSelect1" class="mb-2">請選擇您的產業別</label>
+            <select class="form-control mb-3" id="exampleFormControlSelect1" v-model="serviceSelected">
+                <option disabled value>產業別</option>
+                <option v-for="li in servicelist" :key="li.id" :value="li.name">{{ li.name }}</option>
+            </select>
+            <button @click.once.prevent="submit_type" class="btn__kw">送出</button>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'ServiceSelection',
+    props: [
+    'userId',
+    'logselected'
+    ],
+    data(){
+        return{
+            servicelist: [],
+            serviceSelected: '',
+        }
+    },
+    methods: {
+        getServTypeLi() {
+          this.$http.get('http://www.googo.org:8050/api/service_type/').then(res => {
+            console.log(res.data);
+            this.servicelist = res.data;
+          });
+        },
+        submit_type() {
+          // console.log(this.serviceSelected);
+          const vm = this;
+         this.$http.post('http://www.googo.org:8050/api/users_groups/20',
+           { service_type: this.serviceSelected }).then(res => {
+            this.$router.push('/');
+          });
+        },
+    },
+    created() {
+        this.getServTypeLi();
+    }
+}
+</script>

+ 193 - 0
src/views/Trends.vue

@@ -0,0 +1,193 @@
+<template>
+    <div>
+        <Loading :active.sync="isLoading" :opacity="0.8">
+            <template slot="default">
+                <img src="../assets/ajax-loader.gif">
+            </template>
+        </Loading>
+        <div class="container">
+            <h3 class="usernews__table__title mt-3">本日熱門關鍵字排行</h3>
+            <div class="row mb-3">
+                <div class="col-6 mb-3" v-for="top in tops" :key="top[0]">
+                    <a href="" class="popular__card">
+                        <div class="card">
+                            <div class="card-content d-flex align-items-center">
+                                <span class="d-inline-block">{{ top[3] }}</span>
+                                <p class="d-inline-block pb-0 mb-0 popular__word">{{ top[1] }}</p>
+                                <i class="fas fa-chart-line"></i>
+                            </div>
+                        </div>
+                    </a>
+                </div>
+            </div>
+            <div class="my-3 mb-5">
+                <button class="btn__showmore" @click.prevent="showMore" v-if="topAmount < 20">
+                    顯示更多
+                </button>
+                <button class="btn__showmore" @click.prevent="topAmount = 5;getTops()" v-if="topAmount>=20">
+                    收起
+                </button>
+            </div>
+            <h3 class="usernews__table__title">關鍵字觀測</h3>
+            <form id="searchform" class="d-flex search__form mx-auto">
+                <input type="search" class="search__bar" placeholder="輸入您感興趣的字詞或主題" v-model='query'>
+                <button class="search__btn" type="button" id="search__btn" @click.prevent="search(query)">
+                    <i class="fas fa-search"></i>搜尋
+                </button>
+                <span class="warnmsg" v-if="warnmsg">{{ warnmsg }}</span>
+            </form>
+            <div class="mt-1 history__block" v-if="history.length > 0">
+                <p class="mb-1">最近搜尋字詞</p>
+                <span class="btn btn__searchedWord" v-for="(item, i) in searchedWords" :key="i" @click.prevent="search(item)">{{ item }}
+                    <span class="btn__delete" @click.prevent.stop="deleteWord(item)">X</span>
+                </span>
+            </div>
+            <div class="mb-3 d-flex align-items-center justify-content-between">
+                <div>
+                    <h2 class="text-muted kw__title">關鍵字</h2>
+                    <span class="kw__query">{{ query.trim() }}</span>
+                    <i class="fas fa-long-arrow-alt-up kw__icon kw__icon__up"></i>
+                    <!-- <i class="fas fa-long-arrow-alt-down kw__icon kw__icon__down"></i> -->
+                    <div class="">
+                        <span>正在熱搜關鍵字:</span>
+                        <b-badge href="#" variant="info" v-for="(rec, i) in recommends" :key="i">{{ rec[2] }}</b-badge>
+                    </div>
+                </div>
+                <!-- <div class="btn-group group__btn mb-4" role="group" aria-label="date-buttons">
+                    <button type="button" class="btn__date">單週</button>
+                    <button type="button" class="btn__date">雙週</button>
+                    <button type="button" class="btn__date">月</button>
+                </div> -->
+            </div>
+            <h3 class="usernews__table__title">相關主題</h3>
+            <div class="row mb-5 reltopic">
+                <div class="col-2" v-for="(topic, i) in reltopics" :key="`rel-${i}`">
+                    <b-card>
+                        <h4 class="reltopic__title mb-0">{{ topic[8] }}</h4>
+                        <!-- <i class="fas fa-long-arrow-alt-up kw__icon kw__icon__up"></i> -->
+                    </b-card>
+                </div>
+            </div>
+            <div class="row mb-5">
+                <div class='col-12'>
+                    <b-card shadow>
+                        <div>
+                            <h4>searches / month</h4>
+                            <strong></strong>
+                        </div>
+                        <ve-line :data="chartDatat" :settings="chartSettings" :colors="color"></ve-line>
+                    </b-card>
+                </div>
+            </div>
+        </div> 
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'Usernews',
+    data() {
+        return {
+            query: '',
+            groupChar: [],
+            sortDesc: true,
+            color: ['#dd6565'],
+            fields: [
+                { key: '商品標題', sortable: true },
+                { key: '銷售量', sortable: true },
+                { key: '價格', sortable: true },
+            ],
+            recommends: [
+            ],
+            reltopics: [
+
+            ],
+            chartSettings: {
+                area: true,
+            },
+            chartDatat: {
+                columns: ['月份', '次數'],
+                rows: [
+                    { 月份: '2021-01', 次數: 1000 },
+                    { 月份: '2021-02', 次數: 400 },
+                    { 月份: '2021-03', 次數: 200 },
+                    { 月份: '2021-04', 次數: 600 },
+                    { 月份: '2021-05', 次數: 800 },
+                ]
+            },
+            warnmsg: '',
+            isLoading: false,
+            history: [],
+            tops: [],
+            topAmount: 5,
+        }
+    },
+    methods: {
+        search(words) {
+            const vm = this;
+            vm.warnmsg = '';
+            let word = words.trim();
+            if(word) {
+               // vm.isLoading = true;
+                if(!vm.history.includes(word)){
+                    vm.history.unshift(word);
+                }
+                localStorage.setItem('searchedWords', JSON.stringify(vm.history));
+                vm.$http.get(`http://api.ptt.cx:8000/related_queries/${word}?fd=2020-01-01&td=2021-02-30`).then(res => {
+                    vm.recommends = res.data;
+                    console.log(res.data);
+                    vm.isLoading = false;
+                });
+                vm.$http.get(`http://api.ptt.cx:8000/related_topics/${word}?fd=2020-01-01&td=2021-02-01`).then(res => {
+                    console.log(res.data);
+                    vm.reltopics = res.data;
+                    vm.isLoading = false;
+                })
+            } else {
+                vm.warnmsg = '請輸入字詞';
+                vm.query = '';
+            }
+        },
+        deleteWord(word) {
+            let index = this.history.indexOf(word);
+            this.history.splice(index, 1);
+            localStorage.setItem('searchedWords', JSON.stringify(this.history));
+        },
+        closeModal() {
+            this.$refs['my-modal'].hide();
+        },
+        getTops() {
+            const vm = this;
+            vm.$http.get(`http://api.ptt.cx:8000/ts_top?tc=${vm.topAmount}`).then(res => {
+                console.log(res.data);
+                vm.tops = res.data;
+            });
+        },
+        showMore() {
+            const vm = this;
+            vm.topAmount += 5;
+            if(vm.topAmount >20) {
+                return 
+            } else {
+                vm.getTops();
+            }
+        }
+    },
+    computed: {
+        searchedWords() {
+            if(this.history.length > 3){
+                this.history.pop();
+                localStorage.setItem('searchedWords', JSON.stringify(this.history));
+                return this.history;
+            } else {
+                return this.history;
+            }
+        }
+    },
+    created() {
+        // this.getCharData();
+        this.getTops();
+        this.history = JSON.parse(localStorage.getItem('searchedWords')) || [];
+    }
+}
+</script>

+ 262 - 0
src/views/Usernews.vue

@@ -0,0 +1,262 @@
+<template>
+    <div>
+        <Loading :active.sync="isLoading" :opacity="0.8">
+            <template slot="default">
+                <img src="../assets/ajax-loader.gif">
+            </template>
+        </Loading>
+        <div class="container">
+            <h3 class="usernews__table__title mt-3">本日熱門關鍵字排行</h3>
+            <div class="row mb-3">
+                <div class="col-6 mb-3" v-for="top in tops" :key="top[0]">
+                    <a href="" class="popular__card">
+                        <div class="card">
+                            <div class="card-content d-flex align-items-center">
+                                <span class="d-inline-block">{{ top[3] }}</span>
+                                <p class="d-inline-block pb-0 mb-0 popular__word">{{ top[1] }}</p>
+                                <i class="fas fa-chart-line"></i>
+                            </div>
+                        </div>
+                    </a>
+                </div>
+            </div>
+            <div class="my-3">
+                <button class="btn__showmore" @click.prevent="showMore">
+                    顯示更多
+                </button>
+            </div>
+            <div class="row">
+                <div class='col-12'>
+                    <b-card shadow>
+                        <h4>Sample data</h4>
+                        <div>
+                            <h4>searches / month</h4>
+                            <strong></strong>
+                        </div>
+                        <ve-line :data="chartDatat" :settings="chartSettings" :colors="color"></ve-line>
+                    </b-card>
+                </div>
+            </div>
+            <form id="searchform" class="d-flex search__form mx-auto">
+                <input type="search" class="search__bar" placeholder="輸入您感興趣的產品" v-model='query'>
+                <button class="search__btn" type="button" id="search__btn" @click.prevent="search(query)">
+                    <i class="fas fa-comment mr-1"></i>給我建議
+                </button>
+                <span class="warnmsg" v-if="warnmsg">{{ warnmsg }}</span>
+            </form>
+            <div class="mt-1 history__block" v-if="history.length > 0">
+                <p class="mb-1">最近搜尋字詞</p>
+                <span class="btn btn__searchedWord" v-for="(item, i) in searchedWords" :key="i" @click.prevent="search(item)">{{ item }}
+                    <span class="btn__delete" @click.prevent.stop="deleteWord(item)">X</span>
+                </span>
+            </div>
+            <h3 class="usernews__table__title">其他賣家這麼賣</h3>
+            <div class="mb-5 row align-items-center">
+                <div class="col-12 col-lg-9 col-table">
+                <b-table striped hover sticky-header='400px'
+                    :items="recommends"
+                    :fields="fields" 
+                    :sort-by.sync="sortBy"
+                    :sort-desc.sync="sortDesc"></b-table>
+                </div>
+                <div class="col-12 col-lg-3">
+                    <b-card shadow>
+                        <ve-line :data="chartData[1]" :settings="chartSettings" :colors="color"></ve-line>
+                    </b-card>
+                </div>
+            </div>
+        <!-- <h3 class="usernews__table__title">找文章靈感</h3>
+        <div class="mb-4">
+            <b-table striped hover :items="blogIdeas"></b-table>
+        </div>
+            <h3 class="usernews__table__title">關注商品趨勢</h3>
+            <div class="row my-4">
+                <div class='col-12 col-lg-4 col-card' v-for="(data, i) in groupChar" :key="i">
+                    <b-card shadow>
+                        <h4>{{ data.group_chinese_name }}</h4>
+                        <div>
+                            <h4>searches / month</h4>
+                            <strong>{{ check(data) }}</strong>
+                        </div>
+                        <ve-line :data="chartData[i]" :settings="chartSettings" :colors="color"></ve-line>
+                    </b-card>
+                </div>
+            </div>-->
+        </div> 
+        <b-modal ref="my-modal" hide-footer hide-header title="Using Component Methods">
+            <div class="d-block text-center">
+                <img src="../assets/checked.png">
+                <h3>明天收到資料</h3>
+            </div>
+            <b-button class="mt-3" variant="outline-danger" block @click="closeModal">關閉</b-button>
+        </b-modal>
+        </div>
+</template>
+
+<script>
+export default {
+    name: 'Usernews',
+    data() {
+        return {
+            query: '',
+            groupChar: [],
+            sortBy: '銷售量',
+            sortDesc: true,
+            color: ['#dd6565'],
+            fields: [
+                { key: '商品標題', sortable: true },
+                { key: '銷售量', sortable: true },
+                { key: '價格', sortable: true },
+            ],
+            recommends: [
+            ],
+            chartSettings: {
+                area: true,
+            },
+            chartDatat: {
+                columns: ['月份', '次數'],
+                rows: [
+                    { 月份: '2021-01', 次數: 1000 },
+                    { 月份: '2021-02', 次數: 400 },
+                    { 月份: '2021-03', 次數: 200 },
+                    { 月份: '2021-04', 次數: 600 },
+                    { 月份: '2021-05', 次數: 800 },
+                ]
+            },
+            chartData: [],
+            warnmsg: '',
+            isLoading: false,
+            history: [],
+            tops: [],
+            topAmount: 10,
+        }
+    },
+    methods: {
+        search(words) {
+            const vm = this;
+            vm.warnmsg = '';
+            let word = words.trim();
+            if(word) {
+               // vm.isLoading = true;
+                if(!vm.history.includes(word)){
+                    vm.history.unshift(word);
+                }
+                localStorage.setItem('searchedWords', JSON.stringify(vm.history));
+                vm.$http.post('http://www.googo.org:8050/api/attention_product',
+                { name: word }).then(res => {
+                    console.log(res.data);
+                    vm.$refs['my-modal'].show();
+                })
+                vm.$http.get(`http://www.googo.org:8050/api/shopee_data/?search_keyword=${word}`).then(res => {
+                    let resData = [...res.data];
+                    if(resData.length > 0) {
+                        resData = resData.sort((a,b) => {
+                            return a.sold > b.sold ? -1 : 1;
+                        }).map((el, idx) => {
+                            return { 商品標題: el.title, 銷售量: el.sold, 價格: el.price }
+                        }).slice(0, 49);
+                        console.log(resData);
+                        vm.recommends = resData;
+                    } else {
+                        vm.$http.get(`http://www.googo.org:8050/api/marketing_advice/crawl_shopee/?search=${word}`).then(res => {
+                            let resData = [...res.data];
+                            resData = resData.map((el, idx) => {
+                                return { 商品標題: el.title, 銷售量: el.sold, 價格: el.price }
+                            });
+                            console.log(resData);
+                            vm.recommends = resData;
+                            vm.isLoading = false;
+                        });
+                    }
+                });
+            } else {
+                vm.warnmsg = '請輸入字詞';
+                vm.query = '';
+            }
+        },
+        getCharData() {
+            const vm = this;
+            vm.$http.get('http://www.googo.org:8050/api/groups/data/').then(res => {
+                let resData = [...res.data.slice(0, 3)];
+                vm.groupChar = resData;
+                console.log(resData);
+                let tempData = [];
+                resData.forEach((item, i) => {
+                    let tempTrend = item.data_trends.map((el, idx) => {
+                        return { 月份: el.month, 次數: el.popularity }
+                    }); 
+                    let charData = { columns: ['月份', '次數'], rows: tempTrend};
+                    tempData.push(charData);
+
+                });
+                vm.chartData = tempData;
+                console.log(tempData);
+            });
+        },
+        check(data) {
+            let total = 0;
+            data.data_trends.forEach(item => {
+                total += item.popularity;
+            });
+            let threshold = Math.floor(total / 12);
+            return threshold;
+        },
+        getDefaultData() {
+            const vm  = this;
+            vm.isLoading = true;
+            vm.$http.get('http://www.googo.org:8050/api/marketing_advice/crawl_shopee/?search=%E8%A1%9B%E7%94%9F%E7%B4%99').then(res => {
+                let resData = [...res.data];
+                resData = resData.sort((a,b) => {
+                    return a.sold > b.sold ? -1 : 1;
+                }).map((el, idx) => {
+                    return { 商品標題: el.title, 銷售量: el.sold, 價格: el.price }
+                }).slice(0, 49);
+                console.log(resData);
+                vm.recommends = resData;
+                vm.isLoading = false;
+            })
+        },
+        deleteWord(word) {
+            let index = this.history.indexOf(word);
+            this.history.splice(index, 1);
+            localStorage.setItem('searchedWords', JSON.stringify(this.history));
+        },
+        closeModal() {
+            this.$refs['my-modal'].hide();
+        },
+        getTops() {
+            const vm = this;
+            vm.$http.get(`http://api.ptt.cx:8000/ts_top/${vm.topAmount}`).then(res => {
+                console.log(res.data);
+                vm.tops = res.data;
+            });
+        },
+        showMore() {
+            const vm = this;
+            vm.topAmount += 10;
+            if(vm.topAmount >20) {
+                return 
+            } else {
+                vm.getTops();
+            }
+        }
+    },
+    computed: {
+        searchedWords() {
+            if(this.history.length > 3){
+                this.history.pop();
+                localStorage.setItem('searchedWords', JSON.stringify(this.history));
+                return this.history;
+            } else {
+                return this.history;
+            }
+        }
+    },
+    created() {
+        // this.getCharData();
+        this.getTops();
+        this.getDefaultData();
+        this.history = JSON.parse(localStorage.getItem('searchedWords')) || [];
+    }
+}
+</script>