使用Flask和PyScript构建了一个简单的量表网站框架,实现了:

1. 纯json的量表编辑
2. 任意区间的Ratio填写
3. 可选的Reverse item
4. 可按照子量表计算结果
This commit is contained in:
mxr612 2025-03-04 19:29:43 +08:00
commit 97a3b7b7bf
5 changed files with 141 additions and 0 deletions

60
app.py Normal file
View 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

Binary file not shown.

16
templates/index.html Normal file
View 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
View 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
View 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>