浏览代码

Сделал отображение задач, на странице проекта изменил requirements.txt

Andrei 3 年之前
父节点
当前提交
8e97e40c38
共有 6 个文件被更改,包括 233 次插入6 次删除
  1. 30 0
      functions.py
  2. 11 2
      main.py
  3. 二进制
      requirements.txt
  4. 125 0
      static/css/project.css
  5. 7 2
      static/js/project.js
  6. 60 2
      templates/project.html

+ 30 - 0
functions.py

@@ -1,3 +1,4 @@
+import datetime
 import smtplib
 from json import loads
 from email.message import EmailMessage
@@ -6,6 +7,7 @@ from data.users import User
 from data.staff_projects import StaffProjects
 from data import db_session
 import uuid
+import pymorphy2
 
 
 def check_password(password=''):
@@ -90,3 +92,31 @@ def save_project_logo(photo):
     with open(filename, 'wb') as f:
         photo.save(f)
     return filename
+
+
+def overdue_quest_project(quest):
+    if str(quest.deadline.date()) == str(datetime.datetime.now().date()):
+        quest.overdue = 'today'
+    elif quest.deadline < datetime.datetime.now():
+        quest.overdue = 'yes'
+        quest.time_left = 'Просрочено на' + round_date(quest.deadline)
+    else:
+        quest.overdue = 'no'
+        quest.time_left = 'Еще есть: ' + round_date(quest.deadline)
+    return quest
+
+
+def round_date(date_time):
+    morph = pymorphy2.MorphAnalyzer()
+    difference = abs(date_time - datetime.datetime.now()).days
+    resp = ''
+    if difference // 365:
+        resp += f'{difference // 365} {morph.parse("год")[0].make_agree_with_number(difference // 365).word}'
+        difference -= 365 * (difference // 365)
+    if difference // 30:
+        resp += ', ' if resp else ' ' + f'{difference // 30}' \
+                                        f' {morph.parse("месяц")[0].make_agree_with_number(difference // 30).word}'
+        difference -= 30 * (difference // 30)
+    if difference:
+        resp += ', ' if resp else ' ' + f'{difference} {morph.parse("день")[0].make_agree_with_number(difference).word}'
+    return f'{resp}'

+ 11 - 2
main.py

@@ -11,7 +11,8 @@ from itsdangerous import URLSafeTimedSerializer, SignatureExpired
 from sqlalchemy import or_
 from json import loads
 
-from functions import check_password, mail, init_db_default, get_projects_data, get_user_data, save_project_logo
+from functions import check_password, mail, init_db_default, get_projects_data, get_user_data, save_project_logo, \
+    overdue_quest_project
 from forms.edit_profile import EditProfileForm
 from forms.login import LoginForm
 from forms.find_project import FindProjectForm
@@ -115,7 +116,15 @@ def project(id_project):
             if current_user.id == current_project.creator or current_user.id in list(map(lambda x: x.user, staff)):
                 staff = list(map(lambda x: get_user_data(x), data_session.query(User).filter(
                     User.id.in_(list(map(lambda x: x.user, staff)))).all())) if staff else []
-                return render_template('project.html', project=current_project, title=current_project.name, staff=staff)
+                quests = data_session.query(Quests).filter(Quests.project == current_project.id).all()
+                if quests:
+                    quests.sort(key=lambda x: (x.realized, x.deadline))
+                    quests = list(map(lambda x: overdue_quest_project(x), quests))
+                return render_template('project.html',
+                                       project=current_project,
+                                       title=current_project.name,
+                                       staff=staff,
+                                       quests=quests)
             else:
                 abort(403)
         else:

二进制
requirements.txt


+ 125 - 0
static/css/project.css

@@ -104,6 +104,9 @@
     font-size: 3vw;
     margin-bottom: 15px;
 }
+.header_title_2 {
+    width: 51vw !important;
+}
 .header_title {
     width: 100%;
 }
@@ -147,4 +150,126 @@
     flex-direction: row;
     flex-wrap: nowrap;
     width: 60vw;
+    justify-content: center;
+    align-items: flex-start;
+}
+.list_quests {
+    width: 95%;
+    margin-left: 2.5%;
+    margin-top: 2vw;
+    overflow-y: hidden;
+    overflow-x: hidden;
+}
+.quest_header_button {
+    height: 4.5vw;
+    width: 100%;
+    text-align: left;
+    border-radius: 5vw;
+    background-color: #9E795A;
+    border-color: #9E795A;
+    border-bottom-color: #9E795A;
+    color: #ffffff;
+    display: flex;
+    align-items: center;
+}
+.quest_button_block_one {
+    width: 50%;
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+}
+.quest_title_block {
+    width: 90%;
+    height: 4vw;
+    display: flex;
+    align-items: center;
+}
+.quest_title {
+    overflow-y: hidden;
+    overflow-x: hidden;
+    max-height: 1.5vw;
+    font-size: 1.5vw;
+    display: flex;
+    align-items: center;
+    margin-top: 0.7vw;
+    margin-left: 1.8vw;
+}
+.deadline_block {
+    border-radius: 5vw !important;
+    width: 15vw;
+    height: 70%;
+    margin-top: 2%;
+    font-size: 1vw;
+    display: flex;
+    color: #000000 !important;
+    align-items: center;
+    justify-content: center;
+    flex-direction: row;
+}
+.quest_body_block {
+    background-color: #9E795A;
+    width: 100%;
+    height: 20vw;
+    border-radius: 2vw;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.quest_body {
+    width: 94%;
+    height: 94%;
+    display: flex;
+    align-items: center;
+    justify-content: space-around;
+}
+.quest_description_block {
+    width: 70%;
+    height: 90%;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+}
+.quest_description {
+    width: 100%;
+    height: 100%;
+    background-color: #dcb495;
+    border-radius: 2vw;
+    overflow-y: auto;
+}
+.quest_description::-webkit-scrollbar, .task_block::-webkit-scrollbar-thumb {
+    width: 0.8vw !important;
+}
+.quest_description::-webkit-scrollbar-thumb, .task_block::-webkit-scrollbar-thumb {
+    background-color: #d49d51 !important;    /* цвет плашки */
+    border-radius: 5vw !important;       /* закругления плашки */
+    border: 0.25vw solid #ffffff !important;
+}
+.quest_description_text {
+    margin: 20px;
+}
+.quest_solve_button {
+    width: 13vw;
+    height: 5vw;
+    background-color: #000000;
+    border: 2px solid #ffffff;
+    border-radius: 3vw;
+    margin-left: 2vw;
+}
+.quest_solve_link:hover {
+    text-decoration: none;
+    color: #000000;
+}
+.quest_solve_text {
+    width: 13vw;
+    height: 5vw;
+    text-align: center;
+    font-size: 1.5vw;
+    color: #ffffff;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+#quest_solve_link_id {
+    display: none;
 }

+ 7 - 2
static/js/project.js

@@ -1,2 +1,7 @@
-var edit_button = document.getElementById("edit_button");
-edit_button.href = String(window.location.href) + '/edit';
+var edit_button = document.getElementById("edit_button"),
+new_task_link = document.getElementById("new_task_link"),
+quest_solve_link = document.getElementById("quest_solve_link"),
+quest_solve_link_id = document.getElementById("quest_solve_link_id");
+edit_button.href = String(window.location.href) + '/edit';
+new_task_link.href = String(window.location.href) + '/task/new';
+quest_solve_link.href = String(window.location.href) + '/quest/' + quest_solve_link_id.className;

+ 60 - 2
templates/project.html

@@ -35,14 +35,72 @@
             <div class="head_task">
                 <h3 class="header_title_2">Задачи</h3>
                 <div class="new_task_block">
-                    <a class="new_task_link" href="/">
+                    <a class="new_task_link" id="new_task_link" href="/">
                         <img class="new_task_image" src="../static/images/plus_b.png">
                     </a>
                 </div>
             </div>
             <div class="task_block">
                 <div class="task">
-                    p
+                    {% for quest in quests %}
+                    <div class="accordion list_quests" id="accordionPanelsStayOpen{{ quest.id }}">
+                        <div class="accordion-item quest">
+                            <h2 class="accordion-header quest_header" id="panelsStayOpen-heading{{ quest.id }}">
+                                <button class="accordion-button quest_header_button" type="button"
+                                        data-bs-toggle="collapse"
+                                        data-bs-target="#panelsStayOpen-collapse{{ quest.id }}" aria-expanded="true"
+                                        aria-controls="panelsStayOpen-collapse{{ quest.id }}">
+                                    <div class="quest_button_block_one">
+                                        <div class="quest_title_block">
+                                            <p class="quest_title">{{ quest.name }}</p>
+                                        </div>
+                                    </div>
+                                    {% if quest.overdue == 'yes' and quest.realized != 1 %}
+                                    <div class="deadline_block alert alert-danger" role="alert">
+                                        {{ quest.time_left }}
+                                    </div>
+                                    {% elif quest.overdue == 'today' and quest.realized != 1 %}
+                                    <div class="deadline_block alert alert-warning" role="alert">
+                                        Дедлайн сегодня
+                                    </div>
+                                    {% elif quest.overdue == 'no' and quest.realized != 1 %}
+                                    <div class="deadline_block alert alert-success" role="alert">
+                                        {{ quest.time_left }}
+                                    </div>
+                                    {% else %}
+                                    <div class="deadline_block alert alert-success" role="alert">
+                                        Задача выполнена
+                                    </div>
+                                    {% endif %}
+                                </button>
+                            </h2>
+                            <div id="panelsStayOpen-collapse{{ quest.id }}"
+                                 class="accordion-collapse collapse quest_body_block"
+                                 aria-labelledby="panelsStayOpen-heading{{ quest.id }}">
+                                <div class="accordion-body quest_body">
+                                    {% if quest.realized == 0 %}
+                                    <div class="quest_body">
+                                        <div class="quest_description_block">
+                                            <p class="quest_description_title">Описание</p>
+                                            <div class="quest_description">
+                                                <p class="quest_description_text">{{ quest.description }}</p>
+                                            </div>
+                                        </div>
+                                        <div class="quest_solve_button">
+                                            <a class="quest_solve_link" id="quest_solve_link">
+                                                <p id="quest_solve_link_id" class="{{ quest.id }}"></p>
+                                                <p class="quest_solve_text">Решить</p>
+                                            </a>
+                                        </div>
+                                    </div>
+                                    {% else %}
+
+                                    {% endif %}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    {% endfor %}
                 </div>
             </div>
         </div>