Explorar o código

feat: 管理员管理积分商城系统

SongZihuan %!s(int64=3) %!d(string=hai) anos
pai
achega
6b198a3e2a

+ 20 - 0
app/static/styles/store/add.css

@@ -0,0 +1,20 @@
+#name-input, #score-input, #quantity-input {
+    display: block;
+    font-size: 20px;
+    width: 100%;
+}
+
+#name-label, #score-label, #quantity-label {
+    display: block;
+    margin-top: 30px;
+    font-size: 22px;
+}
+
+#add-submit {
+    position: absolute;
+    right: 0;
+
+    margin-top: 20px;
+    font-size: 18px;
+    width: 60px;
+}

+ 15 - 1
app/static/styles/store/store.css

@@ -5,6 +5,20 @@
     align-items: flex-start;
 }
 
+#add-goods, #add-goods:active, #add-goods:link, #add-goods:visited {
+    display: block;
+    text-decoration: none;
+    color: black;
+
+    font-size: 20px;
+    float: right;
+    margin: 0 10px;
+}
+
+#add-goods:hover {
+    color: red;
+}
+
 #info {
     font-size: 20px;
     line-height: 25px;
@@ -13,7 +27,7 @@
 }
 
 #info-score {
-    margin-right: 10px;
+    margin: 0 10px;
     float: right;
 }
 

+ 72 - 4
app/store/views.py

@@ -16,8 +16,15 @@ store = Blueprint("store", __name__)
 app: Optional[Flask] = None
 
 
-class BuyForm(FlaskForm):
-    quantity = TextField(validators=[DataRequired(message="请输入兑换数量")])
+class BuySetForm(FlaskForm):
+    quantity = TextField(validators=[DataRequired(message="请输入数量")])
+    submit = SubmitField()
+
+
+class AddNewGoodsForm(FlaskForm):
+    name = TextField(validators=[DataRequired(message="请输入名字")])
+    quantity = TextField(validators=[DataRequired(message="请输入库存")])
+    score = TextField(validators=[DataRequired(message="请输入库存")])
     submit = SubmitField()
 
 
@@ -29,7 +36,7 @@ def index():
     购买时发送请求到 store.buy
     :return:
     """
-    form = BuyForm()
+    form = BuySetForm()
     store_list = views.website.get_store_list()
     user: web_user.WebUser = current_user
     user.update_info()
@@ -44,7 +51,7 @@ def buy(goods_id: int):
     仅支持 Post 请求
     非表单的一律 404
     """
-    form = BuyForm()
+    form = BuySetForm()
     if form.validate_on_submit():
         try:
             quantity = int(form.quantity.data)
@@ -75,9 +82,54 @@ def manager_required(f):
         if not current_user.is_manager():
             abort(403)
         return f(*args, **kwargs)
+
     return func
 
 
+@store.route('/set/<int:goods_id>', methods=['POST'])
+@login_required
+@manager_required
+def set_goods(goods_id: int):
+    """
+    设置库存
+    仅支持 Post 请求
+    非表单的一律 404
+    """
+    form = BuySetForm()
+    if form.validate_on_submit():
+        try:
+            quantity = int(form.quantity.data)
+        except (TypeError, ValueError):
+            flash("请输入正确的数量")
+        else:
+            if not views.website.set_goods_quantity(quantity, goods_id):
+                abort(404)
+            return redirect(url_for("store.index"))
+    abort(404)
+
+
+@store.route('/set_score/<int:goods_id>', methods=['POST'])
+@login_required
+@manager_required
+def set_goods_score(goods_id: int):
+    """
+    设置兑换积分
+    仅支持 Post 请求
+    非表单的一律 404
+    """
+    form = BuySetForm()
+    if form.validate_on_submit():
+        try:
+            score = int(form.quantity.data)
+        except (TypeError, ValueError):
+            flash("请输入正确的数量")
+        else:
+            if not views.website.set_goods_score(score, goods_id):
+                abort(404)
+            return redirect(url_for("store.index"))
+    abort(404)
+
+
 @store.route('/check/<string:user>/<string:order>')
 @login_required
 @manager_required
@@ -112,6 +164,22 @@ def confirm(token):
     return redirect(url_for("hello.index"))
 
 
+@store.route('/add', methods=["GET", "POST"])
+@login_required
+@manager_required
+def add_new_goods():
+    form = AddNewGoodsForm()
+    if form.validate_on_submit():
+        name = form.name.data
+        score = form.score.data
+        quantity = form.quantity.data
+        if not views.website.add_new_goods(name, score, quantity):
+            abort(404)
+        flash(f"新增商品 {name} 成功")
+        return redirect(url_for("store.add_new_goods"))
+    return render_template("store/add.html", add_form=form)
+
+
 def creat_store_website(app_: Flask):
     global app
     if app is None:

+ 31 - 0
app/templates/store/add.html

@@ -0,0 +1,31 @@
+{% extends "base.html" %}
+
+{% block style %}
+    {{ super() }}
+    <link href="{{ url_for('static', filename='styles/store/add.css') }}" rel="stylesheet">
+{% endblock %}
+
+{% block title %} 新增商品 {% endblock %}
+{% block h1_title %} 新增商品 {% endblock %}
+
+{% block content %}
+    <form method="post" action="{{ url_for('store.add_new_goods') }}">
+        {{ add_form.hidden_tag() }}
+        <label>
+            <p id="name-label">物品名字: </p><br>
+            {{ add_form.name(id="name-input") }}
+        </label>
+
+        <label>
+            <p id="score-label">物品积分: </p><br>
+            {{ add_form.score(id="score-input", type="number", value=10) }}
+        </label>
+
+        <label>
+            <p id="quantity-label">物品库存: </p><br>
+            {{ add_form.quantity(id="quantity-input", type="number", value=10) }}
+        </label>
+
+        {{ add_form.submit(id="add-submit", value="提交") }}
+    </form>
+{% endblock %}

+ 4 - 2
app/templates/store/store.html

@@ -11,13 +11,15 @@
 
 {% block content %}
     <div id="info">
-        {% if current_user.is_anonymous %}
+        {% if current_user.is_manager() %}
+            <a id="add-goods" href="{{ url_for("store.add_new_goods") }}"> 新增商品 </a>
+        {% elif current_user.is_anonymous %}
             <p id="info-score"> 未登录 </p>
         {% else %}
             <p id="info-score"> 当前积分: {{ current_user.score }} </p>
         {% endif %}
     </div>
     <section id="store">
-        {{ store.get_store_item(store_list, store_form) }}
+        {{ store.get_store_item(store_list, store_form, current_user) }}
     </section>
 {% endblock %}

+ 42 - 18
app/templates/store/store_macro.html

@@ -1,26 +1,50 @@
-{% macro _get_store_item(infos, store_form) %}
-    {% if infos[2] > 0 %}
-    <section id="store-item">
-        <p class="store-item-info store-item-title"> {{ infos[0] }} </p>
-        <p class="store-item-info"> 消耗 {{ infos[1] }} 积分</p>
-        <p class="store-item-info"> 剩余 {{ infos[2] }} 件 </p>
-        <hr>
-        <form method="post" action="{{ url_for("store.buy", goods_id=infos[3]) }}">
-            {{ store_form.hidden_tag() }}
-            <label class="store-item-num">
-                个数:
-                {{ store_form.quantity(type="number", class="store-item-num", placeholder="个数", value="1") }}
-            </label>
-            {{ store_form.submit(value="兑换", class="store-item-submit") }}
-        </form>
-    </section>
+{% macro _get_store_item(infos, store_form, user) %}
+    {% if user.is_manager or infos[2] > 0 %}
+        <section id="store-item">
+            <p class="store-item-info store-item-title"> {{ infos[0] }} </p>
+            <p class="store-item-info"> 消耗 {{ infos[1] }} 积分</p>
+            <p class="store-item-info"> 剩余 {{ infos[2] }} 件 </p>
+            <hr>
+            <form
+                    {% if user.is_manager %}
+                        action="{{ url_for("store.set_goods", goods_id=infos[3]) }}"
+                    {% else %}
+                        action="{{ url_for("store.buy", goods_id=infos[3]) }}"
+                    {% endif %} method="post">
+                {{ store_form.hidden_tag() }}
+                {% if user.is_manager %}
+                    <label class="store-item-num">
+                        库存:
+                        {{ store_form.quantity(type="number", class="store-item-num", placeholder="库存", value=infos[2]) }}
+                    </label>
+                    {{ store_form.submit(value="设定库存", class="store-item-submit") }}
+                {% else %}
+                    <label class="store-item-num">
+                        个数:
+                        {{ store_form.quantity(type="number", class="store-item-num", placeholder="个数", value="1") }}
+                    </label>
+                    {{ store_form.submit(value="兑换", class="store-item-submit") }}
+                {% endif %}
+            </form>
+            {% if user.is_manager %}
+                <hr>
+                <form action="{{ url_for("store.set_goods_score", goods_id=infos[3]) }}" method="post">
+                    {{ store_form.hidden_tag() }}
+                    <label class="store-item-num">
+                        积分:
+                        {{ store_form.quantity(type="number", class="store-item-num", placeholder="积分", value=infos[1]) }}
+                    </label>
+                    {{ store_form.submit(value="设定积分", class="store-item-submit") }}
+                </form>
+            {% endif %}
+        </section>
     {% endif %}
 {% endmacro %}
 
-{% macro get_store_item(info_lines, store_form) %}
+{% macro get_store_item(info_lines, store_form, user) %}
     {% if info_lines %}
         {% for line in info_lines %}
-            {{ _get_store_item(line, store_form) }}
+            {{ _get_store_item(line, store_form, user) }}
         {% endfor %}
     {% else %}
         <section id="store-item">

+ 10 - 1
app/web.py

@@ -14,7 +14,7 @@ from sql.db import DB
 from sql.garbage import count_garbage_by_uid, get_garbage_by_uid
 from sql.user import find_user_by_name, find_user_by_id, get_rank_for_user, count_all_user
 from sql.news import write_news, get_news, get_news_count, delete_news
-from sql.store import check_order, get_goods_from_order
+from sql.store import check_order, get_goods_from_order, set_goods_quantity, set_goods_score, add_new_goods
 
 from . import web_user
 from . import web_goods
@@ -111,6 +111,15 @@ class StoreWebsite(WebsiteBase):
     def confirm_order(self, order_id: int, uid: uid_t) -> bool:
         return confirm_order(order_id, uid, self._db)
 
+    def set_goods_quantity(self, quantity: int, goods_id: int):
+        return set_goods_quantity(quantity, goods_id, self._db)
+
+    def set_goods_score(self, score: score_t, goods_id: int):
+        return set_goods_score(score, goods_id, self._db)
+
+    def add_new_goods(self, name: str, score: score_t, quantity: int):
+        return add_new_goods(name, score, quantity, self._db)
+
 
 class RankWebsite(WebsiteBase):
     def get_rank(self, page: int, order_by: str = "DESC", url: str = "rank_up"):

+ 30 - 0
sql/store.py

@@ -83,3 +83,33 @@ def confirm_order(order: int, uid: uid_t, db: DB) -> bool:
         return False
     assert cur.rowcount == 1
     return True
+
+
+def set_goods_quantity(quantity: int, goods_id, db: DB):
+    cur = db.update(table="goods",
+                    kw={"Quantity": f"{quantity}"},
+                    where=f"GoodsID={goods_id}")
+    if cur is None or cur.rowcount == 0:
+        return False
+    assert cur.rowcount == 1
+    return True
+
+
+def set_goods_score(score: score_t, goods_id, db: DB):
+    cur = db.update(table="goods",
+                    kw={"Score": f"{score}"},
+                    where=f"GoodsID={goods_id}")
+    if cur is None or cur.rowcount == 0:
+        return False
+    assert cur.rowcount == 1
+    return True
+
+
+def add_new_goods(name: str, score: score_t, quantity: int, db: DB):
+    cur = db.insert(table='goods',
+                    columns=["Name", "Quantity", "Score"],
+                    values=f"'{name}', {quantity}, {score}")
+    if cur is None or cur.rowcount == 0:
+        return False
+    assert cur.rowcount == 1
+    return True