添加不吃选项
This commit is contained in:
parent
3fa5d3c637
commit
33589709c3
|
@ -0,0 +1 @@
|
||||||
|
flask
|
50
src/dao.py
50
src/dao.py
|
@ -1,13 +1,15 @@
|
||||||
|
import json
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
|
||||||
|
from entities import *
|
||||||
from utils import get_user
|
from utils import get_user
|
||||||
|
|
||||||
db_path = './data.sqlite3'
|
db_path = './data.sqlite3'
|
||||||
|
|
||||||
|
|
||||||
def get_user_menu() -> tuple[str, str]:
|
def get_user_menu() -> UserMenu:
|
||||||
"""
|
"""
|
||||||
获取当前用户的投票内容
|
获取当前用户的投票内容
|
||||||
:return: 投票内容
|
:return: 投票内容
|
||||||
|
@ -17,24 +19,29 @@ def get_user_menu() -> tuple[str, str]:
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
datestr = datetime.now().strftime('%Y-%m-%d')
|
datestr = datetime.now().strftime('%Y-%m-%d')
|
||||||
try:
|
try:
|
||||||
cursor.execute("select menu, nickname from user_menu where user = ? and datestr=?", (user, datestr))
|
cursor.execute("select menu, nickname, dislike from user_menu where user = ? and datestr=?",
|
||||||
|
(user, datestr))
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
if row:
|
if row:
|
||||||
return row[0], row[1]
|
return UserMenu(user=user, datestr=datestr, menu=json.loads(row[0]), nickname=row[1],
|
||||||
|
dislike=json.loads(row[2] if row[2] else '[]'))
|
||||||
else:
|
else:
|
||||||
cursor.execute(
|
cursor.execute('''
|
||||||
"select menu, nickname from user_menu where user = ? and nickname is not null order by datestr desc limit 1",
|
select menu, nickname, dislike from user_menu
|
||||||
(user,))
|
where user = ? and nickname is not null
|
||||||
|
order by datestr desc limit 1
|
||||||
|
''', (user,))
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
if row:
|
if row:
|
||||||
return '{}', row[1]
|
return UserMenu(user=user, datestr=datestr, nickname=row[1],
|
||||||
return '', ''
|
dislike=json.loads(row[2] if row[2] else '[]'))
|
||||||
|
return UserMenu(user=user, datestr=datestr)
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
def set_user_menu(menu: str, nickname: str, user: str = None) -> None:
|
def set_user_menu(menu: dict[str, float], nickname: str, dislike: list[str] = None, user: str = None) -> None:
|
||||||
"""
|
"""
|
||||||
设置用户投票内容
|
设置用户投票内容
|
||||||
:param menu: 投票内容
|
:param menu: 投票内容
|
||||||
|
@ -47,15 +54,16 @@ def set_user_menu(menu: str, nickname: str, user: str = None) -> None:
|
||||||
db = sqlite3.connect(db_path)
|
db = sqlite3.connect(db_path)
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
try:
|
try:
|
||||||
cursor.execute("insert or replace into user_menu(user,menu,datestr,nickname) values(?,?,?,?)",
|
cursor.execute("insert or replace into user_menu(user,menu,datestr,nickname,dislike) values(?,?,?,?,?)",
|
||||||
(user, menu, datestr, nickname))
|
(user, json.dumps(menu, ensure_ascii=False), datestr, nickname,
|
||||||
|
json.dumps(dislike, ensure_ascii=False)))
|
||||||
db.commit()
|
db.commit()
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
def fetch_all_user_today_menu() -> Generator[tuple[str, str], None, None]:
|
def fetch_all_user_today_menu() -> Generator[UserMenu, None, None]:
|
||||||
"""
|
"""
|
||||||
获取所有用户今日的投票内容
|
获取所有用户今日的投票内容
|
||||||
"""
|
"""
|
||||||
|
@ -63,11 +71,13 @@ def fetch_all_user_today_menu() -> Generator[tuple[str, str], None, None]:
|
||||||
db = sqlite3.connect(db_path)
|
db = sqlite3.connect(db_path)
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
try:
|
try:
|
||||||
cursor.execute("select nickname, menu from user_menu where menu != '' and datestr=? order by user",
|
cursor.execute('''select nickname, menu, user, dislike from user_menu
|
||||||
(datestr,))
|
where menu is not null and menu != '{}' and datestr=? order by user
|
||||||
|
''', (datestr,))
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
while row:
|
while row:
|
||||||
yield row[0], row[1]
|
yield UserMenu(user=row[2], datestr=datestr, menu=json.loads(row[1]),
|
||||||
|
nickname=row[0], dislike=json.loads(row[3] if row[3] else '[]'))
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
@ -92,7 +102,7 @@ def is_valid_user(nickname) -> bool:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
def fetch_all_menu() -> Generator[tuple[str, str, str], None, None]:
|
def fetch_all_menu() -> Generator[Menu, None, None]:
|
||||||
"""
|
"""
|
||||||
获取所有可点的菜单
|
获取所有可点的菜单
|
||||||
"""
|
"""
|
||||||
|
@ -102,7 +112,7 @@ def fetch_all_menu() -> Generator[tuple[str, str, str], None, None]:
|
||||||
cursor.execute("select name, label, expression from menu order by order_num")
|
cursor.execute("select name, label, expression from menu order by order_num")
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
while row:
|
while row:
|
||||||
yield row[0], row[1], row[2]
|
yield Menu(name=row[0], label=row[1], expression=row[2])
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
@ -130,7 +140,7 @@ def fetch_roll_result() -> str | None:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
def fetch_roll_result_list(interval: int = 0, limit: int = 3) -> Generator[str, None, None]:
|
def fetch_roll_result_list(interval: int = 0, limit: int = 3) -> Generator[RollResult, None, None]:
|
||||||
"""
|
"""
|
||||||
获取N天前的抽签结果
|
获取N天前的抽签结果
|
||||||
:param interval: 间隔,天
|
:param interval: 间隔,天
|
||||||
|
@ -142,11 +152,11 @@ def fetch_roll_result_list(interval: int = 0, limit: int = 3) -> Generator[str,
|
||||||
db = sqlite3.connect(db_path)
|
db = sqlite3.connect(db_path)
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
try:
|
try:
|
||||||
cursor.execute("select value from roll_result where datestr<=? order by datestr desc limit ?",
|
cursor.execute("select datestr, value from roll_result where datestr<=? order by datestr desc limit ?",
|
||||||
(datestr, limit))
|
(datestr, limit))
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
while row is not None:
|
while row is not None:
|
||||||
yield row[0]
|
yield RollResult(datestr=row[0], value=row[1])
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import json
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
from session import app
|
from session import app
|
||||||
|
@ -8,15 +7,16 @@ 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]]:
|
def fetch_user_menu_summary() -> tuple[dict[str, float], list[str], list[tuple[str, list[str]]]]:
|
||||||
"""
|
"""
|
||||||
获取今天所有人的投票汇总
|
获取今天所有人的投票汇总
|
||||||
:return: 品类->数量
|
:return: 品类->数量
|
||||||
"""
|
"""
|
||||||
all_menu = list(fetch_all_user_today_menu())
|
all_menu: list[UserMenu] = list(fetch_all_user_today_menu())
|
||||||
if len(all_menu) > 0:
|
if len(all_menu) > 0:
|
||||||
menus = list(map(lambda x: json.loads(x[1]), all_menu))
|
menus = list(map(lambda x: x.menu, all_menu))
|
||||||
users = list(map(lambda x: x[0], all_menu))
|
users = list(map(lambda x: x.nickname, all_menu))
|
||||||
|
dislikes = list(map(lambda x: (x.nickname, x.dislike), all_menu))
|
||||||
menu_keys = set(chain(*menus))
|
menu_keys = set(chain(*menus))
|
||||||
result = {}
|
result = {}
|
||||||
for k in menu_keys:
|
for k in menu_keys:
|
||||||
|
@ -24,8 +24,8 @@ def fetch_user_menu_summary() -> tuple[dict[str, float], list[str]]:
|
||||||
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
|
return result, users, dislikes
|
||||||
return {}, []
|
return {}, [], []
|
||||||
|
|
||||||
|
|
||||||
def within_time() -> bool:
|
def within_time() -> bool:
|
||||||
|
@ -51,31 +51,32 @@ 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], limit: int = 2) -> tuple[dict[str, float], float, list[str]]:
|
def vote_reduce(summary: dict[str, float], limit: int = 2) -> tuple[dict[str, float], float, list[RollResult]]:
|
||||||
"""
|
"""
|
||||||
按规则对投票结果进行修饰
|
按规则对投票结果进行修饰
|
||||||
:param summary: 投票汇总结果
|
:param summary: 投票汇总结果
|
||||||
:param limit: 降低最近N次点餐结果概率
|
:param limit: 降低最近N次点餐结果概率
|
||||||
:return: 投票汇总结果
|
:return: 投票汇总结果
|
||||||
"""
|
"""
|
||||||
last_results = 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 = sum(value for value in summary.values())
|
||||||
for menu in fetch_all_menu():
|
menus: list[Menu] = list(fetch_all_menu())
|
||||||
name, _, expression = menu
|
for menu in menus:
|
||||||
if expression is None or name not in summary.keys():
|
if menu.expression is None or menu.name not in summary.keys():
|
||||||
continue
|
continue
|
||||||
# 计算预定路由规则
|
# 计算预定路由规则
|
||||||
new_name = eval(expression, {'total_vote': total_vote})
|
new_name = eval(menu.expression, {'total_vote': total_vote})
|
||||||
if new_name != name:
|
if new_name != menu.name:
|
||||||
|
if new_name is not None:
|
||||||
if summary.get(new_name) is None:
|
if summary.get(new_name) is None:
|
||||||
summary[new_name] = summary[name]
|
summary[new_name] = summary[menu.name]
|
||||||
else:
|
else:
|
||||||
summary[new_name] += summary[name]
|
summary[new_name] += summary[menu.name]
|
||||||
summary[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 in summary:
|
if last_result.value in summary:
|
||||||
summary[last_result] = summary[last_result] * (8 - i) / 10
|
summary[last_result.value] = summary[last_result.value] * (8 - i) / 10
|
||||||
total_vote = sum(value for value in summary.values())
|
total_vote = sum(value for value in summary.values())
|
||||||
return summary, total_vote, last_results
|
return summary, total_vote, last_results
|
||||||
|
|
||||||
|
@ -99,18 +100,20 @@ def dinner_update():
|
||||||
if not is_valid_user(nickname):
|
if not is_valid_user(nickname):
|
||||||
return make_response(json.dumps(dict(code=-1, data="你不能投票(*^_^*)")))
|
return make_response(json.dumps(dict(code=-1, data="你不能投票(*^_^*)")))
|
||||||
if not user_menu:
|
if not user_menu:
|
||||||
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']
|
||||||
|
dislike = user_menu['dislike']
|
||||||
# 计算总投票数值
|
# 计算总投票数值
|
||||||
summary = sum(abs(int(value)) for value in user_menu.values())
|
summary = sum(abs(int(value)) for value in choice.values())
|
||||||
if summary <= 0:
|
if summary <= 0:
|
||||||
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")))
|
||||||
# 投票数归一化
|
# 投票数归一化
|
||||||
for key in user_menu:
|
for key in choice:
|
||||||
user_menu[key] = abs(int(user_menu[key])) / summary
|
choice[key] = abs(int(choice[key])) / summary
|
||||||
set_user_menu(json.dumps(user_menu, ensure_ascii=False), nickname)
|
set_user_menu(choice, nickname)
|
||||||
return make_response(json.dumps(dict(code=0, data="OK")))
|
return make_response(json.dumps(dict(code=0, data="OK")))
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,7 +131,7 @@ def dinner_roll():
|
||||||
|
|
||||||
|
|
||||||
def roll_logic(check=False):
|
def roll_logic(check=False):
|
||||||
menus, _ = fetch_user_menu_summary()
|
menus, _, _ = fetch_user_menu_summary()
|
||||||
summary, _, _ = vote_reduce(menus)
|
summary, _, _ = vote_reduce(menus)
|
||||||
sorted_items = sorted(summary.items(), key=lambda item: item[1], reverse=True)
|
sorted_items = sorted(summary.items(), key=lambda item: item[1], reverse=True)
|
||||||
items = [item for item in sorted_items[:2]]
|
items = [item for item in sorted_items[:2]]
|
||||||
|
@ -151,27 +154,28 @@ def dinner():
|
||||||
主页面
|
主页面
|
||||||
:return: 响应
|
:return: 响应
|
||||||
"""
|
"""
|
||||||
menu, nickname = get_user_menu()
|
user_menu = get_user_menu()
|
||||||
if menu:
|
menus, users, dislikes = fetch_user_menu_summary()
|
||||||
menu = json.loads(menu)
|
|
||||||
else:
|
|
||||||
menu = {}
|
|
||||||
menus, users = fetch_user_menu_summary()
|
|
||||||
summary, total_vote, last_results = vote_reduce(menus)
|
summary, total_vote, last_results = vote_reduce(menus)
|
||||||
result = fetch_roll_result()
|
result = fetch_roll_result()
|
||||||
can_roll = (check_roll() == 1)
|
can_roll = (check_roll() == 1)
|
||||||
all_choice = list(map(lambda x: {'name': x[0], 'label': x[1]}, fetch_all_menu()))
|
all_choice = list(fetch_all_menu())
|
||||||
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
|
||||||
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,
|
||||||
menu=menu,
|
user_menu=user_menu,
|
||||||
nickname=nickname,
|
|
||||||
users=users,
|
users=users,
|
||||||
|
eat_users=eat_users,
|
||||||
summary=summary,
|
summary=summary,
|
||||||
summary_keys=summary_keys,
|
summary_keys=summary_keys,
|
||||||
total_vote=total_vote,
|
total_vote=total_vote,
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class UserMenu:
|
||||||
|
user: str
|
||||||
|
datestr: str
|
||||||
|
nickname: str = ''
|
||||||
|
menu: dict[str, float] = field(default_factory=dict)
|
||||||
|
dislike: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Menu:
|
||||||
|
name: str
|
||||||
|
label: str
|
||||||
|
expression: str = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RollResult:
|
||||||
|
datestr: str
|
||||||
|
value: str
|
|
@ -10,28 +10,44 @@
|
||||||
<p>第一名与第二名得票数相差不超过10%时随机抽签,按其得票数决定中签概率,否则选择第一名</p>
|
<p>第一名与第二名得票数相差不超过10%时随机抽签,按其得票数决定中签概率,否则选择第一名</p>
|
||||||
<p>投票结果仅供参考,最终解释权归部门总经理、副总经理所有</p>
|
<p>投票结果仅供参考,最终解释权归部门总经理、副总经理所有</p>
|
||||||
{% for last_result in last_results %}
|
{% for last_result in last_results %}
|
||||||
<p>今日{{ last_result }}最终得票数降低{{ 2 + loop.index0 }}0%</p>
|
<p>今日{{ last_result.value }}最终得票数降低{{ 2 + loop.index0 }}0%</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<form id="inputForm" class="form-inline" onsubmit="return false;">
|
<form id="inputForm" class="form-inline" onsubmit="return false;">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group mb-3">
|
<div class="mb-3">
|
||||||
|
<div class="input-group">
|
||||||
<label class="input-group-text" for="inputName" id="basic-addon1">姓名</label>
|
<label class="input-group-text" for="inputName" id="basic-addon1">姓名</label>
|
||||||
<input type="text" class="form-control"
|
<input type="text" class="form-control"
|
||||||
id="inputName" name="nickname" value="{{ nickname }}">
|
id="inputName" name="nickname" value="{{ user_menu.nickname }}">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
<div class="input-group mb-2">
|
<div class="input-group mb-2">
|
||||||
<span class="input-group-addon">我选择</span>
|
<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="col-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label for="range{{ loop.index }}" class="form-label">
|
<label for="range{{ loop.index }}" class="form-label">
|
||||||
<span>{{ choice['label'] }} - </span>
|
<span>{{ choice.label }} - </span>
|
||||||
<span class="percentage">{{ '{:.2f}'.format((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"
|
||||||
id="range{{ loop.index }}" name="{{ choice['name'] }}"
|
id="range{{ loop.index }}" name="choice.{{ choice.name }}"
|
||||||
min="0" max="10" step="1"
|
min="0" max="10" step="1"
|
||||||
value="{{ (menu.get(choice['name']) or 0) * 10 }}">
|
value="{{ (user_menu.menu.get(choice.name) or 0) * 10 }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<input class="form-check-input" type="checkbox" name="dislike[]"
|
||||||
|
id="checkDislike{{ loop.index }}" value="{{ choice.name }}"
|
||||||
|
{{ 'checked' if choice.name in user_menu.dislike else '' }}>
|
||||||
|
<label class="form-check-label" for="checkDislike{{ loop.index }}">
|
||||||
|
不吃
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,19 +55,17 @@
|
||||||
<button type="button" class="btn btn-primary" onclick="update()">更新</button>
|
<button type="button" class="btn btn-primary" onclick="update()">更新</button>
|
||||||
<button type="button" class="btn btn-secondary" onclick="clearValue()">不吃</button>
|
<button type="button" class="btn btn-secondary" onclick="clearValue()">不吃</button>
|
||||||
<button type="button" id="btnRoll"
|
<button type="button" id="btnRoll"
|
||||||
class="btn btn-secondary{{ "" if can_roll == True else ' disabled="disabled"' | safe }}"
|
class="btn btn-secondary" {{ "" if can_roll == True else ' disabled="disabled"' | safe }}
|
||||||
onclick="roll()">开始抽签
|
onclick="roll()">开始抽签
|
||||||
</button>
|
</button>
|
||||||
<div class="pt-3">
|
<div class="pt-3">
|
||||||
<label>大家的选择 - 总票数:{{ '{:.2f}'.format(total_vote | round(2)) }}</label>
|
<label>大家的选择 - 总票数:{{ '{:.2f}'.format(total_vote | round(2)) }}</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{{ " 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 "" }}">
|
||||||
<div class="row justify-content-between">
|
|
||||||
<span class="col-5">{{ key }}</span>
|
<span class="col-5">{{ key }}</span>
|
||||||
<span class="col-3">{{ '{:.2f}'.format(summary[key] | round(2)) }}票</span>
|
<span class="col-3">{{ '{:.2f}'.format(summary[key] | round(2)) }}票</span>
|
||||||
<span class="col-3">{{ '{:.2f}'.format(summary[key] / total_vote * 100 | round(2)) }}%</span>
|
<span class="col-3">{{ '{:.2f}'.format(summary[key] / total_vote * 100 | round(2)) }}%</span>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -66,11 +80,24 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if (eat_users|length) %}
|
||||||
|
<div class="pt-1 mb-3">
|
||||||
|
<label class="mb-2">就餐人员</label>
|
||||||
|
<ul class="list-group list-group-horizontal">
|
||||||
|
{% for user in eat_users %}
|
||||||
|
<li class="list-group-item">{{ user }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="pt-1 mb-3">
|
<div class="pt-1 mb-3">
|
||||||
<label class="mb-2">最近点餐结果</label>
|
<label class="mb-2">最近点餐结果</label>
|
||||||
<ul class="list-group list-group-horizontal">
|
<ul class="list-group">
|
||||||
{% for recent_result in recent_results %}
|
{% for recent_result in recent_results %}
|
||||||
<li class="list-group-item">{{ recent_result }}</li>
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<span>{{ recent_result.value }}</span>
|
||||||
|
<span>{{ recent_result.datestr }}</span>
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -103,15 +130,33 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("input[type=range]").change(function () {
|
const rangesInput = $("input[type=range]");
|
||||||
const values = $("input[type=range]").map(function () {
|
const checkBoxs = $("input[type=checkbox]")
|
||||||
|
rangesInput.change(function () {
|
||||||
|
const values = rangesInput.map(function () {
|
||||||
return $(this).val();
|
return $(this).val();
|
||||||
}).get();
|
}).get();
|
||||||
const summary = values.reduce((a, b) => parseInt(a) + parseInt(b));
|
const summary = values.reduce((a, b) => parseInt(a) + parseInt(b));
|
||||||
const spans = $(".percentage")
|
const spans = $(".percentage")
|
||||||
for (let i = 0; i < values.length; i++) {
|
for (let i = 0; i < values.length; i++) {
|
||||||
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) {
|
||||||
|
checkBoxs[i].checked = false;
|
||||||
|
{#$(checkBoxs[i]).trigger('blur');#}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkBoxs.change(function () {
|
||||||
|
const data = $('#inputForm').serializeJSON();
|
||||||
|
const values = checkBoxs.map(function () {
|
||||||
|
return $(this).val();
|
||||||
|
}).get();
|
||||||
|
for (let i = 0; i < values.length; i++) {
|
||||||
|
if (data.dislike.includes(values[i])) {
|
||||||
|
$(rangesInput[i]).val(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$(rangesInput[0]).trigger('change');
|
||||||
});
|
});
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
|
@ -132,8 +177,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearValue() {
|
function clearValue() {
|
||||||
|
const data = $('#inputForm').serializeJSON();
|
||||||
|
const nickname = data.nickname;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'dinner/update?value=',
|
url: 'dinner/update?nickname=' + nickname + '&value=',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function (result) {
|
success: function (result) {
|
||||||
if (result.code === 0) {
|
if (result.code === 0) {
|
||||||
|
|
Loading…
Reference in New Issue