huaisianhuang 3 年 前
コミット
5856662a5b
4 ファイル変更508 行追加0 行削除
  1. 118 0
      web/Vue.html
  2. 151 0
      web/main.css
  3. 48 0
      web/reset.css
  4. 191 0
      web/vuedata.js

+ 118 - 0
web/Vue.html

@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <title>Document</title>
+    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
+    <link rel="stylesheet" href="main.css">
+    <link rel="stylesheet" href="reset.css">
+    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp"
+    crossorigin="anonymous">
+</head>
+<body class="color__grey">
+    <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="#">行銷日曆</a>
+          </nav>
+          <div class="container-fluid">
+            <div class="row">
+              <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">
+                      <a class="nav-link" href="#">
+                        <i class="fas fa-comment-dots"></i>
+                        近一季行銷建議
+                      </a>
+                    </li>
+                    <li class="nav-item">
+                      <a class="nav-link" href="#">
+                        <i class="fas fa-users"></i>
+                        客群瀏覽
+                      </a>
+                    </li>
+                    <li class="nav-item">
+                      <a class="nav-link" href="#">
+                        <i class="fas fa-quote-left"></i>
+                        關鍵字建議
+                      </a>
+                    </li>
+                  </ul>
+                </div>
+              </nav>
+        
+              <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
+                <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3">
+                  <h1 class="h2">近一季行銷建議</h1>
+                  <div class="d-flex">
+                    <span>季數</span>
+                    <select class="custom-select" v-model='selected'>
+                        <option value="0">Q1</option>
+                        <option value="1">Q2</option>
+                        <option value="2">Q3</option>
+                        <option value="3">Q4</option>
+                    </select>
+                </div>
+                </div>
+                <div class="table-responsive mb-3" v-for="(month, i) in month" :key="i" v-if='selected == i'>
+                  <table class="table">
+                    <thead>
+                      <tr>
+                        <td>客群</td>
+                        <th scope="col" width='320'>{{ month[0] }}</th>
+                        <th scope="col" width='320'>{{ month[1] }}</th>
+                        <th scope="col" width='320'>{{ month[2] }}</th>
+                      </tr>
+                    </thead>
+                    <tbody>
+                        <tr v-for="(item ,k) in user_groups">
+                            <th>客群-{{ item.group_chinese_name }}</th>
+                            <td v-for="t in item.trends[i]">
+                                <button type="button" class="btn__kw" data-toggle="modal" data-target="#exampleModalCenter" @click.prevent="showModal(item.suggests)">關鍵字</button>
+                                
+                                    <div class="highTrend dark-1 p-2 mt-2" v-if="check(t.times, item)">Popular</div>
+                                
+                            </td>
+                        </tr>
+                    </tbody>
+                  </table>
+                </div>
+              </main>
+            </div>
+          </div>
+          <div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenter" aria-hidden="true">
+            <div class="modal-dialog modal-dialog-centered" role="document">
+              <div class="modal-content">
+                <div class="modal-header border-0">
+                  <h5 class="modal-title" id="exampleModalLongTitle">關鍵字群</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>
+                        <template v-for="word in tempkeywords">
+                            <span class="badge badge-warning">{{ word }}</span>
+                        </template>
+                    </div>
+                </div>
+                <div class="modal-footer border-0">
+                  <button type="button" class="btn btn-secondary" data-dismiss="modal">關閉</button>
+                </div>
+              </div>
+            </div>
+          </div>
+    </div>
+    <!-- <footer class="footer text-center p-4 bg-white">
+        <div class="text-muted"> © 2021 Copyright: Googo Website Traffic</div>
+      </footer> -->
+    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
+    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
+    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
+    <script src="vuedata.js"></script>
+</body>
+</html>

+ 151 - 0
web/main.css

@@ -0,0 +1,151 @@
+@import url('https://fonts.googleapis.com/css2?family=Work+Sans:wght@400;500;600&display=swap');
+body {
+    font-family: 'Work Sans', sans-serif;
+}
+/* body background */
+.color__grey {
+    background-color: #f5f5f5;
+}
+
+
+.row {
+    height: 100vh;
+}
+.page-footer {
+    padding-bottom: 20px;
+}
+
+.navbar {
+    background-color: #e57373;
+}
+
+.nav-link {
+    color: rgb(99, 97, 97);
+    padding: 1rem .75rem;
+}
+.nav-link:hover {
+    color: rgb(27, 27, 27);
+}
+.table tbody th, .table tbody td {
+    padding: 1rem;
+}
+
+td[colspan = '2'] {
+    background-color: rgb(160, 245, 245);
+}
+.span {
+    display: block;
+    margin-bottom: .4rem;
+}
+
+
+
+.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;
+  }
+  
+  .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;
+  }
+
+  .dark-2 {
+    background-color: #da3e3e;
+  }
+  .dark-1 {
+    background-color: #dd6565;
+  }
+  .lighten-1 {
+    background-color: #e29595;
+  }
+  .lighten-2 {
+    background-color: #ddacac;
+  }
+
+  .badge {
+      margin: .1rem;
+  }
+  .highTrend {
+      color: white;
+  }
+
+  .btn__kw {
+      padding: .75rem;
+      background-color: #ddacac;
+      border: none;
+      outline: none;
+      border-radius: 5px;
+      transition: all .2s;
+  }
+  .btn__kw:hover {
+    background-color: #e29595;
+  }
+  .btn__kw:focus {
+      outline: none;
+  }
+
+  .badge {
+      font-size: 1rem;
+  }
+  

+ 48 - 0
web/reset.css

@@ -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;
+}

+ 191 - 0
web/vuedata.js

@@ -0,0 +1,191 @@
+const app = new Vue({
+    el:'#app',
+    data:{
+        group_datas: [],
+        user_groups: [],
+        ex: [],
+        month: [['Jan', 'Feb', 'Mar'], ['Apr', 'May', 'Jun'], ['Jul', 'Aug', 'Sep'], ['Oct', 'Nov', 'Dec']],
+        trends: [
+            {
+                group: '婚禮', 
+                data:[
+                    [{month: 'Jan', times: 782}, {month: "Feb", times: 752} , {month: 'Mar', times: 909}],
+                    [{month: 'Apr', times: 880}, {month: 'May', times: 929}, {month: "Jun", times: 883} ],
+                    [{month: 'Jul', times: 855}, {month: 'Aug', times: 776}, {month: 'Sep', times: 1020}],
+                    [{month: "Oct", times: 1206} , {month: 'Nov', times: 1042}, {month: 'Dec', times: 1051}]
+                ]
+            },
+        ],
+        keywords: [
+            { group: "婚禮", words: ['婚禮穿搭', '婚禮穿搭男', '婚禮穿搭dcard', '婚禮穿搭禁忌', ' 婚禮穿搭褲裝', '婚禮穿搭牛仔褲', '婚禮穿搭女', '婚禮穿搭ptt', '婚禮穿搭夏天', '婚禮穿搭 冬天'] },
+            { group: "蔬食", words: ['健康蔬食', '蔬食食譜','素食蔬食']},
+            { group: "室內設計", words: ['室內設計風格', '室內設計圖','室內設計網站']}
+        ],
+        tempkeywords: [],
+        selected: 0,
+        json: [],
+    },
+    methods:{
+        checkback(num) {
+            if(num > 700) {
+                return 'dark-2'
+            } else if (num > 500) {
+                return 'dark-1'
+            } else if (num > 300) {
+                return 'lighten-1'
+            } else {
+                return 'lighten-2'
+            }
+        },
+        showModal(keywords) {
+            $('#exampleModalCenter').modal('show');
+            this.tempkeywords = keywords;
+        },
+        check(num, grpdata) {
+            let total = 0;
+            grpdata.trends.forEach(item => {
+                item.forEach(single => {
+                    total += single.times;
+                })
+            });
+            let threshold = total / 12;
+            if(num > threshold) {
+                return true;
+            } else {
+                return false;
+            }
+        },
+        getData() {
+            axios.get('http://www.googo.org:8050/api/group_datas/').then(res => {
+                this.group_datas = res.data;
+                //console.log(this.group_datas);
+               // this.trends = this.json.filter(item => item['data_type'] === 'trends');
+                //this.keywords = this.json.filter(item => item['data_type'] === 'suggests');
+                
+            });
+            axios.get('http://www.googo.org:8050/api/user_groups/').then(res => {
+                //console.log(res.data);
+                this.user_groups = res.data;
+                this.user_groups.forEach(item => {
+                    this.group_datas.forEach(d => {
+                        if(d.group_id === item.id) {
+                            d.group_chinese_name = item.group_chinese_name;
+                        }
+                    })
+                });
+                //console.log(this.group_datas);
+                this.trends = this.group_datas.filter(item => item['data_type'] === 'trends');
+                this.keywords = this.group_datas.filter(item => item['data_type'] === 'suggests');
+                this.trends.forEach(item => { 
+                    item.times = this.GetObjVal(item.data.data);
+                    let newD = [];
+                    item.times.forEach((k, i) => {
+                        if(i%3===0){
+                            newD.push([]);
+                        }
+                        const page = parseInt(i/3);
+                        newD[page].push({times:k});
+                        console.log(newD);
+                        item.final = newD;
+                    });
+                });
+                console.log(this.trends);
+                console.log(this.keywords);
+                this.user_groups.forEach(item => {
+                    this.group_datas.forEach(d => {
+                        if(d.group_id == item.id) {
+                            if(d['data_type'] == 'suggests') {
+                                item.suggests = d.data.data;
+                                console.log(item.suggests);
+                            };
+                            if(d['data_type'] == 'trends') {
+                                item.trends = d.data.data;
+                            }
+                        }
+                    })
+                });
+                this.user_groups.forEach(item => {
+                    if(item.trends) {
+                        const temp = this.GetObjVal(item.trends);
+                        let newD = [];
+                        temp.forEach((k, i) => {
+                            if(i%3===0){
+                                newD.push([]);
+                            }
+                        const page = parseInt(i/3);
+                        newD[page].push({times:k});
+                        item.trends = newD;
+                    });
+                    } else {
+                        item.trends = [
+                            [{times: 0}, {times: 0}, {times: 0}],
+                            [{times: 0}, {times: 0}, {times: 0}],
+                            [{times: 0}, {times: 0}, {times: 0}],
+                            [{times: 0}, {times: 0}, {times: 0}]
+                        ]
+                    }
+                });
+                console.log(this.user_groups);
+            })
+        },
+        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;
+                    }
+                })
+            });
+        },
+        getPack() {
+            for(let i = 1;i < 5;i++) {
+                axios.get(`http://www.googo.org:8050/api/group_datas/group/${i}/`).then(res => {
+                console.log(res.data);
+                const add = [...res.data];
+                this.ex.push(add);
+                //this.trends = this.json.filter(item => item['data_type'] === 'trends');
+                //this.keywords = this.json.filter(item => item['data_type'] === 'suggests');
+                console.log(this.ex);
+            });
+            }
+        },
+        filter() {
+            this.user_groups .forEach(item => {
+                this.group_datas.forEach(d => {
+                    if(d.group_id === item.id) {
+                        d.group_chinese_name = item.group_chinese_name;
+                    }
+                })
+            });
+        },
+        GetObjVal(val) {
+            return Object.values(val);
+        }
+    },
+    computed: {
+    },
+    created() {
+       const d = new Date();
+       const m = d.getMonth();
+       if(m >= 0 && m < 3) {
+            this.selected = 0;
+       } else if(m >=3 && m < 6) {
+            this.selected = 1;
+       } else if(m >=6 && m < 9) {
+            this.selected = 2;
+       } else {
+            this.selected = 3;
+       };
+        this.getData();
+       //this.getPack();
+    },
+    mounted() {
+       
+    },
+    destroyed() {
+    },
+});
+