main
parent
0b9902002e
commit
276215e23e
@ -0,0 +1,8 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="Flask">
|
||||
<option name="enabled" value="true" />
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.6 (flask+mysql flower)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,69 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="56">
|
||||
<item index="0" class="java.lang.String" itemvalue="pywin32" />
|
||||
<item index="1" class="java.lang.String" itemvalue="scipy" />
|
||||
<item index="2" class="java.lang.String" itemvalue="matplotlib" />
|
||||
<item index="3" class="java.lang.String" itemvalue="torch" />
|
||||
<item index="4" class="java.lang.String" itemvalue="numpy" />
|
||||
<item index="5" class="java.lang.String" itemvalue="torchvision" />
|
||||
<item index="6" class="java.lang.String" itemvalue="onnx" />
|
||||
<item index="7" class="java.lang.String" itemvalue="pycocotools" />
|
||||
<item index="8" class="java.lang.String" itemvalue="apex" />
|
||||
<item index="9" class="java.lang.String" itemvalue="opencv_python" />
|
||||
<item index="10" class="java.lang.String" itemvalue="Pillow" />
|
||||
<item index="11" class="java.lang.String" itemvalue="zlib" />
|
||||
<item index="12" class="java.lang.String" itemvalue="pip" />
|
||||
<item index="13" class="java.lang.String" itemvalue="openssl" />
|
||||
<item index="14" class="java.lang.String" itemvalue="setuptools" />
|
||||
<item index="15" class="java.lang.String" itemvalue="psutil" />
|
||||
<item index="16" class="java.lang.String" itemvalue="tensorflow" />
|
||||
<item index="17" class="java.lang.String" itemvalue="opencv-python" />
|
||||
<item index="18" class="java.lang.String" itemvalue="referencing" />
|
||||
<item index="19" class="java.lang.String" itemvalue="traitlets" />
|
||||
<item index="20" class="java.lang.String" itemvalue="matplotlib-inline" />
|
||||
<item index="21" class="java.lang.String" itemvalue="python-dateutil" />
|
||||
<item index="22" class="java.lang.String" itemvalue="pandocfilters" />
|
||||
<item index="23" class="java.lang.String" itemvalue="nbclient" />
|
||||
<item index="24" class="java.lang.String" itemvalue="wcwidth" />
|
||||
<item index="25" class="java.lang.String" itemvalue="executing" />
|
||||
<item index="26" class="java.lang.String" itemvalue="MarkupSafe" />
|
||||
<item index="27" class="java.lang.String" itemvalue="requests" />
|
||||
<item index="28" class="java.lang.String" itemvalue="jupyter_core" />
|
||||
<item index="29" class="java.lang.String" itemvalue="tinycss2" />
|
||||
<item index="30" class="java.lang.String" itemvalue="Jinja2" />
|
||||
<item index="31" class="java.lang.String" itemvalue="jsonschema-specifications" />
|
||||
<item index="32" class="java.lang.String" itemvalue="rpds-py" />
|
||||
<item index="33" class="java.lang.String" itemvalue="Pygments" />
|
||||
<item index="34" class="java.lang.String" itemvalue="stack-data" />
|
||||
<item index="35" class="java.lang.String" itemvalue="pyzmq" />
|
||||
<item index="36" class="java.lang.String" itemvalue="bleach" />
|
||||
<item index="37" class="java.lang.String" itemvalue="certifi" />
|
||||
<item index="38" class="java.lang.String" itemvalue="urllib3" />
|
||||
<item index="39" class="java.lang.String" itemvalue="jsonschema" />
|
||||
<item index="40" class="java.lang.String" itemvalue="beautifulsoup4" />
|
||||
<item index="41" class="java.lang.String" itemvalue="tornado" />
|
||||
<item index="42" class="java.lang.String" itemvalue="prompt_toolkit" />
|
||||
<item index="43" class="java.lang.String" itemvalue="jupyter_client" />
|
||||
<item index="44" class="java.lang.String" itemvalue="parso" />
|
||||
<item index="45" class="java.lang.String" itemvalue="pure_eval" />
|
||||
<item index="46" class="java.lang.String" itemvalue="nbformat" />
|
||||
<item index="47" class="java.lang.String" itemvalue="packaging" />
|
||||
<item index="48" class="java.lang.String" itemvalue="fastjsonschema" />
|
||||
<item index="49" class="java.lang.String" itemvalue="mistune" />
|
||||
<item index="50" class="java.lang.String" itemvalue="jedi" />
|
||||
<item index="51" class="java.lang.String" itemvalue="jupyterlab_pygments" />
|
||||
<item index="52" class="java.lang.String" itemvalue="asttokens" />
|
||||
<item index="53" class="java.lang.String" itemvalue="platformdirs" />
|
||||
<item index="54" class="java.lang.String" itemvalue="charset-normalizer" />
|
||||
<item index="55" class="java.lang.String" itemvalue="idna" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.6 (flask+mysql flower)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (flask+mysql flower)" project-jdk-type="Python SDK" />
|
||||
</project>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/flask+mysql flower.iml" filepath="$PROJECT_DIR$/.idea/flask+mysql flower.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,288 @@
|
||||
from flask import Flask, request, jsonify
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_cors import CORS
|
||||
import requests
|
||||
from datetime import datetime
|
||||
import base64
|
||||
|
||||
app = Flask(__name__)
|
||||
CORS(app)
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root@localhost/flower'
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
|
||||
UPLOAD_SERVICE_URL = 'https://c.2nicep.com:3000/uploads'
|
||||
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
|
||||
class FlowerShop(db.Model):
|
||||
__tablename__ = 'flower_shop'
|
||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
name = db.Column(db.String(100), nullable=False)
|
||||
description = db.Column(db.Text, nullable=True)
|
||||
price = db.Column(db.DECIMAL(10, 2), nullable=False)
|
||||
quantity = db.Column(db.Integer, nullable=False, default=0)
|
||||
image_url = db.Column(db.String(255), nullable=True)
|
||||
is_active = db.Column(db.Boolean, default=True)
|
||||
|
||||
|
||||
class Order(db.Model):
|
||||
__tablename__ = 'orders'
|
||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
flower_id = db.Column(db.Integer, db.ForeignKey('flower_shop.id'), nullable=False)
|
||||
quantity = db.Column(db.Integer, nullable=False)
|
||||
total_price = db.Column(db.DECIMAL(10, 2), nullable=False)
|
||||
status = db.Column(db.String(20), nullable=False, default='pending')
|
||||
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
||||
|
||||
flower = db.relationship('FlowerShop', backref=db.backref('orders', lazy=True))
|
||||
|
||||
|
||||
API_KEY = "kbt40nMOF8tLGg5IdZStJc4G"
|
||||
SECRET_KEY = "jUoj82HAALIzDWRlrTauoHwLcnB3eAn7"
|
||||
|
||||
|
||||
def get_access_token():
|
||||
url = "https://aip.baidubce.com/oauth/2.0/token"
|
||||
params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
|
||||
return str(requests.post(url, params=params).json().get("access_token"))
|
||||
|
||||
|
||||
@app.route('/api/identify', methods=['POST'])
|
||||
def identify_flower():
|
||||
if 'image' not in request.files:
|
||||
return jsonify({"error": "没有提供图片文件"}), 400
|
||||
|
||||
image_file = request.files['image']
|
||||
image = base64.b64encode(image_file.read()).decode('utf-8')
|
||||
|
||||
url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/plant?access_token=" + get_access_token()
|
||||
|
||||
payload = {
|
||||
"image": image,
|
||||
"baike_num": 0
|
||||
}
|
||||
headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.post(url, headers=headers, data=payload)
|
||||
result = response.json()
|
||||
|
||||
if 'result' in result and len(result['result']) > 0:
|
||||
top_result = result['result'][0]
|
||||
# 检查数据库中是否存在这种花
|
||||
flower = FlowerShop.query.filter(FlowerShop.name.ilike(f"%{top_result['name']}%")).first()
|
||||
|
||||
if flower:
|
||||
return jsonify({
|
||||
"id": flower.id,
|
||||
"name": flower.name,
|
||||
"description": flower.description,
|
||||
"price": float(flower.price),
|
||||
"quantity": flower.quantity,
|
||||
"image_url": flower.image_url
|
||||
}), 200
|
||||
else:
|
||||
# 如果数据库中没有这种花,返回识别的名称和概率
|
||||
return jsonify({
|
||||
"name": top_result['name'],
|
||||
"probability": top_result['score']
|
||||
}), 200
|
||||
else:
|
||||
return jsonify({"error": "未能识别花卉"}), 404
|
||||
|
||||
|
||||
def upload_file_to_service(file):
|
||||
if not file:
|
||||
return None
|
||||
files = {'images': (file.filename, file.read(), file.content_type)}
|
||||
try:
|
||||
response = requests.post(UPLOAD_SERVICE_URL, files=files)
|
||||
if response.status_code == 200:
|
||||
return response.json()['files'][0]
|
||||
else:
|
||||
print(f"Upload failed: {response.text}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Error during upload: {str(e)}")
|
||||
return None
|
||||
|
||||
|
||||
@app.route('/api/flowers', methods=['GET'])
|
||||
def get_flowers():
|
||||
query = request.args.get('query', '')
|
||||
flowers = FlowerShop.query.filter(FlowerShop.name.ilike(f'%{query}%'), FlowerShop.is_active == True).all()
|
||||
return jsonify([{
|
||||
"id": flower.id,
|
||||
"name": flower.name,
|
||||
"description": flower.description,
|
||||
"price": float(flower.price),
|
||||
"quantity": flower.quantity,
|
||||
"image_url": flower.image_url
|
||||
} for flower in flowers])
|
||||
|
||||
|
||||
@app.route('/api/flowers', methods=['POST'])
|
||||
def add_flower():
|
||||
name = request.form.get('name')
|
||||
description = request.form.get('description')
|
||||
price = request.form.get('price')
|
||||
quantity = request.form.get('quantity')
|
||||
image = request.files.get('image')
|
||||
|
||||
if not name or not price or not quantity:
|
||||
return jsonify({"error": "Name, price, and quantity are required"}), 400
|
||||
|
||||
try:
|
||||
price = float(price)
|
||||
quantity = int(quantity)
|
||||
except ValueError:
|
||||
return jsonify({"error": "Invalid price or quantity format"}), 400
|
||||
|
||||
if quantity < 0:
|
||||
return jsonify({"error": "Quantity must be non-negative"}), 400
|
||||
|
||||
image_url = upload_file_to_service(image)
|
||||
|
||||
try:
|
||||
new_flower = FlowerShop(name=name, description=description, price=price, quantity=quantity, image_url=image_url)
|
||||
db.session.add(new_flower)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
print(f"Database error: {str(e)}")
|
||||
return jsonify({"error": "Failed to add flower to database"}), 500
|
||||
|
||||
return jsonify({
|
||||
"message": "Flower added successfully",
|
||||
"id": new_flower.id,
|
||||
"name": new_flower.name,
|
||||
"description": new_flower.description,
|
||||
"price": float(new_flower.price),
|
||||
"quantity": new_flower.quantity,
|
||||
"image_url": new_flower.image_url
|
||||
}), 201
|
||||
|
||||
|
||||
@app.route('/api/my-products', methods=['GET'])
|
||||
def get_my_products():
|
||||
products = FlowerShop.query.all()
|
||||
return jsonify([{
|
||||
"id": product.id,
|
||||
"name": product.name,
|
||||
"description": product.description,
|
||||
"price": float(product.price),
|
||||
"quantity": product.quantity,
|
||||
"image_url": product.image_url,
|
||||
"is_active": product.is_active
|
||||
} for product in products])
|
||||
|
||||
|
||||
@app.route('/api/products/<int:product_id>', methods=['PUT'])
|
||||
def update_product(product_id):
|
||||
product = FlowerShop.query.get_or_404(product_id)
|
||||
data = request.json
|
||||
product.name = data.get('name', product.name)
|
||||
product.description = data.get('description', product.description)
|
||||
product.price = data.get('price', product.price)
|
||||
product.quantity = data.get('quantity', product.quantity)
|
||||
product.is_active = data.get('is_active', product.is_active)
|
||||
|
||||
try:
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({"error": f"Failed to update product: {str(e)}"}), 500
|
||||
|
||||
return jsonify({"message": "Product updated successfully"})
|
||||
|
||||
|
||||
@app.route('/api/products/<int:product_id>/toggle-status', methods=['POST'])
|
||||
def toggle_product_status(product_id):
|
||||
product = FlowerShop.query.get_or_404(product_id)
|
||||
product.is_active = not product.is_active
|
||||
|
||||
try:
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({"error": f"Failed to toggle product status: {str(e)}"}), 500
|
||||
|
||||
return jsonify({"message": f"Product {'activated' if product.is_active else 'deactivated'} successfully"})
|
||||
|
||||
|
||||
@app.route('/api/orders', methods=['GET'])
|
||||
def get_orders():
|
||||
try:
|
||||
orders = Order.query.all()
|
||||
return jsonify([{
|
||||
"id": order.id,
|
||||
"flowerName": order.flower.name if order.flower else "Unknown",
|
||||
"quantity": order.quantity,
|
||||
"totalPrice": float(order.total_price),
|
||||
"status": order.status,
|
||||
"createdAt": order.created_at.isoformat()
|
||||
} for order in orders])
|
||||
except Exception as e:
|
||||
print(f"Error fetching orders: {str(e)}")
|
||||
return jsonify({"error": "Failed to fetch orders"}), 500
|
||||
|
||||
|
||||
@app.route('/api/orders', methods=['POST'])
|
||||
def create_order():
|
||||
data = request.json
|
||||
flower_id = data.get('flowerId')
|
||||
quantity = data.get('quantity', 1)
|
||||
|
||||
if not flower_id or not quantity:
|
||||
return jsonify({"error": "Flower ID and quantity are required"}), 400
|
||||
|
||||
flower = FlowerShop.query.get(flower_id)
|
||||
if not flower:
|
||||
return jsonify({"error": "Flower not found"}), 404
|
||||
|
||||
if flower.quantity < quantity:
|
||||
return jsonify({"error": "Not enough stock"}), 400
|
||||
|
||||
total_price = flower.price * quantity
|
||||
|
||||
try:
|
||||
new_order = Order(flower_id=flower_id, quantity=quantity, total_price=total_price)
|
||||
flower.quantity -= quantity # 减少库存
|
||||
db.session.add(new_order)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
print(f"Database error: {str(e)}")
|
||||
return jsonify({"error": "Failed to create order"}), 500
|
||||
|
||||
return jsonify({
|
||||
"message": "Order created successfully",
|
||||
"orderId": new_order.id,
|
||||
"totalPrice": float(new_order.total_price)
|
||||
}), 201
|
||||
|
||||
|
||||
@app.route('/api/orders/<int:order_id>/cancel', methods=['POST'])
|
||||
def cancel_order(order_id):
|
||||
order = Order.query.get_or_404(order_id)
|
||||
if order.status != 'pending':
|
||||
return jsonify({"error": "Only pending orders can be cancelled"}), 400
|
||||
|
||||
try:
|
||||
order.status = '已取消'
|
||||
order.flower.quantity += order.quantity # 恢复库存
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({"error": f"Failed to cancel order: {str(e)}"}), 500
|
||||
|
||||
return jsonify({"message": "订单取消成功!"})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
app.run(debug=True)
|
Loading…
Reference in new issue