Ext.Net_Ext.Net.DateColumn 日期格式问题

这篇博客探讨了EXT.NET框架中DateColumn组件在显示日期时的格式问题。通过2011-07-14 14:05:37的例子,解释了如何使用不同的字母符号(如Y, M, D等)来定制日期时间格式,并指出EXT.NET会按原样显示设置的格式。" 81088711,7857676,图像处理:基于区域特征集成的显著目标检测,"['计算机视觉', '图像处理', '机器学习', '特征提取', '图像分析']

在使用DateColumn 时,会用到日期格式,代码如下:

<ext:DateColumn Header="日期" DataIndex="FINSERTEDDATE"Format="Y-m-d H:i:s"></ext:DateColumn>
那么EXT.NET日期格式是什么?之前以为跟数据库的格式差不多,又在EXT.NET CHM文档中找,都不对,其实,EXT.NET源代码就是最好的文档。

EXT.NET源代码片段

d:"String.leftPad(this.getDate(), 2, '0')",
D:"Date.getShortDayName(this.getDay())",
j:"this.getDate()",
l:"Date.dayNames[this.getDay()]",
N:"(this.getDay() ? this.getDay() : 7)",
S:"this.getSuffix()",
w:"this.getDay()",
z:"this.getDayOfYear()",
W:"String.leftPad(this.getWeekOfYear(), 2, '0')",
F:"Date.monthNames[this.getMonth()]",
m:"String.leftPad(this.getMonth() + 1, 2, '0')",
M:"Date.getShortMonthName(this.getMonth())",
n:"(this.getMonth() + 1)",
t:"this.getDaysInMonth()",
L:"(this.isLeapYear() ? 1 : 0)",
o:"(this.getFullYear() + (this.getWeekOfYear() == 1 &&this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 &&this.getMonth() < 11 ? -1 : 0)))",
Y:"String.leftPad(this.getFullYear(), 4, '0')",
y:"('' + this.getFullYear()).substring(2, 4)",
a:"(this.getHours() < 12 ? 'am' : 'pm')",
A:"(this.getHours() < 12 ? 'AM' : 'PM')",
g:"((this.getHours() % 12) ? this.getHours() % 12 : 12)",
G:"this.getHours()",
h:"String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2,'0')",
H:"String.leftPad(this.getHours(), 2, '0')",
i:"String.leftPad(this.getMinutes(), 2, '0')",
s:"String.leftPad(this.getSeconds(), 2, '0')",
u:"String.leftPad(this.getMilliseconds(), 3, '0')",
O:"this.getGMTOffset()",
P:"this.getGMTOffset(true)",
T:"this.getTimezone()",
Z:"(this.getTimezoneOffset() * -60)",

说明

根据它们的函数名能猜到它们的含义。比如,Y和y表示年;M和m表示月;D和d表示天;H和h表示小时;i表示分;s和u表示秒;A和a表示上下午。其他的如,L表示是否为闰年;O和P表示格林威治标准时间(GMT),英国的标准时间,也是世界各地时间的参考标准。中英两国的标准时差为8个小时,即英国当地时间比中国北京时间晚8小时;T和Z表示协调世界时(UTC)等等。

以2011-07-14 14:05:37为例

格式

结果

Y-m-d H:i:s

2011-07-14 14:05:37

y-m-d H:i:s

11-07-14 14:05:37

y-M-d H:i:s

2011-7-14 14:05:37

y-m-d H:i:s L

2011-7-14 14:05:37 0

y-m-d H:i:s T

2011-7-14 14:05:37 UTC

y-m-d H:i:s Z

2011-7-14 14:05:37 28800

y-m-d H:i:s O

2011-7-14 14:05:37 +0800

y-m-d H:i:s P

2011-7-14 14:05:37 +08:00

Y-m-d h:i:s

2011-07-14 2:05:37

Y-m-d H:i:s G

2011-7-14 14:05:37 14

Y-m-d H:i:s a

2011-7-14 14:05:37 下午

Y/m/d H:i:s

2011/07/14 14:05:37

Y/m/dH:i:s

2011/07/1414:05:37

说明

只要字母写对了,字母与字母间的字符无所谓,EXT.NET会原样显示。

# backend/routes/page_routes.py """ 前端页面路由模块(HTML 渲染) 职责:返回 HTML 页面,不处理 API 逻辑 依赖:Jinja2Templates + 静态资源挂载在 main.py 中完成 """ from fastapi import APIRouter, Request, Depends, HTTPException from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from pathlib import Path import logging from typing import Dict, Any from backend.jwt_handler import get_current_user_token_data, get_admin_user from backend.database import get_db from sqlalchemy.ext.asyncio import AsyncSession from backend.repositories.character_repo import CharacterRepository # 初始化日志 logger = logging.getLogger(__name__) # 路径配置 BASE_DIR = Path(__file__).resolve().parent.parent.parent # 项目根目录 TEMPLATES_DIR = BASE_DIR / "frontend" / "templates" # 初始化模板引擎 try: templates = Jinja2Templates(directory=str(TEMPLATES_DIR)) logger.info(f"✅ Jinja2 模板引擎已加载:{TEMPLATES_DIR}") except Exception as e: logger.error(f"❌ 初始化模板引擎失败:{str(e)}") raise # 创建路由器 router = APIRouter(tags=["前端页面"]) # ----------------------- # 工具函数:安全渲染模板 # ----------------------- def render_template_or_error( template_name: str, context: Dict[str, Any], request: Request ) -> HTMLResponse: """封装模板渲染,捕获异常""" try: return templates.TemplateResponse(template_name, {**context, "request": request}) except Exception as e: logger.error(f"❌ 渲染模板失败 | 模板:{template_name} | 错误:{str(e)}", exc_info=True) raise HTTPException(status_code=500, detail="页面渲染错误") # ----------------------- # 前端页面路由定义 # ----------------------- @router.get("/", response_class=HTMLResponse) async def home(request: Request): """首页 - 无需登录""" logger.info("📱 访问首页") return render_template_or_error("index.html", {}, request) @router.get("/login", response_class=HTMLResponse) async def login_page(request: Request): """登录页 - 无需认证""" logger.info("🔑 访问登录页") return render_template_or_error("login.html", {}, request) @router.get("/register", response_class=HTMLResponse) async def register_page(request: Request): """注册页 - 无需认证""" logger.info("📝 访问注册页") return render_template_or_error("register.html", {}, request) @router.get("/profile", response_class=HTMLResponse) async def profile_page( request: Request, token_data=Depends(get_current_user_token_data) ): """个人中心页 - 需登录""" logger.info(f"👤 用户访问个人中心 | ID:{token_data.user_id}") return render_template_or_error("profile.html", { "user_role": token_data.role, "user_dept_id": token_data.department_id }, request) @router.get("/chat", response_class=HTMLResponse) async def chat_page( request: Request, token_data=Depends(get_current_user_token_data), db: AsyncSession = Depends(get_db) ): """ 聊天页面 - 需登录 加载 AI 角色列表供前端选择 """ current_user_id = token_data.user_id client_ip = request.client.host logger.info(f"📋 用户访问聊天页 | ID:{current_user_id} | 角色:{token_data.role} | IP:{client_ip}") repo = CharacterRepository(db) try: characters = await repo.get_all() chars_list = [ {"id": c.id, "name": c.name, "trait": c.trait} for c in characters ] characters_json = f"<script>window.CHARACTERS = {repr(chars_list)};</script>" except Exception as e: logger.error(f"❌ 加载AI角色失败:{str(e)}", exc_info=True) raise HTTPException(status_code=500, detail="无法加载AI角色数据") context = { "characters": chars_list, "characters_json": characters_json, "user_role": token_data.role, "user_dept": token_data.department_id, "debug_user": current_user_id } return render_template_or_error("chat.html", context, request) @router.get("/share", response_class=HTMLResponse) async def share_page( request: Request, token_data=Depends(get_current_user_token_data) ): """分享广场页面 - 需登录""" logger.info(f"📌 用户访问分享页 | ID:{token_data.user_id}") return render_template_or_error("share.html", {}, request) @router.get("/search", response_class=HTMLResponse) async def search_page( request: Request, token_data=Depends(get_current_user_token_data) ): """搜索推荐页面 - 需登录""" logger.info(f"🔍 用户访问搜索页 | ID:{token_data.user_id}") return render_template_or_error("search.html", {}, request) @router.get("/forbidden", response_class=HTMLResponse) async def forbidden_page(request: Request): """权限不足页面""" logger.warning(f"⚠️ 用户访问被拒绝页面 | URL:{request.url}") return render_template_or_error("forbidden.html", {}, request) @router.get("/notfound", response_class=HTMLResponse) async def not_found_page(request: Request): """404 页面""" logger.warning(f"🚫 访问不存在的页面 | URL:{request.url}") return render_template_or_error("404.html", {"url": str(request.url)}, request) # ================================ # 管理员后台页面 (需 admin 权限) # ================================ @router.get("/admin", response_class=HTMLResponse) async def admin_dashboard( request: Request, admin=Depends(get_admin_user) ): """管理员控制台首页""" logger.info(f"🛠️ 管理员访问后台首页 | ID:{admin.user_id}") return render_template_or_error("admin/index.html", { "admin_id": admin.user_id, "admin_role": admin.role }, request) @router.get("/admin/users", response_class=HTMLResponse) async def admin_users_page( request: Request, admin=Depends(get_admin_user) ): """用户管理页面""" logger.info(f"👥 管理员访问用户管理页 | ID:{admin.user_id}") return render_template_or_error("admin/users.html", {}, request) @router.get("/admin/depts", response_class=HTMLResponse) async def admin_depts_page( request: Request, admin=Depends(get_admin_user) ): """院系管理页面""" logger.info(f"🏛️ 管理员访问院系管理页 | ID:{admin.user_id}") return render_template_or_error("admin/depts.html", {}, request) @router.get("/admin/characters", response_class=HTMLResponse) async def admin_characters_page( request: Request, admin=Depends(get_admin_user) ): """AI角色管理页面""" logger.info(f"🤖 管理员访问AI角色管理页 | ID:{admin.user_id}") return render_template_or_error("admin/characters.html", {}, request) @router.get("/admin/stats", response_class=HTMLResponse) async def admin_stats_page( request: Request, admin=Depends(get_admin_user) ): """统计数据展示页面""" logger.info(f"📊 管理员访问统计报表页 | ID:{admin.user_id}") return render_template_or_error("admin/stats.html", {}, request) 我现在有多个html页面需求,register,profile,404
最新发布
11-09
你已经完成了 `page_routes.py` 中多个前端页面的路由定义,包括: - `/register`:注册页 - `/profile`:个人中心页 - `/notfound`(即 404 页面) 接下来你需要创建对应的 HTML 模板文件,并确保它们位于正确的路径下(`frontend/templates/` 目录中),同时要保证这些页面具备基本结构、样式和可扩展性。 --- ### ✅ 解决方案:创建所需的 HTML 页面模板 我们将为以下三个页面分别提供基础模板代码: 1. `register.html` 2. `profile.html` 3. `404.html` 所有模板都基于 Jinja2 + Bootstrap 5 构建,便于快速开发与响应式布局。假设你的项目使用了静态资源(如 CSS/JS)在 `frontend/static/` 下。 --- #### 📁 文件结构预期如下: ``` frontend/ ├── templates/ │ ├── register.html │ ├── profile.html │ └── 404.html ├── static/ ├── css/ │ └── style.css └── js/ └── main.js ``` --- ### 1. `register.html` - 用户注册页面 ```html <!-- frontend/templates/register.html --> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>用户注册</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="/static/css/style.css"> </head> <body class="bg-light"> <div class="container mt-5" style="max-width: 400px;"> <h2 class="text-center mb-4">📝 注册新账户</h2> <form id="registerForm"> <div class="mb-3"> <label for="username" class="form-label">用户名</label> <input type="text" class="form-control" id="username" required /> </div> <div class="mb-3"> <label for="email" class="form-label">邮箱</label> <input type="email" class="form-control" id="email" required /> </div> <div class="mb-3"> <label for="password" class="form-label">密码</label> <input type="password" class="form-control" id="password" required /> </div> <div class="mb-3"> <label for="confirmPassword" class="form-label">确认密码</label> <input type="password" class="form-control" id="confirmPassword" required /> </div> <button type="submit" class="btn btn-primary w-100">注册</button> </form> <p class="text-center mt-3"> 已有账号?<a href="/login">去登录</a> </p> </div> <script src="/static/js/main.js"></script> <script> document.getElementById("registerForm").addEventListener("submit", async (e) => { e.preventDefault(); const password = document.getElementById("password").value; const confirmPassword = document.getElementById("confirmPassword").value; if (password !== confirmPassword) { alert("两次输入的密码不一致!"); return; } const res = await fetch("/api/auth/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: document.getElementById("username").value, email: document.getElementById("email").value, password: password, }), }); if (res.ok) { alert("注册成功!即将跳转到登录页..."); window.location.href = "/login"; } else { const data = await res.json(); alert("注册失败:" + (data.detail || "未知错误")); } }); </script> </body> </html> ``` --- ### 2. `profile.html` - 个人中心页面 ```html <!-- frontend/templates/profile.html --> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>个人中心</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="/static/css/style.css"> </head> <body class="bg-white"> <nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <div class="container"> <a class="navbar-brand" href="/">AI 聊天系统</a> <div class="ms-auto"> <span class="navbar-text">角色: {{ user_role }} | 部门: {{ user_dept_id }}</span> </div> </div> </nav> <div class="container mt-5" style="max-width: 600px;"> <h2 class="text-center mb-4">👤 个人资料</h2> <ul class="list-group"> <li class="list-group-item"><strong>用户ID:</strong><span id="userId">加载中...</span></li> <li class="list-group-item"><strong>用户名:</strong><span id="username">加载中...</span></li> <li class="list-group-item"><strong>邮箱:</strong><span id="email">加载中...</span></li> <li class="list-group-item"><strong>角色:</strong>{{ user_role }}</li> <li class="list-group-item"><strong>所属部门ID:</strong>{{ user_dept_id }}</li> <li class="list-group-item"><strong>注册时间:</strong><span id="createdAt">-</span></li> </ul> <div class="mt-4 d-grid gap-2 d-md-flex justify-content-md-end"> <button class="btn btn-outline-secondary" onclick="window.location.href='/'">返回首页</button> <button class="btn btn-danger" onclick="logout()">退出登录</button> </div> </div> <script src="/static/js/main.js"></script> <script> // 获取当前用户信息(通过 JWT 解码或调用 API) async function loadUserProfile() { try { const res = await fetch("/api/users/me", { headers: { "Authorization": "Bearer " + getJwtToken() } }); if (!res.ok) throw new Error("无法获取用户信息"); const user = await res.json(); document.getElementById("userId").textContent = user.id; document.getElementById("username").textContent = user.username; document.getElementById("email").textContent = user.email; document.getElementById("createdAt").textContent = new Date(user.created_at).toLocaleString(); } catch (err) { console.error(err); alert("加载用户信息失败,请重新登录"); window.location.href = "/login"; } } function getJwtToken() { return localStorage.getItem("access_token") || ""; } function logout() { localStorage.removeItem("access_token"); window.location.href = "/login"; } // 页面加载时获取数据 window.onload = loadUserProfile; </script> </body> </html> ``` --- ### 3. `404.html` - 页面未找到 ```html <!-- frontend/templates/404.html --> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>页面不存在</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <style> .error-container { height: 70vh; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; } </style> </head> <body class="bg-light"> <div class="container error-container"> <h1 class="display-1 text-danger">🚫 404</h1> <h2>抱歉,页面未找到</h2> <p class="text-muted">您访问的页面 <code>{{ url }}</code> 不存在。</p> <div class="mt-4"> <a href="/" class="btn btn-primary me-2">返回首页</a> <a href="/chat" class="btn btn-outline-secondary">进入聊天</a> </div> </div> </body> </html> ``` --- ## 🔍 解释说明 | 页面 | 功能 | 技术点 | |------|------|--------| | `register.html` | 新用户注册 | 表单验证、Fetch 提交、前后端交互 | | `profile.html` | 显示用户个人信息 | JWT 认证、异步加载数据、本地存储 token | | `404.html` | 友好提示错误页面 | 动态变量渲染(Jinja2)、用户体验优化 | > ⚠️ 注意事项: - 确保 `main.py` 正确挂载了 `/static` 路径。 - 前端 JS 使用 `localStorage` 存储 `access_token`,需配合登录逻辑设置。 - 所有 `/api/*` 接口需要后端支持 CORS。 --- ## ✅ 后续建议 1. **提取公共部分**:可以将 `<head>`、导航栏等抽成 `base.html`,使用 `{% extends %}` 继承。 2. **增强安全性**:注册时增加验证码、邮箱确认机制。 3. **响应式设计优化**:适配移动端体验。 4. **国际化支持**:未来可加入多语言切换。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值