386 lines
11 KiB
Python
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) |