Mike 3 år sedan
incheckning
d6652f936a

BIN
__MACOSX/step_question/._.DS_Store


BIN
__MACOSX/step_question/._multi_steps


BIN
__MACOSX/step_question/multi_steps/._index.html


BIN
__MACOSX/step_question/multi_steps/._script.js


BIN
__MACOSX/step_question/multi_steps/._style.css


BIN
step_question/.DS_Store


BIN
step_question/apis/__pycache__/main.cpython-36.pyc


+ 51 - 0
step_question/apis/main.py

@@ -0,0 +1,51 @@
+from fastapi import FastAPI, Form, Request
+from fastapi.encoders import jsonable_encoder
+from fastapi.middleware.cors import CORSMiddleware
+import dataset
+import pandas as pd
+from starlette.responses import FileResponse, StreamingResponse
+import io
+
+app = FastAPI()
+app.add_middleware(
+    CORSMiddleware,
+    allow_origins=['*'],
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"],
+)
+
+
+def get_db():
+    db = dataset.connect('mysql://choozmo:pAssw0rd@139.162.121.30:33306/hhh?charset=utf8mb4')
+    step_questions_table = db['step_questions']
+    return step_questions_table
+
+
+@app.post("/step_questions/submit")
+async def submit(request: Request):
+    form_data = await request.form()
+    result = {
+        'sex': form_data.get('q1'),
+        'phone': form_data.get('q2'),
+        'email': form_data.get('q3'),
+        'building_case_name': form_data.get('q4'),
+        'building_case_type': form_data.get('q5'),
+        'decoration_style': ','.join(form_data.getlist('q6')),
+        'decoration_budget': ','.join(form_data.getlist('q7')),
+        'decoration_size': ','.join(form_data.getlist('q8')),
+    }
+    get_db().insert(result)
+    return result
+
+
+@app.get("/step_questions")
+async def get_step_question(request: Request):
+    db_data = list(get_db().find())
+    df = pd.DataFrame(db_data, columns=db_data[0].keys())
+    stream = io.StringIO()    
+    df.to_csv(stream, index = False)
+    # response = StreamingResponse(data_frame.to_csv(index=False), media_type="text/csv")
+    response = StreamingResponse(iter([stream.getvalue()]), media_type="text/csv")
+    response.headers["Content-Disposition"] = "attachment; filename=export.csv"
+    return response

+ 25 - 0
step_question/apis/requirements.txt

@@ -0,0 +1,25 @@
+alembic==1.6.2
+banal==1.0.6
+click==7.1.2
+dataclasses==0.8
+dataset==1.5.0
+fastapi==0.65.1
+greenlet==1.1.0
+h11==0.12.0
+importlib-metadata==4.0.1
+Mako==1.1.4
+MarkupSafe==2.0.0
+mysqlclient==2.0.3
+numpy==1.19.5
+pandas==1.1.5
+pydantic==1.8.2
+python-dateutil==2.8.1
+python-editor==1.0.4
+python-multipart==0.0.5
+pytz==2021.1
+six==1.16.0
+SQLAlchemy==1.4.15
+starlette==0.14.2
+typing-extensions==3.10.0.0
+uvicorn==0.13.4
+zipp==3.4.1

+ 91 - 0
step_question/multi_steps/index.html

@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html lang="en" >
+<head>
+  <meta charset="UTF-8">
+  <title>幸福空間 - 問卷調查</title>
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
+  <link rel="stylesheet" href="./style.css">
+  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
+</head>
+<body>
+<img src="https://hhh.com.tw/assets/images/hhh-logo2.svg" width="145" height="40" alt="hhh-logo">
+<iframe name="dummyframe" id="dummyframe" style="display: none;"></iframe>
+<form action="http://127.0.0.1:8000/step_questions/submit" method="post" id="msform" target="dummyframe">
+  <ul id="progressbar">
+    <li class="active">基本資料</li>
+    <li>建案資料</li>
+    <li>裝修資料</li>
+  </ul>
+  <!-- fieldsets -->
+  <fieldset>
+    <h2 class="fs-title">基本資料</h2>
+    <h3 class="fs-subtitle">This is step 1</h3>
+    <select name="q1">
+      <option value="Male">男</option>
+      <option value="Female">女</option>
+    </select>
+    <input type="text" name='q2' value="" placeholder="手機號碼" /> <br/>
+    <input type="text" name='q3' value="" placeholder="Email" />
+    <input type="button" name="next" class="next action-button" value="Next" />
+  </fieldset>
+  <fieldset>
+    <h2 class="fs-title">建案資料</h2>
+    <h3 class="fs-subtitle">This is step 2</h3>
+    <input type="text" name='q4' value="" placeholder="請問您所在哪個建案" />
+    <div class="left_align">
+    <p>建案類型?</p> <br/>
+    <label><input type="checkbox" class="check_button" value="預售屋" name="q5" />預售屋</label>
+    <label><input type="checkbox" class="check_button" value="新成屋" name="q5" />新成屋</label> <br/>
+    </div>
+    <input type="button" name="previous" class="previous action-button" value="Previous" />
+    <input type="button" name="next" class="next action-button" value="Next" />
+  </fieldset>
+  <fieldset>
+    <h2 class="fs-title">裝修資料</h2>
+    <h3 class="fs-subtitle">This is step 3</h3>
+      <div class="left_align">
+        <p>喜歡的裝修風格?</p><br/>
+        <label><input type="checkbox" value="簡單大方" name="q6" />簡單大方</label>
+        <label><input type="checkbox" value="北歐風" name="q6" />北歐風</label>
+        <label><input type="checkbox" value="日式風格" name="q6" />日式風格</label>
+        <label><input type="checkbox" value="美式鄉村風" name="q6" />美式鄉村風</label>
+        <label><input type="checkbox" value="" id='q6_checkbox' onclick="show_input_text('q6_checkbox', 'q6_input')" />其他</label>
+        <input type="text" id="q6_input" name="q6" style="display:none" value="" />
+      </div>
+      <br/>
+      <div class="left_align">
+        <p>預計裝修預算(不含活動型傢俱/廚具/空調/窗簾/主燈)? </p><br/>
+        <label><input type="checkbox" value="50萬以下" name="q7" />50萬以下</label>
+        <label><input type="checkbox" value="50~100萬" name="q7" />50~100萬</label>
+        <label><input type="checkbox" value="100~200萬" name="q7" />100~200萬</label>
+        <label><input type="checkbox" value="200~300萬" name="q7" />200~300萬</label>
+        <label><input type="checkbox" value="300~500萬" name="q7" />300~500萬</label>
+        <label><input type="checkbox" value="500~800萬" name="q7" />500~800萬</label>
+        <label><input type="checkbox" value="800萬以上" name="q7" />800萬以上</label>
+        <label><input type="checkbox" value="" id='q7_checkbox' onclick="show_input_text('q7_checkbox', 'q7_input')"/>其他</label>
+        <input type="text" id="q7_input" name="q7" style="display:none" value="" />
+        <br/>
+      </div>
+      <div class="left_align">
+        <p>喜歡的裝修風格?</p><br/>
+        <label><input type="checkbox" value="20坪以下" name="q8" />20坪以下</label>
+        <label><input type="checkbox" value="20~30坪" name="q8" />20~30坪</label>
+        <label><input type="checkbox" value="30~40坪" name="q8" />30~40坪</label>
+        <label><input type="checkbox" value="40~50坪" name="q8" />40~50坪</label>
+        <label><input type="checkbox" value="50坪以上" name="q8" />50坪以上</label>
+      </div>
+      <br/>
+      <input type="button" name="previous" class="previous action-button" value="Previous" />
+      <input type="submit" name="submit" class="submit action-button" value="Submit" />
+  </fieldset>
+</form>
+<div id="overlay">
+  <div class="thankyou">
+    <h3>感謝您的填寫</h3>
+  </div>
+</div>
+<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
+<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js'></script>
+<script src="./script.js"></script>
+</body>
+</html>

+ 141 - 0
step_question/multi_steps/script.js

@@ -0,0 +1,141 @@
+//jQuery time
+var current_fs, next_fs, previous_fs; //fieldsets
+var left, opacity, scale; //fieldset properties which we will animate
+var animating; //flag to prevent quick multi-click glitches
+
+$(".next").click(function(){
+  if( !validate() ){
+    return false;
+  }
+
+	if(animating) return false;
+	animating = true;
+	
+	current_fs = $(this).parent();
+	next_fs = $(this).parent().next();
+	
+	//activate next step on progressbar using the index of next_fs
+	$("#progressbar li").eq($("fieldset").index(next_fs)).addClass("active");
+	
+	//show the next fieldset
+	next_fs.show(); 
+	//hide the current fieldset with style
+	current_fs.animate({opacity: 0}, {
+		step: function(now, mx) {
+			//as the opacity of current_fs reduces to 0 - stored in "now"
+			//1. scale current_fs down to 80%
+			scale = 1 - (1 - now) * 0.2;
+			//2. bring next_fs from the right(50%)
+			left = (now * 50)+"%";
+			//3. increase opacity of next_fs to 1 as it moves in
+			opacity = 1 - now;
+			current_fs.css({
+        'transform': 'scale('+scale+')',
+        'position': 'absolute'
+      });
+			next_fs.css({'left': left, 'opacity': opacity});
+		}, 
+		duration: 800, 
+		complete: function(){
+			current_fs.hide();
+			animating = false;
+		}, 
+		//this comes from the custom easing plugin
+		easing: 'easeInOutBack'
+	});
+});
+
+$(".previous").click(function(){
+	if(animating) return false;
+	animating = true;
+	
+	current_fs = $(this).parent();
+	previous_fs = $(this).parent().prev();
+	
+	//de-activate current step on progressbar
+	$("#progressbar li").eq($("fieldset").index(current_fs)).removeClass("active");
+	
+	//show the previous fieldset
+	previous_fs.show(); 
+	//hide the current fieldset with style
+	current_fs.animate({opacity: 0}, {
+		step: function(now, mx) {
+			//as the opacity of current_fs reduces to 0 - stored in "now"
+			//1. scale previous_fs from 80% to 100%
+			scale = 0.8 + (1 - now) * 0.2;
+			//2. take current_fs to the right(50%) - from 0%
+			left = ((1-now) * 50)+"%";
+			//3. increase opacity of previous_fs to 1 as it moves in
+			opacity = 1 - now;
+			current_fs.css({'left': left});
+			previous_fs.css({'transform': 'scale('+scale+')', 'opacity': opacity});
+		}, 
+		duration: 800, 
+		complete: function(){
+			current_fs.hide();
+			animating = false;
+		}, 
+		//this comes from the custom easing plugin
+		easing: 'easeInOutBack'
+	});
+});
+
+$("input[name=submit]").click(function(){
+  console.log($("#msform").serialize());
+  $.ajax({
+    url: 'http://127.0.0.1:8000/step_questions/submit',
+    type: 'post',
+    dataType: 'json',
+    data: $("#msform").serialize(),
+    success: function(data) {
+      showThankyou();
+      }
+  });
+	return false;
+})
+
+function showThankyou() {
+  $('#overlay').show();
+}
+
+function show_input_text(checkbox_id, input_id) {
+	var checkBox = document.getElementById(checkbox_id);
+	var inp = document.getElementById(input_id);
+	if (checkBox.checked == true){
+	  inp.style.display = "block";
+	} else {
+	  inp.style.display = "none";
+	}
+}
+
+function validate() {
+  function q2_validate() {
+    if( $('input[name="q2"]:visible').val() !== undefined && $('input[name="q2"]:visible').val().length <= 0 ) {
+      $('input[name="q2"]:visible').addClass('error');
+      if( !$('.error-text').length )
+          $('input.error').after('<p class="error-text">手機號碼 is Required</p>');
+      return false;
+    }
+    else {
+        $('input[name="q2"]:visible').removeClass('error');
+        $('.error-text').remove();
+        return true;
+    }
+  }
+
+  function q3_validate() {
+    if( $('input[name="q3"]:visible').val() !== undefined && $('input[name="q3"]:visible').val().length <= 0 ) {
+      $('input[name="q3"]:visible').addClass('error');
+      if( !$('.error-text').length )
+          $('input.error').after('<p class="error-text">Email Field is Required</p>');
+      return false;
+    }
+    else {
+        $('input[name="q3"]:visible').removeClass('error');
+        $('.error-text').remove();
+        return true;
+    }
+  }
+
+  return q2_validate() && q3_validate()
+}

+ 193 - 0
step_question/multi_steps/style.css

@@ -0,0 +1,193 @@
+/*custom font*/
+@import url(https://fonts.googleapis.com/css?family=Montserrat);
+
+/*basic reset*/
+* {margin: 0; padding: 0;}
+
+html {
+	height: 100%;
+	/*Image only BG fallback*/
+	
+	/*background = gradient + image pattern combo*/
+	background: 
+		linear-gradient(rgba(196, 102, 0, 0.6), rgba(155, 89, 182, 0.6));
+}
+
+body {
+	font-family: montserrat, arial, verdana;
+}
+/*form styles*/
+#msform {
+	width: 400px;
+	margin: 50px auto;
+	text-align: center;
+	position: relative;
+}
+#msform fieldset {
+	background: white;
+	border: 0 none;
+	border-radius: 3px;
+	box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.4);
+	padding: 20px 30px;
+	box-sizing: border-box;
+	width: 80%;
+	margin: 0 10%;
+	
+	/*stacking fieldsets above each other*/
+	position: relative;
+}
+/*Hide all except first fieldset*/
+#msform fieldset:not(:first-of-type) {
+	display: none;
+}
+/*inputs*/
+#msform input[type="text"], #msform textarea {
+	padding: 15px;
+	border: 1px solid #ccc;
+	border-radius: 3px;
+	margin-bottom: 10px;
+	width: 100%;
+	box-sizing: border-box;
+	font-family: montserrat;
+	color: #2C3E50;
+	font-size: 13px;
+}
+/*buttons*/
+#msform .action-button {
+	width: 100px;
+	background: #27AE60;
+	font-weight: bold;
+	color: white;
+	border: 0 none;
+	border-radius: 1px;
+	cursor: pointer;
+	padding: 10px 5px;
+	margin: 10px 5px;
+}
+#msform .action-button:hover, #msform .action-button:focus {
+	box-shadow: 0 0 0 2px white, 0 0 0 3px #27AE60;
+}
+/*headings*/
+.fs-title {
+	font-size: 15px;
+	text-transform: uppercase;
+	color: #2C3E50;
+	margin-bottom: 10px;
+}
+.fs-subtitle {
+	font-weight: normal;
+	font-size: 13px;
+	color: #666;
+	margin-bottom: 20px;
+}
+/*progressbar*/
+#progressbar {
+	margin-bottom: 30px;
+	overflow: hidden;
+	/*CSS counters to number the steps*/
+	counter-reset: step;
+}
+#progressbar li {
+	list-style-type: none;
+	color: white;
+	text-transform: uppercase;
+	font-size: 9px;
+	width: 33.33%;
+	float: left;
+	position: relative;
+}
+#progressbar li:before {
+	content: counter(step);
+	counter-increment: step;
+	width: 20px;
+	line-height: 20px;
+	display: block;
+	font-size: 10px;
+	color: #333;
+	background: white;
+	border-radius: 3px;
+	margin: 0 auto 5px auto;
+}
+/*progressbar connectors*/
+#progressbar li:after {
+	content: '';
+	width: 100%;
+	height: 2px;
+	background: white;
+	position: absolute;
+	left: -50%;
+	top: 9px;
+	z-index: -1; /*put it behind the numbers*/
+}
+#progressbar li:first-child:after {
+	/*connector not needed before the first step*/
+	content: none; 
+}
+/*marking active/completed steps green*/
+/*The number of the step and the connector before it = green*/
+#progressbar li.active:before,  #progressbar li.active:after{
+	background: #27AE60;
+	color: white;
+}
+
+p.error-text {
+	bottom: -23px;
+	left: 24px;
+	color: rgba(255, 0, 0, .7);
+	font-size: .6em;
+}
+
+select {
+	padding: 15px;
+	border: 1px solid #ccc;
+	border-radius: 3px;
+	margin-bottom: 10px;
+	width: 100%;
+	box-sizing: border-box;
+	font-family: montserrat;
+	color: #2C3E50;
+	font-size: 13px;
+
+	background-color: transparent;
+}
+
+.left_align {
+	font-size: 18px;
+	text-align: left;
+}
+
+#overlay {
+	position: fixed; /* Sit on top of the page content */
+	display: none;
+	width: 100%;
+	height: 100%;
+	top: 0; 
+	left: 0;
+	right: 0;
+	bottom: 0;
+	background-color: rgba(0,0,0,0.5);
+	z-index: 2;
+	cursor: pointer;
+}
+
+.thankyou {
+	margin: auto;
+	width: 260px;
+	height: 160px;
+	margin-top: 190px;
+	background: #fff;
+	padding: 15px 20px;
+	line-height: 25px;
+	border-radius: 4px;
+	text-align: center;
+	box-shadow: -1px 5px 32px 7px rgba(0, 0, 0, 0.5);
+}
+.thankyou input {
+	margin-top: 40px;
+}
+.thankyou h3 {
+	font-size: 3em;
+	font-weight: 700;
+	color: #21ba45;
+	line-height: 50px;
+}