This commit is contained in:
ZaneYork 2024-09-14 17:34:37 +08:00
parent 6aa4fa2c50
commit a7bd6b83a3
4 changed files with 34 additions and 45 deletions

View File

@ -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)
); );

View File

@ -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')

View File

@ -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,

View File

@ -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');#}
} }
} }
}); });