<Project-23 Navigator Portal> Python flask web 网站导航应用 可编辑界面:添加图片、URL、描述、位置移动

目的:

浏览器的地址簿太厚,如下图:

开始,想给每个 Web 应用加 icon 来提高辨识度,发现很麻烦:create image, resize, 还要挑来挑去,重复性地添加代码。再看着这些密密麻麻的含有重复与有规则的字符,真刺眼!

做这个 Portal Web 应用来进行网站应用导航,docker 部署后,占用端口:9999,可以在app.py修改。

 <代码有 Claudi AI 参与>

Navigator Portal 应用

1. 界面展示

2. 目录结构

navigator_portal        #项目名称
│
├── app.py                 # Flask 应用主文件
├── requirements.txt       # Python 依赖包列表
├── Dockerfile             # docker部署文件
├── static/               
│   ├── css/
│   │   └── style.css    
│   ├── js/
│   │   └── main.js      
│   ├── uploads/         # 上传的图片存储目录
│   └── favicon.jpg      # 网站图标
├── templates/          # HTML files 目录
│   ├── base.html       
│   ├── index.html      
│   └── edit.html       # 编辑页面
└── data/               # 存储目录└── nav_links.json  # 导航链接数据文件

3. 完整代码

a. app.py

# app.py
from flask import Flask, render_template, request, jsonify, url_for
import json
from pathlib import Path
import os
from werkzeug.utils import secure_filenameapp = Flask(__name__)
app.secret_key = 'your_secret_key_here'# 配置文件上传
UPLOAD_FOLDER = Path('static/uploads')
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER# 确保上传目录存在
UPLOAD_FOLDER.mkdir(parents=True, exist_ok=True)# 数据文件路径
DATA_FILE = Path('data/nav_links.json')def allowed_file(filename):return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONSdef init_data_file():if not DATA_FILE.exists():default_links = [{"name": "主应用", "url": "http://davens:5000", "port": "5000", "image": "/static/images/default.png", "order": 0},] + [{"name": f"应用 {port}", "url": f"http://davens:{port}", "port": str(port),"image": "/static/images/default.png","order": i + 1}for i, port in enumerate(list(range(9001, 9012)) + [9999])]DATA_FILE.parent.mkdir(parents=True, exist_ok=True)with open(DATA_FILE, 'w', encoding='utf-8') as f:json.dump(default_links, f, indent=2, ensure_ascii=False)def load_links():try:if not DATA_FILE.exists():init_data_file()with open(DATA_FILE, 'r', encoding='utf-8') as f:links = json.load(f)return sorted(links, key=lambda x: x.get('order', 0))except Exception as e:print(f"Error loading links: {e}")return []def save_links(links):try:# 确保 data 目录存在DATA_FILE.parent.mkdir(parents=True, exist_ok=True)with open(DATA_FILE, 'w', encoding='utf-8') as f:json.dump(links, f, indent=2, ensure_ascii=False)return Trueexcept Exception as e:print(f"Error saving links: {e}")return Falsedef clean_url(url):"""清理 URL,移除域名部分只保留路径"""if url and url.startswith(('http://', 'https://')):return urlelif url and '/static/' in url:return url.split('/static/')[-1]return url@app.route('/')
def index():links = load_links()return render_template('index.html', links=links)@app.route('/edit')
def edit():links = load_links()return render_template('edit.html', links=links)@app.route('/api/upload', methods=['POST'])
def upload_file():if 'file' not in request.files:return jsonify({'error': 'No file part'}), 400file = request.files['file']if file.filename == '':return jsonify({'error': 'No selected file'}), 400if file and allowed_file(file.filename):filename = secure_filename(file.filename)filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)file.save(filepath)return jsonify({'url': f'/static/uploads/{filename}'})return jsonify({'error': 'Invalid file type'}), 400@app.route('/api/links', methods=['GET', 'POST', 'PUT', 'DELETE'])
def manage_links():try:if request.method == 'GET':return jsonify(load_links())elif request.method == 'POST':data = request.get_json()if not data:return jsonify({'status': 'error', 'message': 'No data provided'}), 400links = load_links()image_url = data.get('image', '/static/images/default.png')new_link = {'name': data.get('name', ''),'url': data.get('url', ''),'port': data.get('port', ''),'image': clean_url(image_url),'order': len(links)}links.append(new_link)if save_links(links):return jsonify({'status': 'success'})return jsonify({'status': 'error', 'message': 'Failed to save links'}), 500elif request.method == 'PUT':data = request.get_json()if not data:return jsonify({'status': 'error', 'message': 'No data provided'}), 400links = load_links()print("Received PUT data:", data)  # 调试日志if 'reorder' in data:new_order = data.get('new_order', [])if not new_order:return jsonify({'status': 'error', 'message': 'Invalid order data'}), 400reordered_links = [links[i] for i in new_order]if save_links(reordered_links):return jsonify({'status': 'success'})else:try:index = int(data.get('index', -1))if index < 0 or index >= len(links):return jsonify({'status': 'error', 'message': f'Invalid index: {index}'}), 400image_url = data.get('image', links[index].get('image', '/static/images/default.png'))links[index].update({'name': data.get('name', links[index]['name']),'url': data.get('url', links[index]['url']),'port': data.get('port', links[index]['port']),'image': clean_url(image_url)})print("Updated link:", links[index])  # 调试日志if save_links(links):return jsonify({'status': 'success'})except ValueError as e:return jsonify({'status': 'error', 'message': f'Invalid data: {str(e)}'}), 400return jsonify({'status': 'error', 'message': 'Failed to update links'}), 500elif request.method == 'DELETE':try:index = int(request.args.get('index', -1))except ValueError:return jsonify({'status': 'error', 'message': 'Invalid index'}), 400if index < 0:return jsonify({'status': 'error', 'message': 'Invalid index'}), 400links = load_links()if 0 <= index < len(links):del links[index]if save_links(links):return jsonify({'status': 'success'})return jsonify({'status': 'error', 'message': 'Failed to delete link'}), 500except Exception as e:print(f"Error in manage_links: {e}")  # 调试日志import tracebacktraceback.print_exc()  # 打印完整的错误堆栈return jsonify({'status': 'error', 'message': str(e)}), 500if __name__ == '__main__':init_data_file()app.run(host='0.0.0.0', port=9999, debug=True)

b. templates 目录下文件

i. index.html
{% extends "base.html" %}
{% block title %}Web应用导航{% endblock %}
{% block content %}
<div class="header"><h1>Web应用导航</h1><a href="/edit" class="edit-btn">编辑导航</a>
</div><div class="grid" id="nav-grid">{% for link in links %}<!-- 将整个卡片变成链接 --><a href="{{ link.url }}" class="card" data-index="{{ loop.index0 }}"><div class="card-content"><div class="card-image-container"><img src="{{ link.image }}" alt="{{ link.name }}"></div><div class="card-title">{{ link.name }}</div><div class="port">端口: {{ link.port }}</div></div></a>{% endfor %}
</div>
{% endblock %}{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {// 处理所有卡片的点击事件document.querySelectorAll('.card').forEach(card => {card.addEventListener('click', function(e) {e.preventDefault(); // 阻止默认链接行为const url = this.getAttribute('href');if (url) {// 在同一个标签页中打开链接window.location.href = url;}});});
});
</script>
{% endblock %}
ii. base.html
{% extends "base.html" %}
{% block title %}Web应用导航{% endblock %}
{% block content %}
<div class="header"><h1>Web应用导航</h1><a href="/edit" class="edit-btn">编辑导航</a>
</div><div class="grid" id="nav-grid">{% for link in links %}<!-- 将整个卡片变成链接 --><a href="{{ link.url }}" class="card" data-index="{{ loop.index0 }}"><div class="card-content"><div class="card-image-container"><img src="{{ link.image }}" alt="{{ link.name }}"></div><div class="card-title">{{ link.name }}</div><div class="port">端口: {{ link.port }}</div></div></a>{% endfor %}
</div>
{% endblock %}{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {// 处理所有卡片的点击事件document.querySelectorAll('.card').forEach(card => {card.addEventListener('click', function(e) {e.preventDefault(); // 阻止默认链接行为const url = this.getAttribute('href');if (url) {// 在同一个标签页中打开链接window.location.href = url;}});});
});
</script>
{% endblock %}
iii. edit.html
# templates/edit.html
{% extends "base.html" %}
{% block title %}编辑导航{% endblock %}{% block content %}
<div class="edit-container"><div class="header"><h1>编辑导航</h1><a href="/" class="edit-btn">返回首页</a></div><div id="links-list">{% for link in links %}<div class="link-item" data-index="{{ loop.index0 }}"><i class="fas fa-grip-vertical drag-handle"></i><div class="link-image-container"><img src="{{ link.image }}" class="link-image" alt="{{ link.name }}"></div><div class="link-info"><input type="text" value="{{ link.name }}" placeholder="名称" class="name-input"><input type="text" value="{{ link.url }}" placeholder="URL" class="url-input"><input type="text" value="{{ link.port }}" placeholder="端口" class="port-input"><input type="file" class="image-input" accept="image/*" style="display: none;"><button class="btn" onclick="this.previousElementSibling.click()">更换图片</button></div><div class="link-actions"><button class="btn btn-primary" onclick="saveLink({{ loop.index0 }})">保存</button><button class="btn btn-danger" onclick="deleteLink({{ loop.index0 }})">删除</button></div></div>{% endfor %}</div><div class="form-container" style="margin-top: 20px;"><h2>添加新链接</h2><div class="form-group"><label>名称</label><input type="text" id="new-name"></div><div class="form-group"><label>URL</label><input type="text" id="new-url"></div><div class="form-group"><label>端口</label><input type="text" id="new-port"></div><div class="form-group"><label>图片</label><input type="file" id="new-image" accept="image/*"></div><button class="btn btn-primary" onclick="addNewLink()">添加</button></div>
</div>
{% endblock %}{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {// 初始化拖拽排序const linksList = document.getElementById('links-list');if (linksList) {new Sortable(linksList, {handle: '.drag-handle',animation: 150,onEnd: function() {const items = document.querySelectorAll('.link-item');const newOrder = Array.from(items).map(item => parseInt(item.dataset.index));fetch('/api/links', {method: 'PUT',headers: {'Content-Type': 'application/json',},body: JSON.stringify({reorder: true,new_order: newOrder})});}});}// 处理图片上传document.querySelectorAll('.image-input').forEach(input => {input.addEventListener('change', async function(e) {const file = e.target.files[0];if (!file) return;const formData = new FormData();formData.append('file', file);try {const response = await fetch('/api/upload', {method: 'POST',body: formData});const data = await response.json();if (data.url) {const linkItem = this.closest('.link-item');if (linkItem) {linkItem.querySelector('.link-image').src = data.url;}}} catch (error) {console.error('Error uploading image:', error);alert('图片上传失败,请重试!');}});});
});
</script>
{% endblock %}

c. static 目录下文件

i. ./css/style.css
/* static/css/style.css */
body {font-family: Arial, sans-serif;margin: 0;padding: 20px;background-color: #f5f5f5;
}.header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 20px;padding: 0 20px;
}.edit-btn {padding: 8px 16px;background-color: #007bff;color: white;text-decoration: none;border-radius: 4px;
}/* 导航卡片网格 */
.grid {display: grid;grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));gap: 20px;padding: 20px;
}/* 卡片样式 */
.card {background: white;border-radius: 8px;padding: 15px;box-shadow: 0 2px 4px rgba(0,0,0,0.1);transition: transform 0.2s;display: flex;flex-direction: column;text-decoration: none;  /* 移除链接的默认下划线 */color: inherit;        /* 继承颜色 */
}.card:hover {transform: translateY(-5px);
}.card-content {flex: 1;display: flex;flex-direction: column;pointer-events: none;  /* 防止内部元素影响点击 */
}.card-image-container {width: 100%;height: 200px;display: flex;align-items: center;justify-content: center;overflow: hidden;margin-bottom: 10px;border-radius: 4px;background-color: #f8f9fa;
}.card img {max-width: 100%;max-height: 100%;width: auto;height: auto;object-fit: contain;
}.card-title {color: #333;font-weight: bold;margin-top: 10px;font-size: 1.1em;
}.port {color: #666;font-size: 0.9em;margin-top: 5px;
}/* 编辑页面样式 */
.edit-container {max-width: 800px;margin: 0 auto;
}.form-container {max-width: 800px;margin: 0 auto;
}.form-group {margin-bottom: 15px;
}.form-group label {display: block;margin-bottom: 5px;
}.form-group input {width: 100%;padding: 8px;border: 1px solid #ddd;border-radius: 4px;
}.link-item {display: flex;align-items: center;background: white;padding: 15px;margin-bottom: 10px;border-radius: 4px;box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}/* 编辑页面的图片容器 */
.link-image-container {width: 100px;height: 100px;display: flex;align-items: center;justify-content: center;margin-right: 15px;border-radius: 4px;background-color: #f8f9fa;overflow: hidden;
}/* 编辑页面的图片 */
.link-image {max-width: 100%;max-height: 100%;width: auto;height: auto;object-fit: contain;
}.link-info {flex-grow: 1;margin-right: 15px;
}.link-info input {margin-bottom: 8px;width: 100%;
}.link-actions {display: flex;gap: 10px;
}.btn {padding: 8px 16px;border: none;border-radius: 4px;cursor: pointer;transition: background-color 0.2s;
}.btn:hover {opacity: 0.9;
}.btn-primary {background-color: #007bff;color: white;
}.btn-primary:hover {background-color: #0056b3;
}.btn-danger {background-color: #dc3545;color: white;
}.btn-danger:hover {background-color: #c82333;
}.drag-handle {cursor: move;color: #666;margin-right: 10px;padding: 10px;
}/* 响应式调整 */
@media (max-width: 768px) {.grid {grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));}.link-item {flex-direction: column;align-items: flex-start;}.link-image-container {width: 100%;margin-bottom: 10px;margin-right: 0;}.link-actions {width: 100%;justify-content: flex-end;margin-top: 10px;}
}
ii. ./js/main.js
// static/js/main.js
document.addEventListener('DOMContentLoaded', function() {// 初始化拖拽排序const linksList = document.getElementById('links-list');if (linksList) {new Sortable(linksList, {handle: '.drag-handle',animation: 150,onEnd: function() {// 获取新的排序const items = document.querySelectorAll('.link-item');const newOrder = Array.from(items).map(item => parseInt(item.dataset.index));// 发送到服务器fetch('/api/links', {method: 'PUT',headers: {'Content-Type': 'application/json',},body: JSON.stringify({reorder: true,new_order: newOrder})});}});}// 处理图片上传document.querySelectorAll('.image-input').forEach(input => {input.addEventListener('change', handleImageUpload);});// 绑定新增链接的图片上传const newImageInput = document.getElementById('new-image');if (newImageInput) {newImageInput.addEventListener('change', handleImageUpload);}
});// 处理图片上传的函数
async function handleImageUpload(event) {const file = event.target.files[0];if (!file) return;if (!['image/jpeg', 'image/png', 'image/gif'].includes(file.type)) {alert('请上传 JPG、PNG 或 GIF 格式的图片!');return;}const formData = new FormData();formData.append('file', file);try {const response = await fetch('/api/upload', {method: 'POST',body: formData});if (!response.ok) {throw new Error('上传失败');}const data = await response.json();if (data.url) {const linkItem = this.closest('.link-item');if (linkItem) {linkItem.querySelector('.link-image').src = data.url;}} else {throw new Error(data.error || '上传失败');}} catch (error) {console.error('Error uploading image:', error);alert('图片上传失败:' + error.message);}
}// 保存链接
window.saveLink = async function(index) {const linkItem = document.querySelector(`.link-item[data-index="${index}"]`);const name = linkItem.querySelector('.name-input').value.trim();const url = linkItem.querySelector('.url-input').value.trim();const port = linkItem.querySelector('.port-input').value.trim();const image = linkItem.querySelector('.link-image').src;// 验证数据if (!name || !url || !port) {alert('请填写所有必需的字段!');return;}try {const response = await fetch('/api/links', {method: 'PUT',headers: {'Content-Type': 'application/json',},body: JSON.stringify({index: index,name: name,url: url,port: port,image: image})});const result = await response.json();if (response.ok && result.status === 'success') {alert('保存成功!');} else {throw new Error(result.message || '保存失败');}} catch (error) {console.error('Error saving link:', error);alert('保存失败,请重试!错误信息:' + error.message);}
};// 删除链接
window.deleteLink = async function(index) {if (!confirm('确定要删除这个链接吗?')) {return;}try {const response = await fetch(`/api/links?index=${index}`, {method: 'DELETE'});if (response.ok) {location.reload();} else {throw new Error('删除失败');}} catch (error) {console.error('Error deleting link:', error);alert('删除失败,请重试!');}
};// 添加新链接
window.addNewLink = async function() {const name = document.getElementById('new-name').value;const url = document.getElementById('new-url').value;const port = document.getElementById('new-port').value;const imageFile = document.getElementById('new-image').files[0];let image = '/static/images/default.png';try {if (imageFile) {const formData = new FormData();formData.append('file', imageFile);const response = await fetch('/api/upload', {method: 'POST',body: formData});const data = await response.json();if (data.url) {image = data.url;}}const response = await fetch('/api/links', {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify({name,url,port,image})});if (response.ok) {location.reload();} else {throw new Error('添加失败');}} catch (error) {console.error('Error adding new link:', error);alert('添加失败,请重试!');}
};
iii. favicon.jpg

d. ./uploading/ 图片文件

图片会被 网站 打上水印,就不传。

推荐从 Midjourney.com 寻找与下载, AI created 图片是没有版权的,即:随便用。

4. 部署到 QNAP NAS Docker/Container上

a. Docker 部署文件

i. Dockerfile
# Dockerfile
FROM python:3.9-slim# 工作目录
WORKDIR /app# 环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \PYTHONUNBUFFERED=1 \FLASK_APP=app.py \FLASK_ENV=production# 系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \gcc \&& rm -rf /var/lib/apt/lists/*# 复制文件
COPY requirements.txt .
COPY app.py .
COPY static static/
COPY templates templates/
COPY data data/# 创建上传目录
RUN mkdir -p static/uploads && \chmod -R 777 static/uploads data# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt# 端口
EXPOSE 9999# 启动命令
CMD ["python", "app.py"]
ii. requirements.txt min
flask
Werkzeug

b. 执行 docker 部署命令

i.CMD: docker build -t navigator_portal .
[/share/Multimedia/2024-MyProgramFiles/23.Navigator_Portal] # docker build -t navigator_portal .
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.Install the buildx component to build images with BuildKit:https://docs.docker.com/go/buildx/Sending build context to Docker daemon  56.25MB
Step 1/13 : FROM python:3.9-slim---> 6a22698eab0e
Step 2/13 : WORKDIR /app
...
...---> d39c4c26f2c1
Successfully built d39c4c26f2c1
Successfully tagged navigator_portal:latest
[/share/Multimedia/2024-MyProgramFiles/23.Navigator_Portal] # 
ii. CMD:  docker run...
[/share/Multimedia/2024-MyProgramFiles/23.Navigator_Portal] # docker run -d -p 9999:9999 --name navigator_portal_container --restart always navigator_portal
31859f34dfc072740b38a4ebcdb9e9b6789acf95286b1e515126f2927c8467d5
[/share/Multimedia/2024-MyProgramFiles/23.Navigator_Portal] # 

5. 界面功能介绍

a. 页面总览

注:第一次使用这 app 代码,会因为缺失图片文件,而可能显示如下:撕裂的文件

b. 功能:

  • 鼠标移到图标,会向上移动,提醒被选中。
  • 点击右上角,蓝色 “编辑导航” 按钮,可能对图标内容修改

c. 编辑页面

d. 功能:

  • 图标排序:按住图标左侧的“6个点” 可以上下拖动 松手后即保存 (“编辑界面” 图1)
  • 图标体:可以删除、添加  (“编辑界面” 图3)
  • 图标内容可修改:描述, URL, 端口、图片更换  (“编辑界面” 图1 图2)
  • 对多条图标内容修改后,需要对每个图标都要点击 “保存”

已知问题:

  1. 图片不是 resize 保存,最好别使用太大的文件,尤其是在非 LAN 访问
  2. 图片的 URL 内容结尾不要有 "/" , 在移动图标顺序时会不成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/15548.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

文心一言 VS 讯飞星火 VS chatgpt (391)-- 算法导论25.1 5题

五、说明如何将单源最短路径问题表示为矩阵和向量的乘积&#xff0c;并解释该乘积的计算过程如何对应 Bellman-Ford 算法&#xff1f;(请参阅24.1节。)。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 在解决单源最短路径问题时&#xff0c;我们可以将问题表示…

如何使用cx_Freeze打包编译python文件

1. 安装 cx_Freeze 首先&#xff0c;确保你已经安装了 cx_Freeze。你可以通过 pip 安装它&#xff1a; pip install cx_Freeze2.创建setup.py from cx_Freeze import setup, Executable import os# 确定包的文件和依赖 build_exe_options {"packages": ["os…

深度学习之其他常见的生成式模型

1.1 什么是自回归模型&#xff1a;pixelRNN与pixelCNN&#xff1f; ​ 自回归模型通过对图像数据的概率分布 p d a t a ( x ) p_{data}(x) pdata​(x)进行显式建模&#xff0c;并利用极大似然估计优化模型。具体如下&#xff1a; p d a t a ( x ) ∏ i 1 n p ( x i ∣ x 1 …

短期电力负荷(论文复现)

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

DBeaver如何设置自动刷新数据库表的数据,彻底解放双手!

前言 大家好&#xff0c;我是小徐啊。 DBeaver是一款常用的数据库连接工具&#xff0c;它的优点是免费使用&#xff0c;而且支持的数据库类型超级多&#xff0c;甚至可以直接安装数据库对应的驱动jar包来连接数据库。 比如达梦数据库&#xff0c;之前版本是可以通过jar包方式…

黄仁勋:AI革命将创百万亿美元价值!近屿智能带你入局AIGC

11月13日&#xff0c;NVIDIA在日本成功举办了2024年AI峰会。一场关于人工智能驱动的新工业革命的讨论热烈展开。英伟达创始人兼CEO黄仁勋与软银主席兼CEO孙正义共同探讨了当前技术革命的独特之处及其深远影响。 黄仁勋在会上表示&#xff0c;AI革命将创造的价值不是以万亿美元计…

知网翻译助手及其10款翻译工具使用体验大PK!!!

在这个信息爆炸的时代&#xff0c;翻译工具成了我们日常工作中不可或缺的得力助手。作为一个经常需要处理多语言文件的人&#xff0c;翻译工具对我来说简直是救命稻草。除了知网助手外&#xff0c;我还用过不少翻译软件&#xff0c;现在&#xff0c;我就来说说知网翻译助手和其…

Entity Framework的简单使用案例

需要引入的框架&#xff1a; 实体类&#xff1a; [Table("Users")] internal class User {[Key]public int Id { get; set; }[Required][StringLength(100)][Index(IsUnique true)]public string Username { get; set; }[Required][StringLength(100)]public strin…

Scroll 生态全面启动为 Pencils Protocol 赋能,DAPP 将迎强势腾飞

​Pencils Protocol 是 Scroll 生态最大的综合性 DeFi 平台&#xff0c;随着 DAPP 通证面向市场&#xff0c;Pencils Protocol 生态经济体系也将迎来全面运转。目前&#xff0c;DAPP 通证已经陆续上线了 Gate、Kucoin、Bitget、Coinone 等主流交易市场&#xff0c;全球用户能够…

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-23

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…

CPLD架构

1. 通用CPLD构架 传统的CPLD内部构架布局如图1-1所示&#xff0c;可编程互连阵列&#xff08;PIA&#xff09;在芯片中心位置&#xff0c;而逻辑阵列块则在芯片四周靠近I/O模块。目前大多数的CPLD都是采用这种结构&#xff0c;包括Xilinx主流的CoolRunner系列和Altera MAX 300…

2024第十四届新华三杯预赛考试大纲

本文档取自新华三杯官方网站

类与对象

类&#xff1a; class默认私有&#xff0c;struct默认公有 面向对象的三大特性&#xff1a; 封装、继承、多态 封装&#xff1a;本质是一种管控&#xff1b;C数据和方法都放在类里面&#xff0c;使用访问限定符对成员限制 类的存储&#xff1a; 每个对象只存成员变量&#…

elf文件简单介绍

文章目录 elf 程序示意图ELF文件格式概述ELF的组成结构1. ELF头部&#xff08;ELF Header&#xff09;2. 程序头表&#xff08;Program Header Table&#xff09;与程序头项&#xff08;Program Header Entry&#xff09;3. 节区头表&#xff08;Section Header Table&#xff…

【python系列】开篇:自学python的方法

1.前言 唯有自学才是最高效最省钱的学习编程的方法。最高效是因为你可以按照自己的节奏来进行学习&#xff0c;随时随地随心的学习&#xff0c;最主要的是掌握学习方法&#xff0c;当然培训老师是不会告诉你方法的&#xff0c;总是跟着培训老师在盲人摸象。最省钱是不用投入资…

【论文复现】交通路口智能监测平台实现

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀交通路口智能监测平台实现 1.概述2.工程文件简介2.1 工程文件结构2.2 训练检测模型2.2.1 准备数据集2.2.2 训练自己的权重文件2.2.3 使用自己…

不宽的宽字符

根据提示&#xff0c;通过nc 202.38.93.141 14202来进行连接&#xff0c;可以用自己的机器进行连接&#xff0c;也可以直接点击“打开/下载题目”连接&#xff1a; 意料之中的无法打开flag&#xff0c;看来得下载附件看看源码了 #include <iostream> #include <fstrea…

无脑使用matlab运行YOLOv5模型,实现目标检测

文章目录 前言代码报错解决方法缺点总结 前言 YOLO 是一种经典的一阶段目标检测算法&#xff0c;它将检测问题转化为回归问题。与 Faster R-CNN 不同&#xff0c;YOLO 不是提取 RoI,而是直接通过回归的方法生成每个类的边界框坐标和概率。与 Faster R-CNN相比&#xff0c;大大…

java ssm 高校固定资产管理系统 高校物资管理 资产信息 源码 jsp

一、项目简介 本项目是一套基于SSM的高校固定资产管理系统&#xff0c;主要针对计算机相关专业的和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本、软件工具等。 项目都经过严格调试&#xff0c;确保可以运行&#xff01; 二、技术实现 ​后端技术&am…

《战国王朝》青铜材料具体作用介绍

《战国王朝》中的青铜材料是游戏里非常重要的金属材料&#xff0c;而青铜材料的具体作用就是青铜用于制作第三层次的工具和武器;它比铜制的更好&#xff0c;但不如铁和钢制的&#xff0c;相比石制和铜制工具&#xff0c;青铜物品的使用寿命更长。 战国王朝青铜材料有什么用 青…