Signed-off-by: kevin <kevin@lmve.net>
This commit is contained in:
2025-06-05 11:04:12 +08:00
parent 9b63e88da8
commit 9d3eb0cea9
1675 changed files with 357271 additions and 1 deletions
+37
View File
@@ -0,0 +1,37 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>demo</title>
</head>
<body class="d-flex flex-column">
<div class="page">
{{if .is_login}}
{{template "header-logined.html" .}}
{{else}}
{{template "header-no-login.html"}}
{{end}}
{{template "header-navigation.html"}}
{{template "footer.html"}}
</div>
</body>
</html>
+49
View File
@@ -0,0 +1,49 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>404 找不到页面</title>
</head>
<body class=" border-top-wide border-primary d-flex flex-column">
<div class="page page-center">
<div class="container-tight py-4">
<div class="empty">
<div class="empty-header">404</div>
<p class="empty-title">抱歉,当前页面出错了!</p>
<p class="empty-subtitle text-secondary">
找不到资源
</p>
<div class="empty-action">
<a href="/" class="btn btn-primary">
<!-- Download SVG icon from http://tabler-icons.io/i/arrow-left -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M5 12l14 0" />
<path d="M5 12l6 6" />
<path d="M5 12l6 -6" />
</svg>
返回主页
</a>
</div>
</div>
</div>
{{template "footer.html"}}
</div>
</body>
</html>
+49
View File
@@ -0,0 +1,49 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>500 服务器错误</title>
</head>
<body class=" border-top-wide border-primary d-flex flex-column">
<div class="page page-center">
<div class="container-tight py-4">
<div class="empty">
<div class="empty-header">500</div>
<p class="empty-title">抱歉,服务器出错了!</p>
<p class="empty-subtitle text-secondary">
服务器内部错误!
</p>
<div class="empty-action">
<a href="/" class="btn btn-primary">
<!-- Download SVG icon from http://tabler-icons.io/i/arrow-left -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M5 12l14 0" />
<path d="M5 12l6 6" />
<path d="M5 12l6 -6" />
</svg>
返回主页
</a>
</div>
</div>
</div>
{{template "footer.html"}}
</div>
</body>
</html>
+90
View File
@@ -0,0 +1,90 @@
<footer class="footer footer-transparent d-print-none">
<div class="container-xl">
<div class="row text-center align-items-center flex-row-reverse">
<div class="col-lg-auto ms-lg-auto">
<ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item"><a href="https://git.lmve.net/kevin/gin_saas/-/blob/main/readme.md?ref_type=heads" target="_blank"
class="link-secondary" rel="noopener">文档</a></li>
<li class="list-inline-item"><a href="https://git.lmve.net/kevin/gin_saas/-/blob/main/LICENSE?ref_type=heads" target="_blank" class="link-secondary">开源协议</a>
</li>
<li class="list-inline-item"><a href="https://git.lmve.net/kevin/gin_saas" target="_blank"
class="link-secondary" rel="noopener">
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-orange" width="24" height="24"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-brand-gitlab">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M21 14l-9 7l-9 -7l3 -11l3 7h6l3 -7z" />
</svg>
源码</a></li>
<li class="list-inline-item">
<a href="https://wnfed.com" target="_blank" class="link-secondary" rel="noopener">
<!-- Download SVG icon from http://tabler-icons.io/i/heart -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-pink icon-filled icon-inline" width="24"
height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" />
</svg>
博客
</a>
</li>
</ul>
</div>
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
<ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item">
Copyright &copy; 2025
<a href="https://lmve.net" target="_blank" class="link-secondary">Lmve.NET</a>.
All rights reserved.
</li>
<li class="list-inline-item">
<a href="https://git.lmve.net/kevin/gin_saas/-/commits/main" target="_blank" class="link-secondary" rel="noopener">
v0.0.1
</a>
</li>
</ul>
</div>
</div>
</div>
</footer>
<!-- CSS files -->
<link href="/dist/css/tabler.min.css?1692870487" rel="stylesheet" />
<link href="/dist/css/tabler-flags.min.css?1692870487" rel="stylesheet" />
<link href="/dist/css/tabler-payments.min.css?1692870487" rel="stylesheet" />
<link href="/dist/css/tabler-vendors.min.css?1692870487" rel="stylesheet" />
<link href="/dist/css/demo.min.css?1692870487" rel="stylesheet" />
<style>
@import url('https://rsms.me/inter/inter.css');
:root {
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
}
body {
font-feature-settings: "cv03", "cv04", "cv11";
}
</style>
<!-- Libs JS -->
<!-- <script src="/dist/libs/apexcharts/dist/apexcharts.min.js?1692870487" defer></script>
<script src="/dist/libs/jsvectormap/dist/js/jsvectormap.min.js?1692870487" defer></script>
<script src="/dist/libs/jsvectormap/dist/maps/world.js?1692870487" defer></script>
<script src="/dist/libs/jsvectormap/dist/maps/world-merc.js?1692870487" defer></script> -->
<!-- Tabler Core -->
<script src="/dist/js/tabler.min.js?1692870487" defer></script>
<script src="/dist/js/demo.min.js?1692870487" defer></script>
<script src="/dist/js/demo-theme.min.js?1692870487"></script>
<script src="/dist/js/my_js_func.js"></script>
<script src="/dist/js/axios.min.js"></script>
<script src="/dist/js/jquery-3.7.1.min.js"></script>
+130
View File
@@ -0,0 +1,130 @@
<!-- 已登录header -->
<header class="navbar navbar-expand-md d-print-none">
<div class="container-xl">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu"
aria-controls="navbar-menu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<h1 class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
<a href="/">
<img src="/static/logo.svg" width="110" height="32" alt="Tabler" class="navbar-brand-image">
</a>
</h1>
<div class="navbar-nav flex-row order-md-last">
<div class="d-none d-md-flex">
<a href="?theme=dark" class="nav-link px-0 hide-theme-dark" title="Enable dark mode" data-bs-toggle="tooltip"
data-bs-placement="bottom">
<!-- Download SVG icon from http://tabler-icons.io/i/moon -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
</svg>
</a>
<a href="?theme=light" class="nav-link px-0 hide-theme-light" title="Enable light mode" data-bs-toggle="tooltip"
data-bs-placement="bottom">
<!-- Download SVG icon from http://tabler-icons.io/i/sun -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" />
<path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" />
</svg>
</a>
<div class="nav-item dropdown d-none d-md-flex me-3">
<a href="#" class="nav-link px-0" data-bs-toggle="dropdown" tabindex="-1" aria-label="Show notifications">
<!-- Download SVG icon from http://tabler-icons.io/i/bell -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3h-16a4 4 0 0 0 2 -3v-3a7 7 0 0 1 4 -6" />
<path d="M9 17v1a3 3 0 0 0 6 0v-1" />
</svg>
<!-- <span class="badge bg-red"></span> -->
</a>
<div class="dropdown-menu dropdown-menu-arrow dropdown-menu-end dropdown-menu-card">
<div class="card">
<div class="card-header">
<h3 class="card-title">最新消息</h3>
</div>
<div class="list-group list-group-flush list-group-hoverable">
<div class="list-group-item">
<div class="row align-items-center">
<div class="col-auto"><span class="status-dot status-dot-animated bg-green d-block"></span></div>
<div class="col text-truncate">
<a class="text-body d-block">测试消息</a>
<div class="d-block text-secondary text-truncate mt-n1">
这是一条测试用的占位消息
</div>
</div>
<div class="col-auto">
<a class="list-group-item-actions">
<!-- Download SVG icon from http://tabler-icons.io/i/star -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-muted" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" />
</svg>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="nav-item dropdown">
<a href="#" class="nav-link d-flex lh-1 text-reset p-0" data-bs-toggle="dropdown" aria-label="Open user menu">
<span class="avatar avatar-sm" style="background-image: url({{.user_info.AvatarPath}})"></span>
<div class="d-none d-xl-block ps-2">
<div>{{.user_info.Username}}</div>
<div class="mt-1 small text-secondary">{{.user_info.FirstName}}</div>
</div>
</a>
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
<!-- <a href="#" class="dropdown-item">Status</a> -->
<a href="./profile" class="dropdown-item">个人资料</a>
<!-- <a href="#" class="dropdown-item">Feedback</a> -->
<a href="/setting-my" class="dropdown-item">设置</a>
<div class="dropdown-divider"></div>
<a href="#" onclick="logout()" class="dropdown-item">登出</a>
</div>
</div>
</div>
</div>
</header>
<script>
function logout() {
console.log("logout");
const url = '/api/v1/user/logout';
const sumt_data = {
cookie: "",
};
try {
const response = axios.post(url, sumt_data, {
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
//console.log('提交成功:', response.data); // 正确打印服务器数据
//跳转到主页
if (response.data.err_code == 0) {
location.href = '/'
}
});
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码(如 4xx, 5xx)
console.error('服务器错误:', error.response.data);
} else {
console.error('请求未完成:', error.message);
}
}
}
</script>
+40
View File
@@ -0,0 +1,40 @@
<!-- 未登录状态header -->
<header class="navbar navbar-expand-md d-print-none">
<div class="container-xl">
<h1 class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
<a href="/">
<img src="/static/logo.svg" width="110" height="32" alt="Tabler" class="navbar-brand-image">
</a>
</h1>
<div class="navbar-nav flex-row order-md-last">
<!-- 深色模式按钮 -->
<div class="d-none d-md-flex">
<a href="?theme=dark" class="nav-link px-0 hide-theme-dark" title="Enable dark mode"
data-bs-toggle="tooltip" data-bs-placement="bottom">
<!-- Download SVG icon from http://tabler-icons.io/i/moon -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
</svg>
</a>
<a href="?theme=light" class="nav-link px-0 hide-theme-light" title="Enable light mode"
data-bs-toggle="tooltip" data-bs-placement="bottom">
<!-- Download SVG icon from http://tabler-icons.io/i/sun -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" />
<path
d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" />
</svg>
</a>
</div>
<!-- 深色模式按钮 -->
</div>
</div>
</header>
+86
View File
@@ -0,0 +1,86 @@
<header class="navbar-expand-md">
<div class="collapse navbar-collapse" id="navbar-menu">
<div class="navbar">
<div class="container-xl">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/">
<span
class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/home -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M5 12l-2 0l9 -9l9 9l-2 0"></path>
<path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7"></path>
<path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"></path>
</svg>
</span>
<span class="nav-link-title">
主页
</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/warehouses">
<span
class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/home -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-building-warehouse">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M3 21v-13l9 -4l9 4v13"></path>
<path d="M13 13h4v8h-10v-6h6"></path>
<path d="M13 21v-9a1 1 0 0 0 -1 -1h-2a1 1 0 0 0 -1 1v3"></path>
</svg>
</span>
<span class="nav-link-title">
仓库
</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/workorders">
<span
class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/home -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-file-description">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M14 3v4a1 1 0 0 0 1 1h4" />
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" />
<path d="M9 17h6" />
<path d="M9 13h6" />
</svg>
</span>
<span class="nav-link-title">
工单
</span>
</a>
</li>
</ul>
<div class="my-2 my-md-0 flex-grow-1 flex-md-grow-0 order-first order-md-last">
<div class="input-icon">
<span class="input-icon-addon">
<!-- Download SVG icon from http://tabler-icons.io/i/search -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0"></path>
<path d="M21 21l-6 -6"></path>
</svg>
</span>
<input type="text" value="" class="form-control" placeholder="全站搜索"
aria-label="Search in website">
</div>
</div>
</div>
</div>
</div>
</header>
+62
View File
@@ -0,0 +1,62 @@
<!-- 未登录状态header -->
<header class="navbar navbar-expand-md d-print-none">
<div class="container-xl">
<h1 class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
<a href="/">
<img src="/static/logo.svg" width="110" height="32" alt="Tabler" class="navbar-brand-image">
</a>
</h1>
<div class="navbar-nav flex-row order-md-last">
<!-- 深色模式按钮 -->
<div class="d-none d-md-flex">
<a href="?theme=dark" class="nav-link px-0 hide-theme-dark" title="Enable dark mode"
data-bs-toggle="tooltip" data-bs-placement="bottom">
<!-- Download SVG icon from http://tabler-icons.io/i/moon -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
</svg>
</a>
<a href="?theme=light" class="nav-link px-0 hide-theme-light" title="Enable light mode"
data-bs-toggle="tooltip" data-bs-placement="bottom">
<!-- Download SVG icon from http://tabler-icons.io/i/sun -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" />
<path
d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" />
</svg>
</a>
</div>
<!-- 深色模式按钮 -->
<div class="nav-item btn-list">
<a href="/sign-in" class="btn" rel="noreferrer">
<!-- Download SVG icon from http://tabler-icons.io/i/heart -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-blue" width="24" height="24"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-password-user">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 17v4" />
<path d="M10 20l4 -2" />
<path d="M10 18l4 2" />
<path d="M5 17v4" />
<path d="M3 20l4 -2" />
<path d="M3 18l4 2" />
<path d="M19 17v4" />
<path d="M17 20l4 -2" />
<path d="M17 18l4 2" />
<path d="M9 6a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
<path d="M7 14a2 2 0 0 1 2 -2h6a2 2 0 0 1 2 2" />
</svg>
登录/注册
</a>
</div>
</div>
</div>
</header>
+37
View File
@@ -0,0 +1,37 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>主页</title>
</head>
<body class="d-flex flex-column">
<div class="page">
{{if .is_login}}
{{template "header-logined.html" .}}
{{else}}
{{template "header-no-login.html"}}
{{end}}
{{template "header-navigation.html"}}
{{template "footer.html"}}
</div>
</body>
</html>
+34
View File
@@ -0,0 +1,34 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>添加新仓库</title>
</head>
<body class="d-flex flex-column">
<div class="page">
{{template "header-logined.html" .}}
{{template "header-navigation.html"}}
{{template "footer.html"}}
</div>
</body>
</html>
+630
View File
@@ -0,0 +1,630 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>设置-个人设置</title>
</head>
<body class="d-flex flex-column">
<div class="page">
<!-- Navbar -->
{{if .is_login}}
{{template "header-logined.html" .}}
{{else}}
{{template "header-no-login.html"}}
{{end}}
<header class="navbar-expand-md">
</header>
<div class="page-wrapper">
<!-- Page header -->
<div class="page-header d-print-none">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<h2 class="page-title">
设置
</h2>
</div>
</div>
</div>
</div>
<!-- Page body -->
<div class="page-body">
<div class="container-xl">
<div class="card">
<div class="row g-0">
<div class="col-12 col-md-3 border-end">
<div class="card-body">
<h4 class="subheader">账号设置</h4>
<div class="list-group list-group-transparent">
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center active">信息设置</a>
<a href="/setting-security"
class="list-group-item list-group-item-action d-flex align-items-center">安全设置</a>
</div>
<h4 class="subheader mt-4">外部设置</h4>
<div class="list-group list-group-transparent">
</div>
</div>
</div>
<div class="col-12 col-md-9 d-flex flex-column">
<div class="card-body">
<h2 class="mb-4">信息设置</h2>
<!-- <h3 class="card-title">Profile Details</h3> -->
<div class="row align-items-center">
<div class="col-auto"><span id="myAvatar" class="avatar avatar-xl"
style="background-image: url({{.user_info.AvatarPath}})"></span>
</div>
<div class="col-auto"><a href="#" class="btn" onclick="avatar_toolt.show()">
更改头像
</a></div>
<!-- <div class="col-auto"><a href="#" class="btn btn-ghost-danger">
删除头像
</a></div> -->
</div>
<!-- <h3 class="card-title mt-4">Business Profile</h3> -->
<div class="row g-3">
<div class="col-md">
<div class="form-label">名字</div>
<input id="username" type="text" class="form-control" value="{{.user_info.Username}}" maxlength="30">
</div>
<div class="col-md">
<div class="form-label">备注</div>
<input id="first_name" type="text" class="form-control" value="{{.user_info.FirstName}}" maxlength="50">
</div>
</div>
<div class="mb-3">
<label class="form-label">生日</label>
<div class="row g-2">
<div class="col-5">
<input type="text" class="form-control" id="birthday-picker" placeholder="选择生日"
value="{{.user_info.Birthdate}}">
</div>
</div>
</div>
</div>
<div class="card-footer bg-transparent mt-auto">
<div class="btn-list justify-content-end">
<a href="#" onclick="updata_user_info()" class="btn btn-primary">
提交
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{template "footer.html"}}
</div>
</body>
</html>
<div class="modal modal-blur fade" id="avata_toolt" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
<div class="modal-content">
<div class="container">
<h1>头像裁剪工具</h1>
<div class="flex-wrapper">
<!-- 左侧裁剪区 -->
<div class="crop-section">
<div id="image-wrapper">
<img id="cropper-image"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
</div>
<!-- 上传进度 -->
<div class="progress-container">
<div class="progress-bar"></div>
</div>
<!-- 消息提示 -->
<div id="message" class="alert"></div>
<div class="preview-stats">
<!-- <p>当前缩放: <span id="zoomValue">100%</span></p> -->
<p>图片尺寸: <span id="imageSize">0 x 0</span></p>
</div>
</div>
<!-- 右侧预览区 -->
<div class="preview-section">
<h3>实时预览</h3>
<div class="preview-box">
<img id="preview-img"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
</div>
<!-- 控制按钮 -->
<div class="controls">
<label class="btn btn-primary">
📁 选择图片
<input type="file" id="fileInput" accept="image/*">
</label>
<button class="btn btn-secondary " onclick="rotateImage(-90)">↩️ 左旋</button>
<button class="btn btn-success " id="uploadBtn">✂️ 裁剪头像</button>
<button class="btn btn-danger " style="margin-top: 150px;" onclick="avatar_toolt.hide()">❌ 取消</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
/* 主容器 */
.litepicker {
--color-primary: #4f46e5;
/* 主题色(选中日期/按钮) */
--color-primary-light: #e0e7ff;
--color-text: #1f2937;
/* 文本颜色 */
--color-text-light: #6b7280;
--font-family: 'Inter', sans-serif;
/* 自定义字体 */
}
/* 日期单元格悬停效果 */
.litepicker .container__days .day-item:hover {
background: #f3f4f6;
}
.litepicker {
border-radius: 8px;
/* 整体圆角 */
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.litepicker .container__months {
gap: 24px;
/* 月份之间的间距 */
}
@media (max-width: 640px) {
.litepicker {
width: 100% !important;
/* 全屏宽度 */
}
.litepicker .container__months {
flex-direction: column;
/* 垂直排列 */
}
}
/* 头像裁剪器样式*/
.container {
width: 95%; /* 改为百分比宽度 */
margin: 20px auto; /* 增加上下边距 */
max-width: 1200px; /* 保留最大宽度 */
background: white;
padding: 30px;
border-radius: 12px;
}
.flex-wrapper {
display: flex;
gap: 30px;
margin-top: 20px;
flex-wrap: wrap; /* 添加换行支持 */
}
/* 裁剪区域 */
.crop-section {
flex: 1 1 60%; /* 弹性布局基础宽度 */
min-width: 300px; /* 降低最小宽度 */
height: auto; /* 移除固定高度 */
min-height: 400px; /* 设置最小高度 */
}
#image-wrapper {
width: 100%;
height: 60vh; /* 改用视窗单位 */
max-height: 600px; /* 设置最大高度 */
background: #f8f9fa;
border: 2px dashed #ddd;
border-radius: 8px;
overflow: hidden;
}
/* 预览区域自适应 */
.preview-section {
flex: 1 1 35%; /* 弹性布局基础宽度 */
min-width: 250px; /* 设置合理最小宽度 */
}
/* 移动端适配 */
@media (max-width: 768px) {
.container {
padding: 15px; /* 减少内边距 */
}
.flex-wrapper {
flex-direction: column; /* 垂直排列 */
}
.crop-section,
.preview-section {
width: 100% !important; /* 强制全宽 */
min-width: unset; /* 移除最小宽度 */
}
#image-wrapper {
height: 50vh; /* 调整移动端高度 */
}
.preview-box {
width: 120px; /* 缩小预览区域 */
height: 120px;
}
.controls {
flex-direction: column; /* 垂直排列按钮 */
margin-top: 10px;
}
}
#cropper-image {
max-width: none !important;
max-height: none !important;
}
/* 控制区域 */
.controls {
margin-top: 20px;
display: flex;
flex-direction: column;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
/* 预览区域 */
.preview-section {
flex: 1;
min-width: 50px;
}
.preview-box {
width: 150px;
height: 150px;
/* border-radius: 50%; */
border: 3px solid var(--primary-color);
overflow: hidden;
margin: 0 auto 20px;
}
#preview-img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* 上传进度 */
.progress-container {
height: 8px;
background: #eee;
border-radius: 4px;
margin-top: 20px;
overflow: hidden;
display: none;
}
.progress-bar {
width: 0%;
height: 100%;
background: var(--primary-color);
transition: width 0.3s ease;
}
/* 消息提示 */
.alert {
padding: 15px;
border-radius: 6px;
margin-top: 20px;
display: none;
}
.alert-success {
background: #dff0d8;
color: #3c763d;
}
.alert-error {
background: #f2dede;
color: var(--error-color);
}
input[type="file"] {
display: none;
}
</style>
<!-- lib -->
<!-- 依赖库 -->
<!-- 引入 Litepicker 核心 CSS 和 JS -->
<script src="/dist/libs/litepicker/dist/js/litepicker.js"></script>
<script src="/dist/libs/cropper/cropper.min.js"></script>
<link href="/dist/libs/cropper/cropper.min.css" rel="stylesheet">
<!-- libs -->
<script src="/dist/libs/bootstrap/dist/js/bootstrap.min.js"></script>
<script>
const avatar_dom = document.getElementById('myAvatar');
function get_user_avatar() {
const bgImage = avatar_dom.style.backgroundImage;
// 方法 2:字符串分割
const currentUrl = bgImage.split('url("')[1]?.split('")')[0];
return currentUrl;
}
function set_user_avatar(str) {
avatar_dom.style.backgroundImage = 'url("' + str + '")';
}
//头像裁剪工具
const avatar_toolt = new bootstrap.Modal('#avata_toolt');
const birthdayPicker = new Litepicker({
element: document.getElementById('birthday-picker'),
lang: 'zh-cn', // 设置为中文
firstDay: 0, // 周日为首日
format: 'YYYY-MM-DD', // 日期格式
maxDate: new Date(), // 最大日期为今天
dropdowns: {
minYear: 1900, // 最小可选年份
maxYear: new Date().getFullYear(), // 最大为当前年份
months: true, // 显示月份下拉
years: true // 显示年份下拉
}
});
//头像裁剪区
let cropper;
const image = document.getElementById('cropper-image');
const message = document.getElementById('message');
let currentScale = 1;
// 初始化Cropper
function initCropper(imageSrc) {
if (cropper) {
cropper.destroy();
}
image.src = imageSrc;
cropper = new Cropper(image, {
aspectRatio: 1,
viewMode: 2,
autoCropArea: 0.8,
zoomable: true,
zoomOnWheel: true,
zoomOnTouch: true,
wheelZoomRatio: 0.1,
//minCanvasWidth: 400,
//minCanvasHeight: 400,
crop: updatePreview,
ready() {
updateImageInfo();
document.querySelector('.progress-container').style.display = 'none';
}
});
}
// 旋转控制
function rotateImage(degrees) {
if (cropper) {
cropper.rotateTo(cropper.getData().rotate + degrees);
updatePreview();
}
}
// 更新预览
function updatePreview() {
const canvas = cropper.getCroppedCanvas({
width: 250,
height: 250,
imageSmoothingQuality: 'high'
});
if (canvas) {
canvas.toBlob(blob => {
const previewUrl = URL.createObjectURL(blob);
document.getElementById('preview-img').src = previewUrl;
// 清理旧URL
setTimeout(() => URL.revokeObjectURL(previewUrl), 1000);
}, 'image/jpeg', 0.85);
updateImageInfo();
}
}
// 更新图片信息
function updateImageInfo() {
if (cropper) {
const data = cropper.getData();
// document.getElementById('zoomValue').textContent =
// `${Math.round(currentScale * 100)}%`;
document.getElementById('imageSize').textContent =
`${Math.round(data.width)} x ${Math.round(data.height)}`;
}
}
// 文件选择事件
document.getElementById('fileInput').addEventListener('change', function (e) {
const file = e.target.files[0];
if (!file) return;
if (!file.type.startsWith('image/')) {
showMessage('⚠️ 请选择有效的图片文件', 'error');
return;
}
const reader = new FileReader();
reader.onload = () => {
initCropper(reader.result);
currentScale = 1;
};
reader.readAsDataURL(file);
});
// 上传功能
document.getElementById('uploadBtn').addEventListener('click', async () => {
const progressBar = document.querySelector('.progress-bar');
const progressContainer = document.querySelector('.progress-container');
try {
if (!cropper) {
showMessage('⚠️ 请先选择并裁剪图片', 'error');
return;
}
progressContainer.style.display = 'block';
const canvas = cropper.getCroppedCanvas({
width: 1024,
height: 1024,
imageSmoothingQuality: 'high'
});
const blob = await new Promise(resolve =>
canvas.toBlob(resolve, 'image/jpeg', 0.9)
);
const formData = new FormData();
formData.append('file', blob, `avatar_${Date.now()}.jpg`);
formData.append('meta', JSON.stringify({
width: canvas.width,
height: canvas.height,
scale: currentScale.toFixed(2)
}));
const response = await fetch('/api/v1/file/avatar', {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
if (!response.ok) throw new Error(`服务器错误: ${response.status}`);
const result = await response.json();
if (result.err_code == 0) {
showMessage(`✅ 上传成功!`, 'success');
set_user_avatar(result.data.path);
console.log(get_user_avatar());
avatar_toolt.hide();
} else {
showMessage(`❌ 上传失败: ${result.err_msg}`, 'error');
}
} catch (error) {
console.error('上传错误:', error);
showMessage(`❌ 上传失败: ${error.message}`, 'error');
} finally {
progressBar.style.width = '0%';
progressContainer.style.display = 'none';
}
});
// 消息提示
function showMessage(text, type = 'success') {
message.className = `alert alert-${type}`;
message.textContent = text;
message.style.display = 'block';
setTimeout(() => message.style.display = 'none', 5000);
}
// 清理资源
window.addEventListener('beforeunload', () => {
if (cropper) cropper.destroy();
document.querySelectorAll('img').forEach(img => {
if (img.src.startsWith('blob:')) URL.revokeObjectURL(img.src);
});
});
// 初始化默认图片
//initCropper('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=');
//更新用户资料
function updata_user_info(){
const url = '/api/v1/user/updata_info';
const sumt_data = {
avatar:get_user_avatar(),
username:document.getElementById("username").value,
first_name:document.getElementById("first_name").value,
birthday:document.getElementById("birthday-picker").value,
};
try {
const response = axios.post(url, sumt_data, {
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
//console.log(response)
if(response.data.err_code==0){
location.reload()
}else{
console.log(response.data)
}
});
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码(如 4xx, 5xx)
console.error('服务器错误:', error.response.data);
} else {
console.error('请求未完成:', error.message);
}
}
}
</script>
+303
View File
@@ -0,0 +1,303 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>设置-安全设置</title>
</head>
<body class="d-flex flex-column">
<div class="page">
<!-- Navbar -->
{{if .is_login}}
{{template "header-logined.html" .}}
{{else}}
{{template "header-no-login.html"}}
{{end}}
<header class="navbar-expand-md">
</header>
<div class="page-wrapper">
<!-- Page header -->
<div class="page-header d-print-none">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<h2 class="page-title">
设置
</h2>
</div>
</div>
</div>
</div>
<!-- Page body -->
<div class="page-body">
<div class="container-xl">
<div class="card">
<div class="row g-0">
<div class="col-12 col-md-3 border-end">
<div class="card-body">
<h4 class="subheader">账号设置</h4>
<div class="list-group list-group-transparent">
<a href="/setting-my"
class="list-group-item list-group-item-action d-flex align-items-center ">信息设置</a>
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center active">安全设置</a>
</div>
<h4 class="subheader mt-4">外部设置</h4>
<div class="list-group list-group-transparent">
</div>
</div>
</div>
<div class="col-12 col-md-9 d-flex flex-column">
<div class="card-body">
<h2 class="mb-4">安全设置</h2>
<h3 class="card-title mt-4">安全邮箱</h3>
<p class="card-subtitle">用于找回账号密码,该联系方式不会公开显示给其他人。</p>
<div>
<div class="row g-2">
<div class="col-auto">
<input id="mail" type="email" class="form-control w-auto " value="{{.user.Email}}"
maxlength="64">
<div id="email_input_err" class="invalid-feedback">不能为空</div>
<div class="valid-feedback">修改成功</div>
</div>
<div class="col-auto"><a href="#" class="btn" onclick="change_email()">
修改邮箱
</a></div>
</div>
</div>
<h3 class="card-title mt-4">登录密码</h3>
<p class="card-subtitle">修改密码后需要重新登录</p>
<div class="col-auto">
<input id="pass_old" type="password" class="form-control w-auto mt-1" placeholder="旧密码"
autocomplete="off">
<div id="pass_old_err" class="invalid-feedback">不能为空</div>
</div>
<div class="col-auto">
<input id="pass_new" type="password" class="form-control w-auto mt-1" placeholder="新密码"
autocomplete="off">
<div class="invalid-feedback">不能为空</div>
</div>
<div class="col-auto">
<input id="pass_cmf" type="password" class="form-control w-auto mt-1 mb-1" placeholder="确认密码"
autocomplete="off">
<div id="pass_cmf_err" class="invalid-feedback">不能为空</div>
</div>
<a id="show_pass" class="link-secondary " title="显示密码"
data-bs-toggle="tooltip"><!-- Download SVG icon from http://tabler-icons.io/i/eye -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-eye">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
<path d="M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6" />
</svg>
</a>
<a id="show_pass_no" class="link-secondary d-none" title="隐藏密码"
data-bs-toggle="tooltip"><!-- Download SVG icon from http://tabler-icons.io/i/eye -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-eye-off">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10.585 10.587a2 2 0 0 0 2.829 2.828" />
<path
d="M16.681 16.673a8.717 8.717 0 0 1 -4.681 1.327c-3.6 0 -6.6 -2 -9 -6c1.272 -2.12 2.712 -3.678 4.32 -4.674m2.86 -1.146a9.055 9.055 0 0 1 1.82 -.18c3.6 0 6.6 2 9 6c-.666 1.11 -1.379 2.067 -2.138 2.87" />
<path d="M3 3l18 18" />
</svg>
</a>
<div>
<a href="#" class="btn" onclick="change_pass()">
修改密码
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{template "footer.html"}}
</div>
</body>
</html>
<script>
const dom_mail = document.getElementById("mail")
const dom_pass_old = document.getElementById("pass_old")
const dom_pass_new = document.getElementById("pass_new")
const dom_pass_cmf = document.getElementById("pass_cmf")
var show_password_dom = document.getElementById('show_pass');
var show_password_no_dom = document.getElementById('show_pass_no');
show_password_dom.addEventListener('click', function () {
dom_pass_old.type = "text";
dom_pass_new.type = "text";
dom_pass_cmf.type = "text";
show_password_dom.classList.add("d-none")
show_password_no_dom.classList.remove("d-none");
})
show_password_no_dom.addEventListener('click', function () {
dom_pass_old.type = "password";
dom_pass_new.type = "password";
dom_pass_cmf.type = "password";
show_password_no_dom.classList.add("d-none")
show_password_dom.classList.remove("d-none");
})
dom_mail.addEventListener('input', function () {
if (dom_mail.value != "") {
dom_mail.classList.remove("is-invalid");
dom_mail.classList.remove("is-valid");
}
})
dom_pass_old.addEventListener('input', function () {
if (dom_pass_old.value != "") {
dom_pass_old.classList.remove("is-invalid");
}
})
dom_pass_new.addEventListener('input', function () {
if (dom_pass_new.value != "") {
dom_pass_new.classList.remove("is-invalid");
}
})
dom_pass_cmf.addEventListener('input', function () {
if (dom_pass_cmf.value != "") {
dom_pass_cmf.classList.remove("is-invalid");
}
})
function change_email() {
if (dom_mail.value != "") {
if (isValidEmail(dom_mail.value)) {
const url = '/api/v1/user/change_email';
const sumt_data = {
new_email: dom_mail.value
};
try {
const response = axios.post(url, sumt_data, {
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
if (response.data.err_code == 0) {
dom_mail.classList.add("is-valid");
} else {
console.log(response.data)
}
});
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码(如 4xx, 5xx)
console.error('服务器错误:', error.response.data);
} else {
console.error('请求未完成:', error.message);
}
}
//console.log(sumt_data);
} else {
dom_mail.classList.add("is-invalid");
dom_mail.placeholder = "不是邮箱";
document.getElementById("email_input_err").innerHTML = "不是邮箱";
}
} else {
dom_mail.classList.add("is-invalid");
}
}
function change_pass() {
var valid = true
if (dom_pass_old.value == "") {
valid = false
dom_pass_old.classList.add("is-invalid")
}
if (dom_pass_new.value == "") {
valid = false
dom_pass_new.classList.add("is-invalid")
}
if (dom_pass_cmf.value == "") {
valid = false
dom_pass_cmf.classList.add("is-invalid")
} else {
if (dom_pass_cmf.value != dom_pass_new.value) {
valid = false
dom_pass_cmf.classList.add("is-invalid")
document.getElementById("pass_cmf_err").innerHTML = "密码不一致";
}
}
if (valid) {
const url = '/api/v1/user/change_pass';
const sumt_data = {
pass_old: dom_pass_old.value,
pass_new: dom_pass_new.value,
};
try {
const response = axios.post(url, sumt_data, {
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
if (response.data.err_code == 0) {
location.href = '/sign-in'
} else if (response.data.err_code == 3) {
dom_pass_old.classList.add("is-invalid")
document.getElementById("pass_old_err").innerHTML = "密码不正确";
} else {
console.log(response.data)
}
});
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码(如 4xx, 5xx)
console.error('服务器错误:', error.response.data);
} else {
console.error('请求未完成:', error.message);
}
}
}
}
</script>
+197
View File
@@ -0,0 +1,197 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>登录</title>
</head>
<body class=" d-flex flex-column">
<div class="page page-center">
{{template "header-min.html" .}}
<div class="container container-normal py-4">
<div class="row align-items-center g-4">
<div class="col-lg">
<div class="container-tight">
<div class="text-center mb-4">
<a href="." class="navbar-brand navbar-brand-autodark"><img src="/static/logo.svg" height="36"
alt=""></a>
</div>
<div class="card card-md">
<div class="card-body">
<h2 class="h2 text-center mb-4">登录你的账号</h2>
<div class="mb-3">
<label class="form-label">用户名</label>
<input id="username" type="text" class="form-control" placeholder="输入你的用户名" autocomplete="off"
maxlength="25">
<div class="invalid-feedback">不能为空</div>
</div>
<div class="mb-2">
<label class="form-label">
密码
</label>
<div class="input-group input-group-flat">
<input id="password" type="password" class="form-control" placeholder="输入你的密码" autocomplete="off">
<span class="input-group-text">
<a id="show_pass" class="link-secondary " title="显示密码"
data-bs-toggle="tooltip"><!-- Download SVG icon from http://tabler-icons.io/i/eye -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-eye">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
<path d="M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6" />
</svg>
</a>
<a id="show_pass_no" class="link-secondary d-none" title="隐藏密码"
data-bs-toggle="tooltip"><!-- Download SVG icon from http://tabler-icons.io/i/eye -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-eye-off">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10.585 10.587a2 2 0 0 0 2.829 2.828" />
<path
d="M16.681 16.673a8.717 8.717 0 0 1 -4.681 1.327c-3.6 0 -6.6 -2 -9 -6c1.272 -2.12 2.712 -3.678 4.32 -4.674m2.86 -1.146a9.055 9.055 0 0 1 1.82 -.18c3.6 0 6.6 2 9 6c-.666 1.11 -1.379 2.067 -2.138 2.87" />
<path d="M3 3l18 18" />
</svg>
</a>
</span>
<div id="pass_err" class="invalid-feedback">不能为空</div>
</div>
</div>
<div class="mb-2">
<label class="form-check">
<input id="keep_login" type="checkbox" class="form-check-input" />
<span class="form-check-label">保持登录</span>
</label>
</div>
<div class="form-footer">
<button onclick="sign_in()" class="btn btn-primary w-100">登录</button>
</div>
</div>
</div>
<div class="text-center text-secondary mt-3">
还没账号?
<a href="/sign-up/" tabindex="-1">点击注册</a>
<span class="form-label-description">
<a href="./forgot-password.html">忘记密码?</a>
</span>
</div>
</div>
</div>
<div class="col-lg d-none d-lg-block">
<img src="/static/illustrations/undraw_secure_login_pdn4.svg" height="300" class="d-block mx-auto" alt="">
</div>
</div>
</div>
{{template "footer.html"}}
</div>
<!-- Libs JS -->
</body>
</html>
<script>
var username_dom = document.getElementById('username');
var password_dom = document.getElementById('password');
var keep_login_dom = document.getElementById('keep_login');
var show_password_dom = document.getElementById('show_pass');
var show_password_no_dom = document.getElementById('show_pass_no');
show_password_dom.addEventListener('click', function () {
password_dom.type = "text";
show_password_dom.classList.add("d-none")
show_password_no_dom.classList.remove("d-none");
})
show_password_no_dom.addEventListener('click', function () {
password_dom.type = "password";
show_password_no_dom.classList.add("d-none")
show_password_dom.classList.remove("d-none");
})
username_dom.addEventListener('input', function () {
if (username_dom.value != "") {
username_dom.classList.remove("is-invalid");
}
})
password_dom.addEventListener('input', function () {
if (password_dom.value != "") {
password_dom.classList.remove("is-invalid");
}
})
function sign_in() {
var from_data_check = true;
if (username_dom.value == "") {
username_dom.classList.add("is-invalid");
username_dom.placeholder = "不能为空";
from_data_check = false;
} else {
username_dom.classList.remove("is-invalid");
}
if (password_dom.value == "") {
password_dom.classList.add("is-invalid");
password_dom.placeholder = "不能为空";
from_data_check = false;
} else {
password_dom.classList.remove("is-invalid");
}
if (from_data_check) {
const url = '/api/v1/user/login';
const sumt_data = {
username: username_dom.value,
userpass: password_dom.value,
keep_login: keep_login_dom.checked
};
try {
const response = axios.post(url, sumt_data, {
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
console.log('提交成功:', response.data); // 正确打印服务器数据
//跳转到主页
if (response.data.err_code == 0) {
location.href = '/'
} else {
password_dom.classList.add("is-invalid");
document.getElementById("pass_err").innerHTML = "账号或密码错误";
}
});
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码(如 4xx, 5xx)
console.error('服务器错误:', error.response.data);
} else {
console.error('请求未完成:', error.message);
}
}
}
}
</script>
+254
View File
@@ -0,0 +1,254 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>新用户注册</title>
</head>
<body class=" d-flex flex-column">
<div class="page page-center">
{{template "header-min.html" .}}
<div class="container container-tight py-4">
<div class="text-center mb-4">
<a href="." class="navbar-brand navbar-brand-autodark">
<img src="/static/logo.svg" width="110" height="32" alt="Tabler" class="navbar-brand-image">
</a>
</div>
<div class="card card-md" action="" method="" autocomplete="off" novalidate>
<div class="card-body">
<h2 class="card-title text-center mb-4">创建新用户</h2>
<div class="mb-3">
<label class="form-label">用户名</label>
<input id="username" type="text" class="form-control" placeholder="输入用户名" maxlength="25">
<div id="name_input_err" class="invalid-feedback">不能为空</div>
</div>
<div class="mb-3">
<label class="form-label">邮箱地址</label>
<input id="email" type="email" class="form-control" placeholder="输入电子邮箱" maxlength="64">
<div id="email_input_err" class="invalid-feedback">不能为空</div>
</div>
<div class="mb-3">
<label class="form-label">密码</label>
<div class="input-group input-group-flat">
<input id="password" type="password" class="form-control" placeholder="输入密码" autocomplete="off">
<span class="input-group-text">
<a id="show_pass" class="link-secondary " title="显示密码"
data-bs-toggle="tooltip"><!-- Download SVG icon from http://tabler-icons.io/i/eye -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-eye">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
<path d="M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6" />
</svg>
</a>
<a id="show_pass_no" class="link-secondary d-none" title="隐藏密码"
data-bs-toggle="tooltip"><!-- Download SVG icon from http://tabler-icons.io/i/eye -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-eye-off">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10.585 10.587a2 2 0 0 0 2.829 2.828" />
<path
d="M16.681 16.673a8.717 8.717 0 0 1 -4.681 1.327c-3.6 0 -6.6 -2 -9 -6c1.272 -2.12 2.712 -3.678 4.32 -4.674m2.86 -1.146a9.055 9.055 0 0 1 1.82 -.18c3.6 0 6.6 2 9 6c-.666 1.11 -1.379 2.067 -2.138 2.87" />
<path d="M3 3l18 18" />
</svg>
</a>
</span>
<div class="invalid-feedback">不能为空</div>
</div>
</div>
<!-- <div class="mb-3">
<label class="form-check">
<input type="checkbox" class="form-check-input"/>
<span class="form-check-label">Agree the <a href="./terms-of-service.html" tabindex="-1">terms and policy</a>.</span>
</label>
</div> -->
<div class="form-footer">
<button id="sumtbutton" class="btn btn-primary w-100">创建</button>
</div>
</div>
</div>
<div class="text-center text-secondary mt-3">
已有账号? <a href="/sign-in/" tabindex="-1">点击登录</a>
</div>
</div>
{{template "footer.html"}}
</div>
<!-- Libs JS -->
<div class="modal modal-blur fade" id="modal-success" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<div class="modal-status bg-success"></div>
<div class="modal-body text-center py-4">
<!-- Download SVG icon from http://tabler-icons.io/i/circle-check -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon mb-2 text-green icon-lg" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
<path d="M9 12l2 2l4 -4" />
</svg>
<h3>用户注册成功</h3>
<div class="text-secondary">你已成功注册,请前往邮箱激活账号。或者 立即登录</div>
</div>
<div class="modal-footer">
<div class="w-100">
<div class="row">
<div class="col"><a onclick="location.href = '/'" class="btn w-100" data-bs-dismiss="modal">
返回主页
</a></div>
<div class="col"><a onclick="location.href = '/sign-in'" class="btn btn-success w-100"
data-bs-dismiss="modal">
立即登录
</a></div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
<script>
//console.log("test");
function sup() {
}
var username_dom = document.getElementById('username');
var email_dom = document.getElementById('email');
var password_dom = document.getElementById('password');
var show_password_dom = document.getElementById('show_pass');
var show_password_no_dom = document.getElementById('show_pass_no');
username_dom.addEventListener('input', function () {
if (username_dom.value != "") {
username_dom.classList.remove("is-invalid");
}
})
email_dom.addEventListener('input', function () {
if (email_dom.value != "") {
email_dom.classList.remove("is-invalid");
}
})
password_dom.addEventListener('input', function () {
if (password_dom.value != "") {
password_dom.classList.remove("is-invalid");
}
})
show_password_dom.addEventListener('click', function () {
password_dom.type = "text";
show_password_dom.classList.add("d-none")
show_password_no_dom.classList.remove("d-none");
})
show_password_no_dom.addEventListener('click', function () {
password_dom.type = "password";
show_password_no_dom.classList.add("d-none")
show_password_dom.classList.remove("d-none");
})
document.getElementById('sumtbutton').addEventListener('click', function () {
//console.log('按钮被点击了!');
var from_data_check = true;
if (username_dom.value == "") {
username_dom.classList.add("is-invalid");
username_dom.placeholder = "不能为空";
from_data_check = false;
} else {
username_dom.classList.remove("is-invalid");
}
if (email_dom.value == "") {
email_dom.classList.add("is-invalid");
email_dom.placeholder = "不能为空";
document.getElementById("email_input_err").innerHTML = "不能为空";
from_data_check = false;
} else if (!isValidEmail(email_dom.value)) {
email_dom.classList.add("is-invalid");
email_dom.placeholder = "不是邮箱";
document.getElementById("email_input_err").innerHTML = "不是邮箱";
from_data_check = false;
} else {
email_dom.classList.remove("is-invalid");
}
if (password_dom.value == "") {
password_dom.classList.add("is-invalid");
password_dom.placeholder = "不能为空";
from_data_check = false;
} else {
password_dom.classList.remove("is-invalid");
}
if (from_data_check) {
//console.log("ok");
const url = '/api/v1/user/add';
const sumt_data = {
username: username_dom.value,
useremail: email_dom.value,
userpass: password_dom.value
};
try {
const response = axios.post(url, sumt_data, {
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
console.log('提交成功:', response.data); // 正确打印服务器数据
if (response.data.err_code == 1) {
username_dom.classList.add("is-invalid");
document.getElementById("name_input_err").innerHTML = "用户名已存在";
} else if (response.data.err_code == 0) {
const myModal = new bootstrap.Modal('#modal-success');
myModal.show();
}
});
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码(如 4xx, 5xx)
console.error('服务器错误:', error.response.data);
} else {
console.error('请求未完成:', error.message);
}
}
//console.log(sumt_data);
}
});
</script>
+372
View File
@@ -0,0 +1,372 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>头像裁剪上传系统 - 完整版</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.css" rel="stylesheet">
<style>
:root {
--primary-color: #2196F3;
--error-color: #f44336;
}
body {
font-family: 'Segoe UI', sans-serif;
background: #f5f5f5;
margin: 0;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
}
.flex-wrapper {
display: flex;
gap: 30px;
margin-top: 20px;
}
/* 裁剪区域 */
.crop-section {
flex: 2;
min-width: 500px;
}
#image-wrapper {
width: 100%;
height: 500px;
background: #f8f9fa;
border: 2px dashed #ddd;
border-radius: 8px;
overflow: hidden;
}
#cropper-image {
max-width: none !important;
max-height: none !important;
}
/* 控制区域 */
.controls {
margin-top: 20px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
/* 预览区域 */
.preview-section {
flex: 1;
min-width: 300px;
}
.preview-box {
width: 250px;
height: 250px;
border-radius: 50%;
border: 3px solid var(--primary-color);
overflow: hidden;
margin: 0 auto 20px;
}
#preview-img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* 按钮样式 */
.btn {
padding: 12px 20px;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: #1976D2;
}
.btn-zoom {
background: #4CAF50;
}
/* 上传进度 */
.progress-container {
height: 8px;
background: #eee;
border-radius: 4px;
margin-top: 20px;
overflow: hidden;
display: none;
}
.progress-bar {
width: 0%;
height: 100%;
background: var(--primary-color);
transition: width 0.3s ease;
}
/* 消息提示 */
.alert {
padding: 15px;
border-radius: 6px;
margin-top: 20px;
display: none;
}
.alert-success {
background: #dff0d8;
color: #3c763d;
}
.alert-error {
background: #f2dede;
color: var(--error-color);
}
input[type="file"] {
display: none;
}
</style>
</head>
<body>
<div class="container">
<h1>专业头像裁剪系统</h1>
<div class="flex-wrapper">
<!-- 左侧裁剪区 -->
<div class="crop-section">
<div id="image-wrapper">
<img id="cropper-image"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
</div>
<!-- 控制按钮 -->
<div class="controls">
<label class="btn btn-primary">
📁 选择图片
<input type="file" id="fileInput" accept="image/*">
</label>
<button class="btn btn-primary" id="uploadBtn">🚀 上传头像</button>
<button class="btn btn-primary" id="resetBtn">🔄 重置</button>
<button class="btn btn-zoom" onclick="zoomControl(0.2)"> 放大</button>
<button class="btn btn-zoom" onclick="zoomControl(-0.2)"> 缩小</button>
<button class="btn btn-primary" onclick="rotateImage(-90)">↩️ 左旋</button>
</div>
<!-- 上传进度 -->
<div class="progress-container">
<div class="progress-bar"></div>
</div>
<!-- 消息提示 -->
<div id="message" class="alert"></div>
</div>
<!-- 右侧预览区 -->
<div class="preview-section">
<h3>实时预览 (250x250px)</h3>
<div class="preview-box">
<img id="preview-img"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
</div>
<div class="preview-stats">
<p>当前缩放: <span id="zoomValue">100%</span></p>
<p>图片尺寸: <span id="imageSize">0 x 0</span></p>
</div>
</div>
</div>
</div>
<!-- 依赖库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
<script>
let cropper;
const image = document.getElementById('cropper-image');
const message = document.getElementById('message');
let currentScale = 1;
// 初始化Cropper
function initCropper(imageSrc) {
if (cropper) {
cropper.destroy();
}
image.src = imageSrc;
cropper = new Cropper(image, {
aspectRatio: 1,
viewMode: 2,
autoCropArea: 0.8,
zoomable: true,
zoomOnWheel: true,
zoomOnTouch: true,
wheelZoomRatio: 0.1,
minCanvasWidth: 400,
minCanvasHeight: 400,
crop: updatePreview,
ready() {
updateImageInfo();
document.querySelector('.progress-container').style.display = 'none';
}
});
}
// 缩放控制
function zoomControl(ratio) {
if (!cropper) return;
currentScale = Math.min(Math.max(0.5, currentScale + ratio), 3);
cropper.zoomTo(currentScale);
updateImageInfo();
}
// 旋转控制
function rotateImage(degrees) {
if (cropper) {
cropper.rotateTo(cropper.getData().rotate + degrees);
updatePreview();
}
}
// 更新预览
function updatePreview() {
const canvas = cropper.getCroppedCanvas({
width: 250,
height: 250,
imageSmoothingQuality: 'high'
});
if (canvas) {
canvas.toBlob(blob => {
const previewUrl = URL.createObjectURL(blob);
document.getElementById('preview-img').src = previewUrl;
// 清理旧URL
setTimeout(() => URL.revokeObjectURL(previewUrl), 1000);
}, 'image/jpeg', 0.85);
}
}
// 更新图片信息
function updateImageInfo() {
if (cropper) {
const data = cropper.getData();
document.getElementById('zoomValue').textContent =
`${Math.round(currentScale * 100)}%`;
document.getElementById('imageSize').textContent =
`${Math.round(data.width)} x ${Math.round(data.height)}`;
}
}
// 文件选择事件
document.getElementById('fileInput').addEventListener('change', function (e) {
const file = e.target.files[0];
if (!file) return;
if (!file.type.startsWith('image/')) {
showMessage('⚠️ 请选择有效的图片文件', 'error');
return;
}
const reader = new FileReader();
reader.onload = () => {
initCropper(reader.result);
currentScale = 1;
};
reader.readAsDataURL(file);
});
// 上传功能
document.getElementById('uploadBtn').addEventListener('click', async () => {
const progressBar = document.querySelector('.progress-bar');
const progressContainer = document.querySelector('.progress-container');
try {
if (!cropper) {
showMessage('⚠️ 请先选择并裁剪图片', 'error');
return;
}
progressContainer.style.display = 'block';
const canvas = cropper.getCroppedCanvas({
width: 1024,
height: 1024,
imageSmoothingQuality: 'high'
});
const blob = await new Promise(resolve =>
canvas.toBlob(resolve, 'image/jpeg', 0.9)
);
const formData = new FormData();
formData.append('file', blob, `avatar_${Date.now()}.jpg`);
formData.append('meta', JSON.stringify({
width: canvas.width,
height: canvas.height,
scale: currentScale.toFixed(2)
}));
const response = await fetch('/api/v1/file/upload', {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
if (!response.ok) throw new Error(`服务器错误: ${response.status}`);
const result = await response.json();
showMessage(`✅ 上传成功!路径: ${result.path}`, 'success');
} catch (error) {
console.error('上传错误:', error);
showMessage(`❌ 上传失败: ${error.message}`, 'error');
} finally {
progressBar.style.width = '0%';
progressContainer.style.display = 'none';
}
});
// 消息提示
function showMessage(text, type = 'success') {
message.className = `alert alert-${type}`;
message.textContent = text;
message.style.display = 'block';
setTimeout(() => message.style.display = 'none', 5000);
}
// 清理资源
window.addEventListener('beforeunload', () => {
if (cropper) cropper.destroy();
document.querySelectorAll('img').forEach(img => {
if (img.src.startsWith('blob:')) URL.revokeObjectURL(img.src);
});
});
// 初始化默认图片
initCropper('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=');
</script>
</body>
</html>
+268
View File
@@ -0,0 +1,268 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>仓库</title>
</head>
<body class="d-flex flex-column">
<div class="page">
{{if .is_login}}
{{template "header-logined.html" .}}
{{else}}
{{template "header-no-login.html"}}
{{end}}
{{template "header-navigation.html"}}
<div class="page-wrapper">
<!-- Page header -->
<div class="page-header d-print-none">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<h2 class="page-title">
所有仓库
</h2>
<div class="text-secondary mt-1">第{{.this_page}}页-共{{.total_pages}}页</div>
</div>
<!-- Page title actions -->
<div class="col-auto ms-auto d-print-none">
<div class="d-flex">
<input type="search" class="form-control d-inline-block w-9 me-3" placeholder="搜索仓库">
<a href="#" class="btn btn-primary" onclick="new_warehouses_windows_dom.show()">
<!-- Download SVG icon from http://tabler-icons.io/i/plus -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 5l0 14"></path>
<path d="M5 12l14 0"></path>
</svg>
创建新仓库
</a>
</div>
</div>
</div>
</div>
</div>
<!-- Page body -->
<div class="page-body">
<div class="container-xl">
<div class="row row-cards">
{{range .Warehouses}}
<div class="col-md-6 col-lg-3">
<div class="card h-100">
<div class="card-body p-4 text-center">
<span class="avatar avatar-xl mb-3 rounded">仓库{{.ID}}</span>
<h3 class="m-0 mb-1"><a href="/warehouse/{{.ID}}">{{.Name}}</a></h3>
<div class="text-secondary">{{.Info}}</div>
</div>
<div class="d-flex">
<div class="card-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-box">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3l8 4.5l0 9l-8 4.5l-8 -4.5l0 -9l8 -4.5" />
<path d="M12 12l8 -4.5" />
<path d="M12 12l0 9" />
<path d="M12 12l-8 -4.5" />
</svg>
{{.UsedCapacity}}
</div>
<a href="/warehouse/{{.ID}}" class="card-btn"><!-- Download SVG icon from http://tabler-icons.io/i/phone -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-binoculars">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M7 16m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
<path d="M17 16m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
<path d="M16.346 9.17l-.729 -1.261c-.16 -.248 -1.056 -.203 -1.117 .091l-.177 1.38" />
<path
d="M19.761 14.813l-2.84 -5.133c-.189 -.31 -.592 -.68 -1.421 -.68c-.828 0 -1.5 .448 -1.5 1v6" />
<path d="M7.654 9.17l.729 -1.261c.16 -.249 1.056 -.203 1.117 .091l.177 1.38" />
<path d="M4.239 14.813l2.84 -5.133c.189 -.31 .592 -.68 1.421 -.68c.828 0 1.5 .448 1.5 1v6" />
<rect width="4" height="2" x="10" y="12" />
</svg>
查看</a>
</div>
</div>
</div>
{{end}}
</div>
<div class="d-flex mt-4">
<ul class="pagination ms-auto">
<li class="page-item {{if .disabled_prev_page}}disabled{{end}}">
<a class="page-link" href="{{.prev_page}}">
<!-- Download SVG icon from http://tabler-icons.io/i/chevron-left -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M15 6l-6 6l6 6"></path>
</svg>
上一页
</a>
</li>
{{range .page_range}}
<li class="page-item {{.active}}"><a class="page-link" href="{{.page_href}} ">{{.page}} </a></li>
{{end}}
<li class="page-item {{if .disabled_next_page}}disabled{{end}}">
<a class="page-link" href="{{.next_page}}">
下一页 <!-- Download SVG icon from http://tabler-icons.io/i/chevron-right -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M9 6l6 6l-6 6"></path>
</svg>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
{{template "footer.html"}}
</div>
</body>
</html>
<!-- 弹出内容 -->
<div class="modal modal-blur fade" id="new_warehouses_windows" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">创建新仓库</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row mb-3 align-items-end">
<div class="col-auto">
<a href="#" class="avatar avatar-upload rounded">
<!-- Download SVG icon from http://tabler-icons.io/i/plus -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24"
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 5l0 14" />
<path d="M5 12l14 0" />
</svg>
<span class="avatar-upload-text">添加图片</span>
</a>
</div>
<div class="col">
<label class="form-label">仓库名*</label>
<input type="text" class="form-control" id="wh_name" />
</div>
</div>
<div>
<label class="form-label">仓库说明</label>
<textarea class="form-control" id="wh_info"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn me-auto" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" onclick="creat_ware_houses_post()">创建</button>
</div>
</div>
</div>
</div>
<!-- libs -->
<script src="/dist/libs/bootstrap/dist/js/bootstrap.min.js"></script>
<script>
//新建仓库窗口
const new_warehouses_windows_dom = new bootstrap.Modal('#new_warehouses_windows');
function creat_ware_houses_post() {
var data_chack = false;
//检测数据合法性
if ($("#wh_name").val() == "") {
//console.log("no");
data_chack = false;
} else {
data_chack = true;
}
//数据合法,推送
if (data_chack) {
const url = '/api/v1/warehouses_api/create';
const sumt_data = {
warehouses_name: $("#wh_name").val(),
warehouses_info: $("#wh_info").val()
};
try {
const response = axios.post(url, sumt_data, {
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
console.log('提交成功:', response.data); // 正确打印服务器数据
//跳转到主页
if (response.data.err_code == 0) {
new_warehouses_windows_dom.hide();
location.reload();
}
});
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码(如 4xx, 5xx)
console.error('服务器错误:', error.response.data);
} else {
console.error('请求未完成:', error.message);
}
}
}
}
</script>
+295
View File
@@ -0,0 +1,295 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>仓库-{{.warehouse_id}}</title>
</head>
<body class="d-flex flex-column">
<div class="page">
{{if .is_login}}
{{template "header-logined.html" .}}
{{else}}
{{template "header-no-login.html"}}
{{end}}
{{template "header-navigation.html"}}
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">物件清单</h3>
</div>
<div class="card-body border-bottom py-3">
<div class="d-flex">
<div class="text-secondary">
显示
<div class="mx-2 d-inline-block">
<input type="text" class="form-control form-control-sm" value="8" size="3"
aria-label="Invoices count">
</div>
个物件
</div>
<div class="ms-auto text-secondary d-flex">
<input type="search" class="form-control d-inline-block w-9 me-3" placeholder="搜索物件">
<a href="#" class="btn btn-primary" onclick="new_warehouses_item_windows_dom.show()">
<!-- Download SVG icon from http://tabler-icons.io/i/plus -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 5l0 14"></path>
<path d="M5 12l14 0"></path>
</svg>
添加物件
</a>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table card-table table-vcenter text-nowrap datatable">
<thead>
<tr>
<th class="w-1"><input class="form-check-input m-0 align-middle" type="checkbox"
aria-label="Select all invoices"></th>
<th class="w-1">ID. <!-- Download SVG icon from http://tabler-icons.io/i/chevron-up -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-sm icon-thick" width="24"
height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"
fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 15l6 -6l6 6"></path>
</svg>
</th>
<th>型号</th>
<th>序列号</th>
<th>归属</th>
<th>工单</th>
<th>最后状态</th>
<th>更新时间</th>
<th></th>
</tr>
</thead>
<tbody>
{{range .items}}
<tr>
<td><input class="form-check-input m-0 align-middle" type="checkbox"
aria-label="Select invoice"></td>
<td><span class="text-secondary">{{.ID}}</span></td>
<td><a href="invoice.html" class="text-reset" tabindex="-1">{{.Name}}</a></td>
<td>
{{.SerialNumber}}
</td>
<td>
{{.Destiny}}
</td>
<td>2</td>
<td>
<span class="badge {{.Color}} me-1"></span> {{.Status}}
</td>
<td>
{{.UpdatedAt}}
</td>
<td class="text-end">
<button class="btn ">查看</button>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<div class="card-footer d-flex align-items-center">
<p class="m-0 text-secondary">Showing <span>1</span> to <span>8</span> of <span>16</span> entries
</p>
<ul class="pagination m-0 ms-auto">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">
<!-- Download SVG icon from http://tabler-icons.io/i/chevron-left -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M15 6l-6 6l6 6"></path>
</svg>
prev
</a>
</li>
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item active"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item"><a class="page-link" href="#">4</a></li>
<li class="page-item"><a class="page-link" href="#">5</a></li>
<li class="page-item">
<a class="page-link" href="#">
next <!-- Download SVG icon from http://tabler-icons.io/i/chevron-right -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M9 6l6 6l-6 6"></path>
</svg>
</a>
</li>
</ul>
</div>
</div>
</div>
{{template "footer.html"}}
</div>
</body>
</html>
<!-- 弹出内容 -->
<div class="modal modal-blur fade" id="new_warehouses_item_windows" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">添加物件</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row mb-3 align-items-end">
<div class="col-auto">
<a href="#" class="avatar avatar-upload rounded">
<!-- Download SVG icon from http://tabler-icons.io/i/plus -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 5l0 14" />
<path d="M5 12l14 0" />
</svg>
<span class="avatar-upload-text">添加图片</span>
</a>
</div>
<div class="col">
<label class="form-label">物件名*</label>
<input type="text" class="form-control" maxlength="128" id="item_name" />
</div>
<div class="col">
<label class="form-label">序列号</label>
<input type="text" class="form-control" maxlength="100" id="item_sn" />
</div>
</div>
<div class="mb-2">
<label class="form-label">物件说明</label>
<textarea class="form-control" id="item_info"></textarea>
</div>
<div class="row mb-3 align-items-end">
<div class="col">
<label class="form-label">物件归属</label>
<input type="text" class="form-control" maxlength="100" id="item_who" />
</div>
<div class="col">
<label class="form-label">物件数量</label>
<input type="number" class="form-control" id="item_int" />
</div>
<div class="col">
<label class="form-label">物件价值</label>
<input type="number" step="0.01" class="form-control" id="item_consts" />
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn me-auto" data-bs-dismiss="modal"
onclick="new_warehouses_item_windows_dom.hide()">取消</button>
<button type="button" class="btn btn-primary" onclick="add_item()">创建</button>
</div>
</div>
</div>
</div>
<!-- libs -->
<script src="/dist/libs/bootstrap/dist/js/bootstrap.min.js"></script>
<script>
var items;
function add_item() {
var data_chack = true;
//检测数据合法性
if ($("#item_name").val() == "") {
//console.log("no");
data_chack = false;
$("#item_name").addClass("is-invalid")
}
if (data_chack) {
const url = '/api/v1/warehouses_api/add_item';
const sumt_data = {
warehouse_id: parseInt("{{.warehouse_id}}", 10),
item_name: $("#item_name").val(),
item_sn: $("#item_sn").val(),
item_info: $("#item_info").val(),
item_who: $("#item_who").val(),
item_int: parseInt($("#item_int").val(), 10),
item_consts: parseFloat($("#item_consts").val()),
};
try {
const response = axios.post(url, sumt_data, {
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
console.log('提交成功:', response.data); // 正确打印服务器数据
if (response.data.err_code == 0) {
new_warehouses_item_windows_dom.hide();
location.reload();
}
});
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码(如 4xx, 5xx)
console.error('服务器错误:', error.response.data);
} else {
console.error('请求未完成:', error.message);
}
}
}
}
//新建仓库窗口
const new_warehouses_item_windows_dom = new bootstrap.Modal('#new_warehouses_item_windows');
//输入的时候清除输入框的异常状态
$("#item_name").on('input', function () {
$("#item_name").removeClass("is-invalid")
})
</script>
+152
View File
@@ -0,0 +1,152 @@
<!doctype html>
<!--
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
* @version 1.0.0-beta20
* @link https://tabler.io
* Copyright 2018-2023 The Tabler Authors
* Copyright 2018-2023 codecalm.net Paweł Kuna
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>工单列表</title>
</head>
<body class="d-flex flex-column">
<div class="page">
{{if .is_login}}
{{template "header-logined.html" .}}
{{else}}
{{template "header-no-login.html"}}
{{end}}
{{template "header-navigation.html"}}
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">工单列表</h3>
</div>
<div class="card-body border-bottom py-3">
<div class="d-flex">
<div class="text-secondary">
显示
<div class="mx-2 d-inline-block">
<input type="text" class="form-control form-control-sm" value="8" size="3"
aria-label="Invoices count">
</div>
个工单
</div>
<div class="ms-auto text-secondary d-flex">
<input type="search" class="form-control d-inline-block w-9 me-3" placeholder="搜索工单">
</div>
</div>
</div>
<div class="table-responsive">
<table class="table card-table table-vcenter text-nowrap datatable">
<thead>
<tr>
<th class="w-1"><input class="form-check-input m-0 align-middle" type="checkbox"
aria-label="Select all invoices"></th>
<th class="w-1">ID. <!-- Download SVG icon from http://tabler-icons.io/i/chevron-up -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-sm icon-thick" width="24"
height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"
fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 15l6 -6l6 6"></path>
</svg>
</th>
<th>标题</th>
<th>简报</th>
<th>归属</th>
<th>评论</th>
<th>最后状态</th>
<th>更新时间</th>
<th></th>
</tr>
</thead>
<tbody>
{{range .items}}
<tr>
<td><input class="form-check-input m-0 align-middle" type="checkbox"
aria-label="Select invoice"></td>
<td><span class="text-secondary">{{.ID}}</span></td>
<td><a href="invoice.html" class="text-reset" tabindex="-1">{{.Name}}</a></td>
<td>
{{.SerialNumber}}
</td>
<td>
{{.Destiny}}
</td>
<td>2</td>
<td>
<span class="badge {{.Color}} me-1"></span> {{.Status}}
</td>
<td>
{{.UpdatedAt}}
</td>
<td class="text-end">
<button class="btn ">查看</button>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<div class="card-footer d-flex align-items-center">
<p class="m-0 text-secondary">Showing <span>1</span> to <span>8</span> of <span>16</span> entries
</p>
<ul class="pagination m-0 ms-auto">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">
<!-- Download SVG icon from http://tabler-icons.io/i/chevron-left -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M15 6l-6 6l6 6"></path>
</svg>
prev
</a>
</li>
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item active"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item"><a class="page-link" href="#">4</a></li>
<li class="page-item"><a class="page-link" href="#">5</a></li>
<li class="page-item">
<a class="page-link" href="#">
next <!-- Download SVG icon from http://tabler-icons.io/i/chevron-right -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M9 6l6 6l-6 6"></path>
</svg>
</a>
</li>
</ul>
</div>
</div>
</div>
{{template "footer.html"}}
</div>
</body>
</html>