This commit is contained in:
parent
6aa4fa2c50
commit
a7bd6b83a3
13
db/ddl.sql
13
db/ddl.sql
|
@ -16,23 +16,16 @@ create table main.roll_result
|
||||||
value text
|
value text
|
||||||
);
|
);
|
||||||
|
|
||||||
create table main.sqlite_master
|
|
||||||
(
|
|
||||||
type TEXT,
|
|
||||||
name TEXT,
|
|
||||||
tbl_name TEXT,
|
|
||||||
rootpage INT,
|
|
||||||
sql TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
create table main.user_menu
|
create table main.user_menu
|
||||||
(
|
(
|
||||||
user text,
|
user text,
|
||||||
menu text,
|
menu text,
|
||||||
datestr text,
|
datestr text,
|
||||||
nickname text,
|
nickname text,
|
||||||
primary key (user, datestr),
|
dislike text,
|
||||||
constraint user_menu_pk
|
constraint user_menu_pk
|
||||||
|
primary key (user, datestr),
|
||||||
|
constraint user_menu_uk
|
||||||
unique (nickname, datestr)
|
unique (nickname, datestr)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ def set_user_menu(menu: dict[str, float], nickname: str, dislike: list[str] = No
|
||||||
设置用户投票内容
|
设置用户投票内容
|
||||||
:param menu: 投票内容
|
:param menu: 投票内容
|
||||||
:param nickname: 姓名
|
:param nickname: 姓名
|
||||||
|
:param dislike: 不吃的清单
|
||||||
:param user: 用户,默认当前用户
|
:param user: 用户,默认当前用户
|
||||||
"""
|
"""
|
||||||
datestr = datetime.now().strftime('%Y-%m-%d')
|
datestr = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from collections import defaultdict
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
from session import app
|
from session import app
|
||||||
|
@ -7,7 +8,7 @@ from dao import *
|
||||||
from utils import is_mobile_request
|
from utils import is_mobile_request
|
||||||
|
|
||||||
|
|
||||||
def fetch_user_menu_summary() -> tuple[dict[str, float], list[str], list[tuple[str, list[str]]]]:
|
def fetch_user_menu_summary() -> tuple[defaultdict[str, float], list[str], list[tuple[str, list[str]]]]:
|
||||||
"""
|
"""
|
||||||
获取今天所有人的投票汇总
|
获取今天所有人的投票汇总
|
||||||
:return: 品类->数量
|
:return: 品类->数量
|
||||||
|
@ -17,15 +18,12 @@ def fetch_user_menu_summary() -> tuple[dict[str, float], list[str], list[tuple[s
|
||||||
menus = list(map(lambda x: x.menu, all_menu))
|
menus = list(map(lambda x: x.menu, all_menu))
|
||||||
users = list(map(lambda x: x.nickname, all_menu))
|
users = list(map(lambda x: x.nickname, all_menu))
|
||||||
dislikes = list(map(lambda x: (x.nickname, x.dislike), all_menu))
|
dislikes = list(map(lambda x: (x.nickname, x.dislike), all_menu))
|
||||||
menu_keys = set(chain(*menus))
|
result = defaultdict(float)
|
||||||
result = {}
|
|
||||||
for k in menu_keys:
|
|
||||||
result[k] = 0
|
|
||||||
for user_menu in menus:
|
for user_menu in menus:
|
||||||
for k in user_menu:
|
for k in user_menu:
|
||||||
result[k] += user_menu[k]
|
result[k] += user_menu[k]
|
||||||
return result, users, dislikes
|
return result, users, dislikes
|
||||||
return {}, [], []
|
return defaultdict(float), [], []
|
||||||
|
|
||||||
|
|
||||||
def within_time() -> bool:
|
def within_time() -> bool:
|
||||||
|
@ -51,9 +49,9 @@ def check_roll() -> int:
|
||||||
return 0 if within_time() else 1
|
return 0 if within_time() else 1
|
||||||
|
|
||||||
|
|
||||||
def vote_reduce(summary: dict[str, float],
|
def vote_reduce(summary: defaultdict[str, float],
|
||||||
dislikes: list[tuple[str, list[str]]], limit: int = 2
|
dislikes: list[tuple[str, list[str]]], limit: int = 2
|
||||||
) -> tuple[dict[str, float], float, list[RollResult]]:
|
) -> tuple[defaultdict[str, float], int, list[RollResult]]:
|
||||||
"""
|
"""
|
||||||
按规则对投票结果进行修饰
|
按规则对投票结果进行修饰
|
||||||
:param summary: 投票汇总结果
|
:param summary: 投票汇总结果
|
||||||
|
@ -62,7 +60,7 @@ def vote_reduce(summary: dict[str, float],
|
||||||
:return: 投票汇总结果
|
:return: 投票汇总结果
|
||||||
"""
|
"""
|
||||||
last_results: list[RollResult] = list(fetch_roll_result_list(-1, limit))
|
last_results: list[RollResult] = list(fetch_roll_result_list(-1, limit))
|
||||||
total_vote = sum(value for value in summary.values())
|
total_vote = round(sum(value for value in summary.values()))
|
||||||
menus: list[Menu] = list(fetch_all_menu())
|
menus: list[Menu] = list(fetch_all_menu())
|
||||||
for menu in menus:
|
for menu in menus:
|
||||||
if menu.expression is None or menu.name not in summary.keys():
|
if menu.expression is None or menu.name not in summary.keys():
|
||||||
|
@ -72,16 +70,12 @@ def vote_reduce(summary: dict[str, float],
|
||||||
new_name = eval(menu.expression, {'total_vote': total_vote - dislike_cnt})
|
new_name = eval(menu.expression, {'total_vote': total_vote - dislike_cnt})
|
||||||
if new_name != menu.name:
|
if new_name != menu.name:
|
||||||
if new_name is not None:
|
if new_name is not None:
|
||||||
if summary.get(new_name) is None:
|
|
||||||
summary[new_name] = summary[menu.name]
|
|
||||||
else:
|
|
||||||
summary[new_name] += summary[menu.name]
|
summary[new_name] += summary[menu.name]
|
||||||
summary[menu.name] = 0
|
summary[menu.name] = 0
|
||||||
# 昨日中签项降低权重
|
# 昨日中签项降低权重
|
||||||
for i, last_result in enumerate(last_results):
|
for i, last_result in enumerate(last_results):
|
||||||
if last_result.value in summary:
|
if last_result.value in summary:
|
||||||
summary[last_result.value] = summary[last_result.value] * (8 - i) / 10
|
summary[last_result.value] = summary[last_result.value] * (8 - i) / 10
|
||||||
total_vote = sum(value for value in summary.values())
|
|
||||||
return summary, total_vote, last_results
|
return summary, total_vote, last_results
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,18 +101,16 @@ def dinner_update():
|
||||||
set_user_menu({}, nickname, [])
|
set_user_menu({}, nickname, [])
|
||||||
return make_response(json.dumps(dict(code=0, data="OK")))
|
return make_response(json.dumps(dict(code=0, data="OK")))
|
||||||
user_menu = json.loads(user_menu)
|
user_menu = json.loads(user_menu)
|
||||||
choice = user_menu['choice']
|
choice = {key: int(value) for key, value in user_menu['choice'].items() if int(value) > 0}
|
||||||
dislike = user_menu.get('dislike')
|
dislike = user_menu.get('dislike') or []
|
||||||
if dislike is None:
|
|
||||||
dislike = []
|
|
||||||
# 计算总投票数值
|
# 计算总投票数值
|
||||||
summary = sum(abs(int(value)) for value in choice.values())
|
vote_sum = sum(value for value in choice.values())
|
||||||
if summary <= 0:
|
if vote_sum <= 0:
|
||||||
set_user_menu({}, nickname, dislike)
|
set_user_menu({}, nickname, dislike)
|
||||||
return make_response(json.dumps(dict(code=0, data="OK")))
|
return make_response(json.dumps(dict(code=0, data="OK")))
|
||||||
# 投票数归一化
|
# 投票数归一化
|
||||||
for key in choice:
|
for key in choice:
|
||||||
choice[key] = abs(int(choice[key])) / summary
|
choice[key] /= vote_sum
|
||||||
set_user_menu(choice, nickname, dislike)
|
set_user_menu(choice, nickname, dislike)
|
||||||
return make_response(json.dumps(dict(code=0, data="OK")))
|
return make_response(json.dumps(dict(code=0, data="OK")))
|
||||||
|
|
||||||
|
@ -154,6 +146,16 @@ def roll_logic(check=False):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def compute_eat_users(dislikes, result, users):
|
||||||
|
if result is None:
|
||||||
|
return []
|
||||||
|
eat_users = users.copy()
|
||||||
|
for (n, d) in dislikes:
|
||||||
|
if result in d:
|
||||||
|
eat_users.remove(n)
|
||||||
|
return eat_users
|
||||||
|
|
||||||
|
|
||||||
@app.route('/dinner')
|
@app.route('/dinner')
|
||||||
def dinner():
|
def dinner():
|
||||||
"""
|
"""
|
||||||
|
@ -169,13 +171,9 @@ def dinner():
|
||||||
summary_keys = list(filter(lambda x: x in summary.keys(), map(lambda y: y.name, all_choice)))
|
summary_keys = list(filter(lambda x: x in summary.keys(), map(lambda y: y.name, all_choice)))
|
||||||
if not result:
|
if not result:
|
||||||
predict_result = roll_logic(check=True)
|
predict_result = roll_logic(check=True)
|
||||||
eat_users = []
|
|
||||||
else:
|
else:
|
||||||
eat_users = users.copy()
|
|
||||||
for (n, d) in dislikes:
|
|
||||||
if result in d:
|
|
||||||
eat_users.remove(n)
|
|
||||||
predict_result = None
|
predict_result = None
|
||||||
|
eat_users = compute_eat_users(dislikes, result or predict_result, users)
|
||||||
recent_results = list(fetch_roll_result_list(-1, 7))
|
recent_results = list(fetch_roll_result_list(-1, 7))
|
||||||
return render_template('dinner.html',
|
return render_template('dinner.html',
|
||||||
all_choice=all_choice,
|
all_choice=all_choice,
|
||||||
|
|
|
@ -22,9 +22,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div class="input-group mb-2">
|
<label class="input-group-addon">我选择</label>
|
||||||
<span class="input-group-addon">我选择</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% for choice in all_choice %}
|
{% for choice in all_choice %}
|
||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
|
@ -34,8 +32,8 @@
|
||||||
<span>{{ choice.label }} - </span>
|
<span>{{ choice.label }} - </span>
|
||||||
<span class="percentage">{{ '{:.2f}'.format((user_menu.menu.get(choice.name) or 0) * 100) }}</span>%
|
<span class="percentage">{{ '{:.2f}'.format((user_menu.menu.get(choice.name) or 0) * 100) }}</span>%
|
||||||
</label>
|
</label>
|
||||||
<input type="range" class="form-range"
|
<input type="range" class="form-range" data-skip-falsy="true"
|
||||||
id="range{{ loop.index }}" name="choice[{{ choice.name }}]"
|
id="range{{ loop.index }}" name="choice[{{ choice.name }}]:number"
|
||||||
min="0" max="10" step="1"
|
min="0" max="10" step="1"
|
||||||
value="{{ (user_menu.menu.get(choice.name) or 0) * 10 }}">
|
value="{{ (user_menu.menu.get(choice.name) or 0) * 10 }}">
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,7 +57,7 @@
|
||||||
onclick="roll()">开始抽签
|
onclick="roll()">开始抽签
|
||||||
</button>
|
</button>
|
||||||
<div class="pt-3">
|
<div class="pt-3">
|
||||||
<label>大家的选择 - 总票数:{{ '{:.2f}'.format(total_vote | round(2)) }}</label>
|
<label>大家的选择 - 总投票人数:{{ total_vote }}</label>
|
||||||
<ul class="list-group pt-2 mb-4">
|
<ul class="list-group pt-2 mb-4">
|
||||||
{% for key in summary_keys %}
|
{% for key in summary_keys %}
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center{{ " active" if result == key else "" }} {{ " list-group-item-primary" if predict_result == key else "" }}">
|
<li class="list-group-item d-flex justify-content-between align-items-center{{ " active" if result == key else "" }} {{ " list-group-item-primary" if predict_result == key else "" }}">
|
||||||
|
@ -80,9 +78,9 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if (eat_users|length) %}
|
{% if ((users|length) > 3 or result) %}
|
||||||
<div class="pt-1 mb-3">
|
<div class="pt-1 mb-3">
|
||||||
<label class="mb-2">就餐人员</label>
|
<label class="mb-2">{{ ('如果吃' + predict_result) if predict_result else '' }}就餐人员</label>
|
||||||
<ul class="list-group list-group-horizontal">
|
<ul class="list-group list-group-horizontal">
|
||||||
{% for user in eat_users %}
|
{% for user in eat_users %}
|
||||||
<li class="list-group-item">{{ user }}</li>
|
<li class="list-group-item">{{ user }}</li>
|
||||||
|
@ -142,7 +140,6 @@
|
||||||
spans[i].innerHTML = summary > 0 ? (parseFloat(values[i]) * 100 / summary).toFixed(2) : 0;
|
spans[i].innerHTML = summary > 0 ? (parseFloat(values[i]) * 100 / summary).toFixed(2) : 0;
|
||||||
if (values[i] > 0 && checkBoxs[i].checked) {
|
if (values[i] > 0 && checkBoxs[i].checked) {
|
||||||
checkBoxs[i].checked = false;
|
checkBoxs[i].checked = false;
|
||||||
{#$(checkBoxs[i]).trigger('blur');#}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue