使用Flask和PyScript构建了一个简单的量表网站框架,实现了:
1. 纯json的量表编辑 2. 任意区间的Ratio填写 3. 可选的Reverse item 4. 可按照子量表计算结果
This commit is contained in:
commit
97a3b7b7bf
60
app.py
Normal file
60
app.py
Normal file
@ -0,0 +1,60 @@
|
||||
import json
|
||||
import os
|
||||
from flask import Flask, render_template, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# 加载所有问卷数据
|
||||
def load_all_scales():
|
||||
scale_folder = 'scales'
|
||||
scales = {}
|
||||
for filename in os.listdir(scale_folder):
|
||||
if filename.endswith('.json'):
|
||||
with open(os.path.join(scale_folder, filename), 'r', encoding='utf-8') as f:
|
||||
scale = json.load(f)
|
||||
# 使用文件名作为问卷的唯一标识
|
||||
scale_id = os.path.splitext(filename)[0]
|
||||
scales[scale_id] = scale
|
||||
return scales
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
scales = load_all_scales()
|
||||
return render_template('index.html', scales=scales)
|
||||
|
||||
@app.route('/scales/<scale_id>')
|
||||
def scale(scale_id):
|
||||
scales = load_all_scales()
|
||||
scale = scales.get(scale_id)
|
||||
if scale:
|
||||
return render_template('scale.html', scale_id=scale_id,scale=scale)
|
||||
return "问卷未找到", 404
|
||||
|
||||
@app.route('/result/<scale_id>', methods=['POST'])
|
||||
def result(scale_id):
|
||||
# print(request.form)
|
||||
scales = load_all_scales()
|
||||
scale = scales.get(scale_id)
|
||||
if scale:
|
||||
responses = {}
|
||||
ranges = {}
|
||||
# print(scale['questions'])
|
||||
for question in scale['questions']:
|
||||
# print(question['subscale'])
|
||||
if question['subscale'] not in responses:
|
||||
responses[question['subscale']] = 0
|
||||
ranges[question['subscale']] = [0,0]
|
||||
if 'reverse' in question and question['reverse']:
|
||||
responses[question['subscale']] += question['range'][1] + question['range'][0] - int( request.form[question['id']])
|
||||
else:
|
||||
responses[question['subscale']] += int( request.form[question['id']])
|
||||
ranges[question['subscale']][0] += question['range'][0]
|
||||
ranges[question['subscale']][1] += question['range'][1]
|
||||
# 这里可以添加保存数据到数据库等逻辑
|
||||
# print(ranges)
|
||||
return render_template('result.html', responses=responses, ranges=ranges, scale_title=scale['title'])
|
||||
return "问卷未找到", 404
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
BIN
requirements.txt
Normal file
BIN
requirements.txt
Normal file
Binary file not shown.
16
templates/index.html
Normal file
16
templates/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>心尺 PsychoScales</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>心尺 PsychoScales</h1>
|
||||
<ul>
|
||||
{% for scale_id, scale in scales.items() %}
|
||||
<li><a href="{{ url_for('scale', scale_id=scale_id) }}">{{ scale.get('title', '未命名问卷') }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
17
templates/result.html
Normal file
17
templates/result.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Result</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{ scale_title }} </h1>
|
||||
<!-- <h2>您的结果如下:</h2> -->
|
||||
<ul>
|
||||
{% for key, value in responses.items() %}
|
||||
<li>{{ key }}: 在 {{ranges[key][0]}} 到 {{ranges[key][1]}} 的量表中得分 {{ value }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
48
templates/scale.html
Normal file
48
templates/scale.html
Normal file
@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ scale.title }}</title>
|
||||
<style>
|
||||
/* 定义单选按钮容器样式 */
|
||||
.radio-button-group {
|
||||
display: flex;
|
||||
gap: 10px; /* 按钮之间的间距 */
|
||||
}
|
||||
/* 定义单选按钮隐藏样式 */
|
||||
.radio-button-group input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
/* 定义单选按钮标签样式 */
|
||||
.radio-button-group label {
|
||||
padding: 10px 20px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
/* 定义单选按钮选中时标签样式 */
|
||||
.radio-button-group input[type="radio"]:checked + label {
|
||||
background-color: #007BFF;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{ scale.title }}</h1>
|
||||
<p>{{ scale.instructions }}</p>
|
||||
<form action="{{ url_for('result', scale_id=scale_id) }}" method="post">
|
||||
{% for question in scale.questions %}
|
||||
<label for="{{ question.id }}">{{ question.text }}</label>
|
||||
<div class="radio-button-group">
|
||||
<!-- 将下拉菜单替换为单选按钮 -->
|
||||
{% for option in range(question.range[0], question.range[1]+1) %}
|
||||
<input type="radio" id="{{ question.id }}_{{ option }}" name="{{ question.id }}" value="{{ option }}" {% if not ( 'optional' in question and question.optional) %}required{% endif %}>
|
||||
<label for="{{ question.id }}_{{ option }}">{{ option }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<input type="submit" value="提交">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user