veadk-python 0.2.5__py3-none-any.whl → 0.2.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of veadk-python might be problematic. Click here for more details.
- veadk/agent.py +29 -22
- veadk/agent_builder.py +94 -0
- veadk/auth/__init__.py +13 -0
- veadk/auth/base_auth.py +22 -0
- veadk/auth/veauth/__init__.py +13 -0
- veadk/auth/veauth/apmplus_veauth.py +65 -0
- veadk/auth/veauth/ark_veauth.py +77 -0
- veadk/auth/veauth/base_veauth.py +50 -0
- veadk/auth/veauth/cozeloop_veauth.py +13 -0
- veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
- veadk/auth/veauth/vesearch_veauth.py +62 -0
- veadk/cli/cli.py +2 -0
- veadk/cli/cli_deploy.py +5 -2
- veadk/cli/cli_init.py +25 -6
- veadk/cli/cli_pipeline.py +220 -0
- veadk/cli/cli_prompt.py +4 -4
- veadk/config.py +45 -81
- veadk/configs/__init__.py +13 -0
- veadk/configs/database_configs.py +83 -0
- veadk/configs/model_configs.py +42 -0
- veadk/configs/tool_configs.py +42 -0
- veadk/configs/tracing_configs.py +110 -0
- veadk/consts.py +32 -1
- veadk/database/database_adapter.py +256 -3
- veadk/database/kv/redis_database.py +47 -0
- veadk/database/local_database.py +23 -4
- veadk/database/relational/mysql_database.py +58 -0
- veadk/database/vector/opensearch_vector_database.py +6 -3
- veadk/database/viking/viking_database.py +272 -36
- veadk/integrations/ve_code_pipeline/__init__.py +13 -0
- veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
- veadk/integrations/ve_cozeloop/__init__.py +13 -0
- veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
- veadk/integrations/ve_cr/__init__.py +13 -0
- veadk/integrations/ve_cr/ve_cr.py +220 -0
- veadk/integrations/ve_faas/template/cookiecutter.json +3 -2
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +2 -2
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +1 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +24 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +1 -12
- veadk/integrations/ve_faas/ve_faas.py +352 -35
- veadk/integrations/ve_faas/web_template/cookiecutter.json +17 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +41 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
- veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +6 -3
- veadk/integrations/ve_tls/__init__.py +13 -0
- veadk/integrations/ve_tls/utils.py +117 -0
- veadk/integrations/ve_tls/ve_tls.py +208 -0
- veadk/integrations/ve_tos/ve_tos.py +128 -73
- veadk/knowledgebase/knowledgebase.py +116 -20
- veadk/memory/long_term_memory.py +20 -21
- veadk/memory/short_term_memory_processor.py +9 -4
- veadk/runner.py +213 -223
- veadk/tools/builtin_tools/vesearch.py +2 -2
- veadk/tools/builtin_tools/video_generate.py +27 -20
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +5 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +253 -129
- veadk/tracing/telemetry/attributes/extractors/types.py +15 -4
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +158 -12
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +4 -9
- veadk/tracing/telemetry/exporters/tls_exporter.py +4 -10
- veadk/tracing/telemetry/opentelemetry_tracer.py +11 -5
- veadk/tracing/telemetry/telemetry.py +23 -5
- veadk/utils/logger.py +1 -1
- veadk/utils/misc.py +48 -0
- veadk/utils/volcengine_sign.py +6 -2
- veadk/version.py +1 -1
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/METADATA +2 -1
- veadk_python-0.2.7.dist-info/RECORD +172 -0
- veadk_python-0.2.5.dist-info/RECORD +0 -127
- /veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{{ cookiecutter.app_name|replace('-', '_') }} → {{ cookiecutter.app_name }}}/__init__.py +0 -0
- /veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{{ cookiecutter.app_name|replace('-', '_') }} → {{ cookiecutter.app_name }}}/agent.py +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/WHEEL +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/entry_points.txt +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/licenses/LICENSE +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from flask import Flask, render_template, request, redirect, url_for, flash, session
|
|
16
|
+
from models import db, Post, User
|
|
17
|
+
from werkzeug.security import generate_password_hash, check_password_hash
|
|
18
|
+
import os
|
|
19
|
+
|
|
20
|
+
app = Flask(__name__)
|
|
21
|
+
app.config['SECRET_KEY'] = 'your-secret-key-here'
|
|
22
|
+
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
|
|
23
|
+
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
24
|
+
app.instance_path = os.path.join("/tmp", "flask_instance")
|
|
25
|
+
os.makedirs(app.instance_path, exist_ok=True)
|
|
26
|
+
|
|
27
|
+
db.init_app(app)
|
|
28
|
+
|
|
29
|
+
# 前台首页
|
|
30
|
+
@app.route('/')
|
|
31
|
+
def index():
|
|
32
|
+
page = request.args.get('page', 1, type=int)
|
|
33
|
+
posts = Post.query.order_by(Post.created_at.desc()).paginate(
|
|
34
|
+
page=page, per_page=5, error_out=False)
|
|
35
|
+
return render_template('index.html', posts=posts)
|
|
36
|
+
|
|
37
|
+
# 文章详情页
|
|
38
|
+
@app.route('/post/<int:post_id>')
|
|
39
|
+
def post_detail(post_id):
|
|
40
|
+
post = Post.query.get_or_404(post_id)
|
|
41
|
+
return render_template('post.html', post=post)
|
|
42
|
+
|
|
43
|
+
# 后台登录页
|
|
44
|
+
@app.route('/admin/login', methods=['GET', 'POST'])
|
|
45
|
+
def admin_login():
|
|
46
|
+
if request.method == 'POST':
|
|
47
|
+
username = request.form['username']
|
|
48
|
+
password = request.form['password']
|
|
49
|
+
|
|
50
|
+
user = User.query.filter_by(username=username).first()
|
|
51
|
+
|
|
52
|
+
if user and check_password_hash(user.password, password):
|
|
53
|
+
session['admin_logged_in'] = True
|
|
54
|
+
return redirect(url_for('admin_dashboard'))
|
|
55
|
+
else:
|
|
56
|
+
flash('用户名或密码错误')
|
|
57
|
+
|
|
58
|
+
return render_template('admin/login.html')
|
|
59
|
+
|
|
60
|
+
# 后台登出
|
|
61
|
+
@app.route('/admin/logout')
|
|
62
|
+
def admin_logout():
|
|
63
|
+
session.pop('admin_logged_in', None)
|
|
64
|
+
return redirect(url_for('admin_login'))
|
|
65
|
+
|
|
66
|
+
# 后台管理面板
|
|
67
|
+
@app.route('/admin/dashboard')
|
|
68
|
+
def admin_dashboard():
|
|
69
|
+
if not session.get('admin_logged_in'):
|
|
70
|
+
return redirect(url_for('admin_login'))
|
|
71
|
+
|
|
72
|
+
post_count = Post.query.count()
|
|
73
|
+
return render_template('admin/dashboard.html', post_count=post_count)
|
|
74
|
+
|
|
75
|
+
# 文章管理
|
|
76
|
+
@app.route('/admin/posts')
|
|
77
|
+
def admin_posts():
|
|
78
|
+
if not session.get('admin_logged_in'):
|
|
79
|
+
return redirect(url_for('admin_login'))
|
|
80
|
+
|
|
81
|
+
page = request.args.get('page', 1, type=int)
|
|
82
|
+
posts = Post.query.order_by(Post.created_at.desc()).paginate(
|
|
83
|
+
page=page, per_page=10, error_out=False)
|
|
84
|
+
return render_template('admin/posts.html', posts=posts)
|
|
85
|
+
|
|
86
|
+
# 创建/编辑文章
|
|
87
|
+
@app.route('/admin/post', methods=['GET', 'POST'])
|
|
88
|
+
@app.route('/admin/post/<int:post_id>', methods=['GET', 'POST'])
|
|
89
|
+
def admin_edit_post(post_id=None):
|
|
90
|
+
if not session.get('admin_logged_in'):
|
|
91
|
+
return redirect(url_for('admin_login'))
|
|
92
|
+
|
|
93
|
+
if post_id:
|
|
94
|
+
post = Post.query.get_or_404(post_id)
|
|
95
|
+
else:
|
|
96
|
+
post = Post()
|
|
97
|
+
|
|
98
|
+
if request.method == 'POST':
|
|
99
|
+
post.title = request.form['title']
|
|
100
|
+
post.content = request.form['content']
|
|
101
|
+
|
|
102
|
+
if post_id is None:
|
|
103
|
+
db.session.add(post)
|
|
104
|
+
db.session.commit()
|
|
105
|
+
flash('文章保存成功')
|
|
106
|
+
return redirect(url_for('admin_posts'))
|
|
107
|
+
|
|
108
|
+
return render_template('admin/edit_post.html', post=post)
|
|
109
|
+
|
|
110
|
+
# 删除文章
|
|
111
|
+
@app.route('/admin/post/delete/<int:post_id>', methods=['POST'])
|
|
112
|
+
def admin_delete_post(post_id):
|
|
113
|
+
if not session.get('admin_logged_in'):
|
|
114
|
+
return redirect(url_for('admin_login'))
|
|
115
|
+
|
|
116
|
+
post = Post.query.get_or_404(post_id)
|
|
117
|
+
db.session.delete(post)
|
|
118
|
+
db.session.commit()
|
|
119
|
+
flash('文章删除成功')
|
|
120
|
+
return redirect(url_for('admin_posts'))
|
|
121
|
+
|
|
122
|
+
if __name__ == '__main__':
|
|
123
|
+
app.run(debug=True)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from app import app, db
|
|
16
|
+
from models import User
|
|
17
|
+
from werkzeug.security import generate_password_hash
|
|
18
|
+
from sqlalchemy.exc import OperationalError
|
|
19
|
+
|
|
20
|
+
def init_database():
|
|
21
|
+
with app.app_context():
|
|
22
|
+
try:
|
|
23
|
+
# 创建所有数据库表
|
|
24
|
+
db.metadata.create_all(bind=db.engine, checkfirst=True)
|
|
25
|
+
print("数据库表创建成功")
|
|
26
|
+
except OperationalError as e:
|
|
27
|
+
if "table already exists" in str(e).lower():
|
|
28
|
+
print("数据库表已存在,跳过创建")
|
|
29
|
+
else:
|
|
30
|
+
print(f"创建数据库表时出错: {e}")
|
|
31
|
+
raise
|
|
32
|
+
|
|
33
|
+
# 创建默认管理员账户(如不存在)
|
|
34
|
+
if not User.query.filter_by(username='admin').first():
|
|
35
|
+
admin = User(
|
|
36
|
+
username='admin',
|
|
37
|
+
password=generate_password_hash('admin123')
|
|
38
|
+
)
|
|
39
|
+
db.session.add(admin)
|
|
40
|
+
db.session.commit()
|
|
41
|
+
print("默认管理员账户创建成功")
|
|
42
|
+
else:
|
|
43
|
+
print("默认管理员账户已存在,跳过创建")
|
|
44
|
+
|
|
45
|
+
if __name__ == '__main__':
|
|
46
|
+
init_database()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from flask_sqlalchemy import SQLAlchemy
|
|
16
|
+
from datetime import datetime
|
|
17
|
+
|
|
18
|
+
db = SQLAlchemy()
|
|
19
|
+
|
|
20
|
+
class Post(db.Model):
|
|
21
|
+
id = db.Column(db.Integer, primary_key=True)
|
|
22
|
+
title = db.Column(db.String(200), nullable=False)
|
|
23
|
+
content = db.Column(db.Text, nullable=False)
|
|
24
|
+
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
25
|
+
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
26
|
+
|
|
27
|
+
def __repr__(self):
|
|
28
|
+
return f'<Post {self.title}>'
|
|
29
|
+
|
|
30
|
+
class User(db.Model):
|
|
31
|
+
id = db.Column(db.Integer, primary_key=True)
|
|
32
|
+
username = db.Column(db.String(80), unique=True, nullable=False)
|
|
33
|
+
password = db.Column(db.String(200), nullable=False)
|
|
34
|
+
|
|
35
|
+
def __repr__(self):
|
|
36
|
+
return f'<User {self.username}>'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 兼容源码部署到faas & 镜像部署到faas
|
|
4
|
+
pip install -r requirements.txt
|
|
5
|
+
|
|
6
|
+
HOST="0.0.0.0"
|
|
7
|
+
PORT="${_FAAS_RUNTIME_PORT:-8000}"
|
|
8
|
+
|
|
9
|
+
export SERVER_HOST=$HOST
|
|
10
|
+
export SERVER_PORT=$PORT
|
|
11
|
+
|
|
12
|
+
# 设置环境变量
|
|
13
|
+
export FLASK_APP=app.py
|
|
14
|
+
export FLASK_ENV=production
|
|
15
|
+
|
|
16
|
+
# 初始化数据库
|
|
17
|
+
python init_db.py
|
|
18
|
+
|
|
19
|
+
echo "Starting Web application..."
|
|
20
|
+
# 启动应用,使用生产服务器配置
|
|
21
|
+
exec python -m gunicorn -w 4 -b $SERVER_HOST:$SERVER_PORT app:app
|
veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/* 基础样式 */
|
|
2
|
+
* {
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 0;
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
10
|
+
line-height: 1.6;
|
|
11
|
+
color: #333;
|
|
12
|
+
background-color: #f8f9fa;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.container {
|
|
16
|
+
max-width: 1200px;
|
|
17
|
+
margin: 0 auto;
|
|
18
|
+
padding: 0 20px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* 头部 */
|
|
22
|
+
header {
|
|
23
|
+
background-color: #fff;
|
|
24
|
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
|
25
|
+
padding: 1rem 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
header h1 a {
|
|
29
|
+
text-decoration: none;
|
|
30
|
+
color: #2c3e50;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
header nav {
|
|
34
|
+
float: right;
|
|
35
|
+
margin-top: 10px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
header nav a {
|
|
39
|
+
margin-left: 20px;
|
|
40
|
+
text-decoration: none;
|
|
41
|
+
color: #3498db;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
header nav a:hover {
|
|
45
|
+
text-decoration: underline;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* 主体内容 */
|
|
49
|
+
main {
|
|
50
|
+
padding: 2rem 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* 消息提示 */
|
|
54
|
+
.flash-messages {
|
|
55
|
+
margin-bottom: 20px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.flash-message {
|
|
59
|
+
padding: 10px;
|
|
60
|
+
background-color: #d4edda;
|
|
61
|
+
border: 1px solid #c3e6cb;
|
|
62
|
+
border-radius: 4px;
|
|
63
|
+
color: #155724;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* 文章列表 */
|
|
67
|
+
.post-preview {
|
|
68
|
+
background: white;
|
|
69
|
+
margin-bottom: 20px;
|
|
70
|
+
padding: 20px;
|
|
71
|
+
border-radius: 5px;
|
|
72
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.post-preview h2 a {
|
|
76
|
+
text-decoration: none;
|
|
77
|
+
color: #2c3e50;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.post-preview h2 a:hover {
|
|
81
|
+
color: #3498db;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.post-meta {
|
|
85
|
+
color: #7f8c8d;
|
|
86
|
+
font-size: 0.9em;
|
|
87
|
+
margin: 10px 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.read-more {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
margin-top: 10px;
|
|
93
|
+
color: #3498db;
|
|
94
|
+
text-decoration: none;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.read-more:hover {
|
|
98
|
+
text-decoration: underline;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* 文章详情 */
|
|
102
|
+
.post-detail {
|
|
103
|
+
background: white;
|
|
104
|
+
padding: 30px;
|
|
105
|
+
border-radius: 5px;
|
|
106
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.post-detail h1 {
|
|
110
|
+
margin-bottom: 10px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.post-content {
|
|
114
|
+
margin: 20px 0;
|
|
115
|
+
white-space: pre-wrap;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.back-link {
|
|
119
|
+
display: inline-block;
|
|
120
|
+
margin-top: 20px;
|
|
121
|
+
color: #3498db;
|
|
122
|
+
text-decoration: none;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* 分页 */
|
|
126
|
+
.pagination {
|
|
127
|
+
text-align: center;
|
|
128
|
+
margin: 30px 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.pagination a {
|
|
132
|
+
display: inline-block;
|
|
133
|
+
padding: 8px 16px;
|
|
134
|
+
margin: 0 5px;
|
|
135
|
+
text-decoration: none;
|
|
136
|
+
background-color: #3498db;
|
|
137
|
+
color: white;
|
|
138
|
+
border-radius: 4px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.pagination a:hover {
|
|
142
|
+
background-color: #2980b9;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.pagination span {
|
|
146
|
+
display: inline-block;
|
|
147
|
+
padding: 8px 16px;
|
|
148
|
+
margin: 0 5px;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* 登录表单 */
|
|
152
|
+
.login-form {
|
|
153
|
+
max-width: 400px;
|
|
154
|
+
margin: 50px auto;
|
|
155
|
+
background: white;
|
|
156
|
+
padding: 30px;
|
|
157
|
+
border-radius: 5px;
|
|
158
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.login-form h2 {
|
|
162
|
+
text-align: center;
|
|
163
|
+
margin-bottom: 20px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.form-group {
|
|
167
|
+
margin-bottom: 20px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.form-group label {
|
|
171
|
+
display: block;
|
|
172
|
+
margin-bottom: 5px;
|
|
173
|
+
font-weight: bold;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.form-group input {
|
|
177
|
+
width: 100%;
|
|
178
|
+
padding: 10px;
|
|
179
|
+
border: 1px solid #ddd;
|
|
180
|
+
border-radius: 4px;
|
|
181
|
+
font-size: 16px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.form-group input:focus {
|
|
185
|
+
border-color: #3498db;
|
|
186
|
+
outline: none;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
button, .btn {
|
|
190
|
+
display: inline-block;
|
|
191
|
+
padding: 10px 20px;
|
|
192
|
+
background-color: #3498db;
|
|
193
|
+
color: white;
|
|
194
|
+
text-decoration: none;
|
|
195
|
+
border: none;
|
|
196
|
+
border-radius: 4px;
|
|
197
|
+
cursor: pointer;
|
|
198
|
+
font-size: 16px;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
button:hover, .btn:hover {
|
|
202
|
+
background-color: #2980b9;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.hint {
|
|
206
|
+
margin-top: 20px;
|
|
207
|
+
text-align: center;
|
|
208
|
+
color: #7f8c8d;
|
|
209
|
+
font-size: 0.9em;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* 管理面板 */
|
|
213
|
+
.admin-dashboard {
|
|
214
|
+
background: white;
|
|
215
|
+
padding: 30px;
|
|
216
|
+
border-radius: 5px;
|
|
217
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.stats {
|
|
221
|
+
display: flex;
|
|
222
|
+
margin: 30px 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.stat-card {
|
|
226
|
+
flex: 1;
|
|
227
|
+
text-align: center;
|
|
228
|
+
padding: 20px;
|
|
229
|
+
background-color: #f1f8ff;
|
|
230
|
+
border-radius: 5px;
|
|
231
|
+
margin: 0 10px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.stat-number {
|
|
235
|
+
font-size: 2em;
|
|
236
|
+
font-weight: bold;
|
|
237
|
+
color: #3498db;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.admin-links {
|
|
241
|
+
text-align: center;
|
|
242
|
+
margin-top: 30px;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.admin-links .btn {
|
|
246
|
+
margin: 0 10px;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* 文章管理 */
|
|
250
|
+
.admin-posts {
|
|
251
|
+
background: white;
|
|
252
|
+
padding: 30px;
|
|
253
|
+
border-radius: 5px;
|
|
254
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.admin-header {
|
|
258
|
+
display: flex;
|
|
259
|
+
justify-content: space-between;
|
|
260
|
+
align-items: center;
|
|
261
|
+
margin-bottom: 20px;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.posts-table {
|
|
265
|
+
width: 100%;
|
|
266
|
+
border-collapse: collapse;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.posts-table th,
|
|
270
|
+
.posts-table td {
|
|
271
|
+
padding: 12px;
|
|
272
|
+
text-align: left;
|
|
273
|
+
border-bottom: 1px solid #ddd;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.posts-table th {
|
|
277
|
+
background-color: #f8f9fa;
|
|
278
|
+
font-weight: bold;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.posts-table td a {
|
|
282
|
+
color: #3498db;
|
|
283
|
+
text-decoration: none;
|
|
284
|
+
margin-right: 10px;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.posts-table td a:hover {
|
|
288
|
+
text-decoration: underline;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.delete-btn {
|
|
292
|
+
background: none;
|
|
293
|
+
border: none;
|
|
294
|
+
color: #e74c3c;
|
|
295
|
+
cursor: pointer;
|
|
296
|
+
padding: 0;
|
|
297
|
+
font-size: 1em;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.delete-btn:hover {
|
|
301
|
+
text-decoration: underline;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/* 编辑文章 */
|
|
305
|
+
.edit-post {
|
|
306
|
+
background: white;
|
|
307
|
+
padding: 30px;
|
|
308
|
+
border-radius: 5px;
|
|
309
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.edit-post textarea {
|
|
313
|
+
width: 100%;
|
|
314
|
+
padding: 10px;
|
|
315
|
+
border: 1px solid #ddd;
|
|
316
|
+
border-radius: 4px;
|
|
317
|
+
font-family: inherit;
|
|
318
|
+
font-size: 16px;
|
|
319
|
+
resize: vertical;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.form-actions {
|
|
323
|
+
margin-top: 20px;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.btn-cancel {
|
|
327
|
+
background-color: #95a5a6;
|
|
328
|
+
margin-left: 10px;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.btn-cancel:hover {
|
|
332
|
+
background-color: #7f8c8d;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* 页脚 */
|
|
336
|
+
footer {
|
|
337
|
+
background-color: #2c3e50;
|
|
338
|
+
color: white;
|
|
339
|
+
text-align: center;
|
|
340
|
+
padding: 20px 0;
|
|
341
|
+
margin-top: 40px;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* 响应式设计 */
|
|
345
|
+
@media (max-width: 768px) {
|
|
346
|
+
header nav {
|
|
347
|
+
float: none;
|
|
348
|
+
text-align: center;
|
|
349
|
+
margin-top: 10px;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.admin-header {
|
|
353
|
+
flex-direction: column;
|
|
354
|
+
align-items: flex-start;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.admin-header .btn {
|
|
358
|
+
margin-top: 10px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.stats {
|
|
362
|
+
flex-direction: column;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.stat-card {
|
|
366
|
+
margin: 10px 0;
|
|
367
|
+
}
|
|
368
|
+
}
|
veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}管理面板{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="admin-dashboard">
|
|
7
|
+
<h2>管理面板</h2>
|
|
8
|
+
|
|
9
|
+
<div class="stats">
|
|
10
|
+
<div class="stat-card">
|
|
11
|
+
<h3>文章总数</h3>
|
|
12
|
+
<p class="stat-number">{{ post_count }}</p>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="admin-links">
|
|
17
|
+
<a href="{{ url_for('admin_posts') }}" class="btn">文章管理</a>
|
|
18
|
+
<a href="{{ url_for('admin_edit_post') }}" class="btn">新建文章</a>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
{% endblock %}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{% if post.id %}编辑文章{% else %}新建文章{% endif %}{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="edit-post">
|
|
7
|
+
<h2>{% if post.id %}编辑文章{% else %}新建文章{% endif %}</h2>
|
|
8
|
+
|
|
9
|
+
<form method="POST">
|
|
10
|
+
<div class="form-group">
|
|
11
|
+
<label for="title">标题:</label>
|
|
12
|
+
<input type="text" id="title" name="title" value="{{ post.title or '' }}" required>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="form-group">
|
|
15
|
+
<label for="content">内容:</label>
|
|
16
|
+
<textarea id="content" name="content" rows="15" required>{{ post.content or '' }}</textarea>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="form-actions">
|
|
19
|
+
<button type="submit">保存</button>
|
|
20
|
+
<a href="{{ url_for('admin_posts') }}" class="btn-cancel">取消</a>
|
|
21
|
+
</div>
|
|
22
|
+
</form>
|
|
23
|
+
</div>
|
|
24
|
+
{% endblock %}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}管理员登录{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="login-form">
|
|
7
|
+
<h2>管理员登录</h2>
|
|
8
|
+
<form method="POST">
|
|
9
|
+
<div class="form-group">
|
|
10
|
+
<label for="username">用户名:</label>
|
|
11
|
+
<input type="text" id="username" name="username" required>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="form-group">
|
|
14
|
+
<label for="password">密码:</label>
|
|
15
|
+
<input type="password" id="password" name="password" required>
|
|
16
|
+
</div>
|
|
17
|
+
<button type="submit">登录</button>
|
|
18
|
+
</form>
|
|
19
|
+
<p class="hint">默认账号: admin / 密码: admin123</p>
|
|
20
|
+
</div>
|
|
21
|
+
{% endblock %}
|