Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d175777d75 | ||
|
|
0256f4e7f3 | ||
|
|
9ccab93c5b |
@@ -97,7 +97,7 @@ Page({
|
|||||||
const termTime = dayInfo.solarTerm ? (SOLAR_TERM_TIMES[dayInfo.solarTerm] || '') : '';
|
const termTime = dayInfo.solarTerm ? (SOLAR_TERM_TIMES[dayInfo.solarTerm] || '') : '';
|
||||||
const isFirstOrFifteen = this.data.highlightLunar && (dayInfo.lunarDay === 1 || dayInfo.lunarDay === 15);
|
const isFirstOrFifteen = this.data.highlightLunar && (dayInfo.lunarDay === 1 || dayInfo.lunarDay === 15);
|
||||||
const nextBuddhist = this.data.showBuddhist ? getNextBuddhistFestival(y, m, d) : null;
|
const nextBuddhist = this.data.showBuddhist ? getNextBuddhistFestival(y, m, d) : null;
|
||||||
const upcoming = getUpcomingFestivals(5, y, m, d);
|
const upcoming = getUpcomingFestivals(10, y, m, d);
|
||||||
return {
|
return {
|
||||||
key: fmt(y, m, d),
|
key: fmt(y, m, d),
|
||||||
dayInfo, almanac, legalHoliday, workday, termTime,
|
dayInfo, almanac, legalHoliday, workday, termTime,
|
||||||
|
|||||||
@@ -123,14 +123,14 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 节日速查(默认显示3条,点击查看更多) -->
|
<!-- 节日速查(显示最近10条,点击查看更多) -->
|
||||||
<view class="card">
|
<view class="card">
|
||||||
<view class="fest-head">
|
<view class="fest-head">
|
||||||
<text class="section-title">节日速查</text>
|
<text class="section-title">节日速查</text>
|
||||||
<text class="fest-more" bindtap="openZoom" data-type="fest-year" data-date="{{dayItem.key}}">更多 >></text>
|
<text class="fest-more" bindtap="openZoom" data-type="fest-year" data-date="{{dayItem.key}}">更多 >></text>
|
||||||
</view>
|
</view>
|
||||||
<view class="fest-quick" wx:if="{{dayItem.upcoming.length > 0}}">
|
<view class="fest-quick" wx:if="{{dayItem.upcoming && dayItem.upcoming.length > 0}}">
|
||||||
<view class="fest-quick-item" wx:for="{{dayItem.upcoming.slice(0, 3)}}" wx:key="name" catchtap="goFestival" data-date="{{item.solarDate}}">
|
<view class="fest-quick-item" wx:for="{{dayItem.upcoming}}" wx:key="name" catchtap="goFestival" data-date="{{item.solarDate}}">
|
||||||
<text class="fest-name">{{item.name}}</text>
|
<text class="fest-name">{{item.name}}</text>
|
||||||
<text class="fest-date">{{item.solarMonth}}月{{item.solarDay}}日</text>
|
<text class="fest-date">{{item.solarMonth}}月{{item.solarDay}}日</text>
|
||||||
<text class="fest-left {{item.daysLeft === 0 ? 'is-today' : ''}}">{{item.daysLeft === 0 ? '今天' : item.daysLeft + '天后'}}</text>
|
<text class="fest-left {{item.daysLeft === 0 ? 'is-today' : ''}}">{{item.daysLeft === 0 ? '今天' : item.daysLeft + '天后'}}</text>
|
||||||
|
|||||||
@@ -491,6 +491,9 @@
|
|||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #C41E3A;
|
color: #C41E3A;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
flex-shrink: 0;
|
||||||
|
min-width: 100rpx;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fest-left.is-today {
|
.fest-left.is-today {
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ Page({
|
|||||||
// 按日期排序
|
// 按日期排序
|
||||||
terms.sort((a, b) => new Date(a.date) - new Date(b.date));
|
terms.sort((a, b) => new Date(a.date) - new Date(b.date));
|
||||||
this.setData({ terms });
|
this.setData({ terms });
|
||||||
|
},
|
||||||
|
|
||||||
onShareAppMessage() {
|
onShareAppMessage() {
|
||||||
return {
|
return {
|
||||||
title: '二十四节气 - 节气查询',
|
title: '二十四节气 - 节气查询',
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ func Auth() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AdminAuth 管理员认证中间件:要求携带 role=admin 的 JWT(Authorization 头或 HttpOnly Cookie)
|
// AdminAuth 管理员认证中间件:要求携带 role=admin 的 JWT(Authorization 头或 HttpOnly Cookie)
|
||||||
|
// 浏览器导航(GET 页面请求)未登录时渲染登录页;API 请求未登录时返回 401 JSON
|
||||||
func AdminAuth() gin.HandlerFunc {
|
func AdminAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
tokenString := ""
|
tokenString := ""
|
||||||
@@ -115,18 +116,24 @@ func AdminAuth() gin.HandlerFunc {
|
|||||||
tokenString, _ = c.Cookie(service.AdminTokenCookie)
|
tokenString, _ = c.Cookie(service.AdminTokenCookie)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tokenString == "" {
|
authed := false
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{
|
if tokenString != "" {
|
||||||
"code": 401,
|
cfg := config.Load()
|
||||||
"msg": "需要管理员权限",
|
userService := service.NewUserService()
|
||||||
})
|
authed = userService.IsAdminToken(tokenString, cfg.JWT.Secret)
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := config.Load()
|
if !authed {
|
||||||
userService := service.NewUserService()
|
// 页面导航(GET 且非 /admin/api/):返回登录页
|
||||||
if !userService.IsAdminToken(tokenString, cfg.JWT.Secret) {
|
if c.Request.Method == http.MethodGet && !strings.HasPrefix(c.Request.URL.Path, "/admin/api/") {
|
||||||
|
c.HTML(http.StatusOK, "index.html", gin.H{
|
||||||
|
"title": "管理员登录",
|
||||||
|
"page": "login",
|
||||||
|
"url": c.Request.URL.Path,
|
||||||
|
})
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{
|
c.JSON(http.StatusUnauthorized, gin.H{
|
||||||
"code": 401,
|
"code": 401,
|
||||||
"msg": "需要管理员权限",
|
"msg": "需要管理员权限",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
createInertiaApp({
|
createInertiaApp({
|
||||||
resolve: name => {
|
resolve: name => {
|
||||||
const pages = {
|
const pages = {
|
||||||
|
login: () => import('/static/js/pages/Login.js'),
|
||||||
dashboard: () => import('/static/js/pages/Dashboard.js'),
|
dashboard: () => import('/static/js/pages/Dashboard.js'),
|
||||||
users: () => import('/static/js/pages/Users.js'),
|
users: () => import('/static/js/pages/Users.js'),
|
||||||
orders: () => import('/static/js/pages/Orders.js'),
|
orders: () => import('/static/js/pages/Orders.js'),
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// Login 管理员登录页
|
||||||
|
export default {
|
||||||
|
template: `
|
||||||
|
<div class="min-h-screen bg-gray-100 flex items-center justify-center px-4">
|
||||||
|
<div class="max-w-sm w-full bg-white rounded-lg shadow-md p-8">
|
||||||
|
<div class="text-center mb-6">
|
||||||
|
<h1 class="text-2xl font-bold text-red-600">祈福小助手</h1>
|
||||||
|
<p class="text-gray-500 text-sm mt-1">管理后台登录</p>
|
||||||
|
</div>
|
||||||
|
<form @submit.prevent="submit">
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">管理密码</label>
|
||||||
|
<input
|
||||||
|
v-model="password"
|
||||||
|
type="password"
|
||||||
|
autocomplete="current-password"
|
||||||
|
placeholder="请输入 ADMIN_PASSWORD"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent"
|
||||||
|
:disabled="loading"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="error" class="mb-4 text-sm text-red-600">{{ error }}</div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
:disabled="loading || !password"
|
||||||
|
class="w-full bg-red-600 text-white py-2 rounded-md hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed transition"
|
||||||
|
>
|
||||||
|
{{ loading ? '登录中...' : '登 录' }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
password: '',
|
||||||
|
loading: false,
|
||||||
|
error: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async submit() {
|
||||||
|
if (!this.password || this.loading) return;
|
||||||
|
this.loading = true;
|
||||||
|
this.error = '';
|
||||||
|
try {
|
||||||
|
const res = await fetch('/admin/login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ password: this.password })
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.code === 0) {
|
||||||
|
// Cookie 已由服务端写入,跳回原本要访问的页面
|
||||||
|
window.location.href = window.location.pathname === '/admin/login'
|
||||||
|
? '/admin/'
|
||||||
|
: window.location.pathname;
|
||||||
|
} else {
|
||||||
|
this.error = data.msg || '登录失败';
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.error = '网络错误,请重试';
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user