Files
bolt-website/app.py
2025-05-27 17:31:00 +08:00

386 lines
11 KiB
Python

from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Length
from flask_ckeditor import CKEditor, CKEditorField
from datetime import datetime
import os
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'your-secret-key')
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'mysql+pymysql://user:password@localhost/liehoo_db')
app.config['UPLOAD_FOLDER'] = 'static/uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
ckeditor = CKEditor(app)
# Models
class User(UserMixin, db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
articles = db.relationship('Article', backref='author', lazy=True)
class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
content = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
# Forms
class LoginForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired()])
password = PasswordField('密码', validators=[DataRequired()])
submit = SubmitField('登录')
class ArticleForm(FlaskForm):
title = StringField('标题', validators=[DataRequired(), Length(max=200)])
content = CKEditorField('内容', validators=[DataRequired()])
submit = SubmitField('发布')
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# 默认路由 - 首页
@app.route('/')
def index():
featured_article = Article.query.order_by(Article.created_at.desc()).first()
latest_articles = Article.query.order_by(Article.created_at.desc()).limit(4).all()
return render_template('index.html', featured_article=featured_article, latest_articles=latest_articles)
# 文章详情页路由
@app.route('/article/<int:id>')
def article_detail(id):
article = Article.query.get_or_404(id)
return render_template('article.html', article=article)
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('admin'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and user.password == form.password.data: # In production, use proper password hashing
login_user(user)
return redirect(url_for('admin'))
flash('用户名或密码错误')
return render_template('login.html', form=form)
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('login'))
@app.route('/admin')
@login_required
def admin():
articles = Article.query.order_by(Article.created_at.desc()).all()
return render_template('admin.html', articles=articles)
@app.route('/admin/article/new', methods=['GET', 'POST'])
@login_required
def new_article():
form = ArticleForm()
if form.validate_on_submit():
article = Article(
title=form.title.data,
content=form.content.data,
author_id=current_user.id
)
db.session.add(article)
db.session.commit()
flash('文章发布成功')
return redirect(url_for('admin'))
return render_template('article_form.html', form=form)
@app.route('/admin/article/<int:id>/edit', methods=['GET', 'POST'])
@login_required
def edit_article(id):
article = Article.query.get_or_404(id)
form = ArticleForm(obj=article)
if form.validate_on_submit():
article.title = form.title.data
article.content = form.content.data
article.updated_at = datetime.utcnow()
db.session.commit()
flash('文章更新成功')
return redirect(url_for('admin'))
return render_template('article_form.html', form=form, article=article)
@app.route('/admin/article/<int:id>/delete', methods=['POST'])
@login_required
def delete_article(id):
article = Article.query.get_or_404(id)
db.session.delete(article)
db.session.commit()
flash('文章已删除')
return redirect(url_for('admin'))
@app.route('/api/articles/latest')
def latest_articles():
articles = Article.query.order_by(Article.created_at.desc()).limit(5).all()
return jsonify([{
'id': article.id,
'title': article.title,
'created_at': article.created_at.strftime('%Y-%m-%d')
} for article in articles])
# 网络营销业务线 - 腾讯广告事业部
@app.route('/services/marketing/tencent/information-flow')
def information_flow():
return render_template('submenu_page.html', title='信息流')
@app.route('/services/marketing/tencent/short-video')
def short_video():
return render_template('submenu_page.html', title='短视频')
@app.route('/services/marketing/tencent/search')
def search():
return render_template('submenu_page.html', title='搜索(搜狗)')
# 网络营销业务线 - 平台媒体事业部
@app.route('/services/marketing/platform/kuaishou')
def kuaishou():
return render_template('submenu_page.html', title='快手项目部')
@app.route('/services/marketing/platform/360')
def platform_360():
return render_template('submenu_page.html', title='360项目部')
@app.route('/services/marketing/platform/ali')
def ali():
return render_template('submenu_page.html', title='阿里汇川项目部')
@app.route('/services/marketing/platform/gaode')
def gaode():
return render_template('submenu_page.html', title='高德项目部')
# 软件管理业务线
@app.route('/services/software/yonyou')
def yonyou():
return render_template('submenu_page.html', title='用友事业部')
@app.route('/services/software/dingtalk')
def dingtalk():
return render_template('submenu_page.html', title='钉钉项目部')
@app.route('/services/software/wecom')
def wecom():
return render_template('submenu_page.html', title='企微项目部')
@app.route('/services/software/feishu')
def feishu():
return render_template('submenu_page.html', title='飞书项目部')
@app.route('/services/software/youzan')
def youzan():
return render_template('submenu_page.html', title='有赞项目部')
@app.route('/services/software/crm')
def crm():
return render_template('submenu_page.html', title='CRM项目部')
@app.route('/services/software/development')
def development():
return render_template('submenu_page.html', title='技术开发部')
# 财税法务业务线
@app.route('/services/legal/badun-legal')
def badun_legal():
return render_template('submenu_page.html', title='八盾法务')
@app.route('/services/legal/badun-asset')
def badun_asset():
return render_template('submenu_page.html', title='八盾资产')
@app.route('/services/legal/beike-finance')
def beike_finance():
return render_template('submenu_page.html', title='贝壳财税')
# 直播电商事业部
@app.route('/ecommerce/live/selection')
def selection():
return render_template('submenu_page.html', title='选品招商')
@app.route('/ecommerce/live/traceability')
def traceability():
return render_template('submenu_page.html', title='溯源专场')
@app.route('/ecommerce/live/supply-chain')
def supply_chain():
return render_template('submenu_page.html', title='供应链金融')
# 达人运营事业部
@app.route('/ecommerce/talent/business')
def talent_business():
return render_template('submenu_page.html', title='达人商务')
@app.route('/ecommerce/talent/account')
def account_operation():
return render_template('submenu_page.html', title='账号运营')
@app.route('/ecommerce/talent/live')
def live_operation():
return render_template('submenu_page.html', title='直播运营')
# 平台电商事业部
@app.route('/ecommerce/platform/pinduoduo')
def pinduoduo():
return render_template('submenu_page.html', title='拼多多项目部')
@app.route('/ecommerce/platform/taotian')
def taotian():
return render_template('submenu_page.html', title='淘天项目部')
@app.route('/ecommerce/platform/jd')
def jd():
return render_template('submenu_page.html', title='京东项目部')
# 文旅与大健康
@app.route('/tourism-health/yueke')
def yueke():
return render_template('submenu_page.html', title='悦客嘉酒店管理')
@app.route('/tourism-health/stem-cell')
def stem_cell():
return render_template('submenu_page.html', title='昆大干细胞')
@app.route('/tourism-health/massage')
def massage():
return render_template('submenu_page.html', title='邱氏百年中医推拿')
@app.route('/tourism-health/dental')
def dental():
return render_template('submenu_page.html', title='袋鼠齿盟')
# 平台运营管理
@app.route('/platform/changqi')
def changqi():
return render_template('submenu_page.html', title='长企网')
@app.route('/platform/badun')
def badun():
return render_template('submenu_page.html', title='八盾资产')
@app.route('/platform/limao')
def limao():
return render_template('submenu_page.html', title='礼猫猫')
@app.route('/platform/yunfang')
def yunfang():
return render_template('submenu_page.html', title='云纺科技园')
@app.route('/platform/cell-park')
def cell_park():
return render_template('submenu_page.html', title='昆明细胞产业园')
@app.route('/platform/digital')
def digital():
return render_template('submenu_page.html', title='云南数字企业平台')
@app.route('/platform/association')
def association():
return render_template('submenu_page.html', title='云南省互联网零售业协会')
# 品牌与投资
@app.route('/brand/jiabeijia')
def jiabeijia():
return render_template('submenu_page.html', title='佳贝佳')
@app.route('/brand/beicheng')
def beicheng():
return render_template('submenu_page.html', title='贝成教育')
@app.route('/brand/xiaohua')
def xiaohua():
return render_template('submenu_page.html', title='云南小花')
@app.route('/brand/guoxiaofu')
def guoxiaofu():
return render_template('submenu_page.html', title='果小福')
@app.route('/brand/xiaxiong')
def xiaxiong():
return render_template('submenu_page.html', title='夏小熊')
if __name__ == '__main__':
with app.app_context():
db.create_all()
if not User.query.filter_by(username='admin').first():
admin = User(username='admin', password='admin123')
db.session.add(admin)
db.session.commit()
app.run(debug=True, host='0.0.0.0', port=5000)