File size: 11,176 Bytes
8d7d15e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c16f98d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8d7d15e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c16f98d
 
 
 
 
 
 
8d7d15e
 
 
 
c16f98d
 
 
8d7d15e
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SP Website - 用户管理</title>
    <!-- Bootstrap 5.3 CSS CDN -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Font Awesome CDN for icons -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
    <!-- Custom CSS -->
    <link rel="stylesheet" href="/static/style.css">
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
            <div class="container-fluid">
                <a class="navbar-brand d-flex align-items-center" href="/">
                    <img src="/static/images/ShareAPI.png" alt="API Router Logo" width="30" height="30" class="d-inline-block align-text-top me-2">
                    <span class="fw-bold fs-5">API Router</span>
                </a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarNav">
                    <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                        <li class="nav-item">
                            <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin' }" href="/admin">
                                <i class="fas fa-home me-1"></i> 后台首页
                            </a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin/users' }" href="/admin/users">
                                <i class="fas fa-users-cog me-1"></i> 用户管理
                            </a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin/pictures' }" href="/admin/pictures">
                                <i class="fas fa-images me-1"></i> 图片管理
                            </a>
                        </li>
                    </ul>
                    <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
                        <li class="nav-item dropdown" v-if="isLoggedIn">
                            <a class="nav-link dropdown-toggle d-flex align-items-center me-3" href="#" id="userDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                                <i class="fas fa-user me-1"></i> {{ userEmail }}
                            </a>
                            <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
                                <li><a class="dropdown-item" href="#" @click.prevent="handleShowChangePasswordModal">修改密码</a></li>
                                <li><hr class="dropdown-divider"></li>
                                <li><a class="dropdown-item" href="#" @click.prevent="logout">退出</a></li>
                            </ul>
                        </li>
                        <li class="nav-item" v-else>
                            <a class="nav-link d-flex align-items-center" href="/login">
                                <i class="fas fa-user me-1"></i> 登录
                            </a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>

        <div class="container mt-5 pt-5">
            <h2 class="mb-4">用户管理</h2>

            <!-- 用户管理模块 -->
            <div class="card shadow-sm p-4 mb-4">
                <h4 class="mb-3">用户管理</h4>
                <div class="input-group mb-3">
                    <input type="text" class="form-control" placeholder="按邮箱搜索用户" v-model="userSearchQuery" @keyup.enter="fetchUsers">
                    <button class="btn btn-outline-secondary" type="button" @click="fetchUsers">搜索</button>
                </div>
                <div class="table-responsive">
                    <table class="table table-striped table-hover">
                        <thead>
                            <tr>
                                <th>ID</th>
                                <th>邮箱</th>
                                <th>已验证</th>
                                <th>管理员</th>
                                <th>禁用</th> <!-- Add new column header -->
                                <th>创建时间</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="user in users" :key="user.id">
                                <td>{{ user.id }}</td>
                                <td>{{ user.email }}</td>
                                <td>
                                    <span v-if="user.email_verified" class="badge bg-success"></span>
                                    <span v-else class="badge bg-danger"></span>
                                </td>
                                <td>
                                    <span v-if="user.is_admin" class="badge bg-primary"></span>
                                    <span v-else class="badge bg-secondary"></span>
                                </td>
                                <td>
                                    <span v-if="user.disabled" class="badge bg-warning"></span> <!-- Display disabled status -->
                                    <span v-else class="badge bg-success"></span>
                                </td>
                                <td>{{ new Date(user.created_at).toLocaleString() }}</td>
                                <td>
                                    <button class="btn btn-sm btn-info me-2" @click="editUser(user)">编辑</button>
                                    <button class="btn btn-sm btn-danger" @click="deleteUser(user.id)">删除</button>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
                <nav aria-label="User pagination" v-if="totalPages > 1">
                    <ul class="pagination justify-content-center">
                        <li class="page-item" :class="{ disabled: currentPage === 1 }">
                            <a class="page-link" href="#" @click.prevent="changePage(currentPage - 1)">上一页</a>
                        </li>
                        <li class="page-item" v-for="pageNumber in totalPages" :key="pageNumber" :class="{ active: pageNumber === currentPage }">
                            <a class="page-link" href="#" @click.prevent="changePage(pageNumber)">{{ pageNumber }}</a>
                        </li>
                        <li class="page-item" :class="{ disabled: currentPage === totalPages }">
                            <a class="page-link" href="#" @click.prevent="changePage(currentPage + 1)">下一页</a>
                        </li>
                    </ul>
                </nav>
                <p v-if="userMessage" class="mt-3 text-info">{{ userMessage }}</p>
            </div>

            <!-- 编辑用户模态框 -->
            <div class="modal fade" id="editUserModal" tabindex="-1" aria-labelledby="editUserModalLabel" aria-hidden="true">
                <div class="modal-dialog">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h5 class="modal-title" id="editUserModalLabel">编辑用户</h5>
                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                        </div>
                        <div class="modal-body">
                            <form @submit.prevent="saveUserChanges">
                                <div class="mb-3">
                                    <label for="editUserEmail" class="form-label">邮箱</label>
                                    <input type="email" class="form-control" id="editUserEmail" v-model="editingUser.email" required>
                                </div>
                                <div class="mb-3">
                                    <label for="editUserPassword" class="form-label">新密码 (留空则不修改)</label>
                                    <input type="password" class="form-control" id="editUserPassword" v-model="editingUser.password">
                                </div>
                                <div class="mb-3 form-check">
                                    <input type="checkbox" class="form-check-input" id="editEmailVerified" v-model="editingUser.email_verified">
                                    <label class="form-check-label" for="editEmailVerified">邮箱已验证</label>
                                </div>
                                <div class="mb-3 form-check">
                                    <input type="checkbox" class="form-check-input" id="editIsAdmin" v-model="editingUser.is_admin">
                                    <label class="form-check-label" for="editIsAdmin">管理员</label>
                                </div>
                                <div class="mb-3 form-check">
                                    <input type="checkbox" class="form-check-input" id="editIsDisabled" v-model="editingUser.disabled">
                                    <label class="form-check-label" for="editIsDisabled">禁用</label>
                                    </div>
                                    <button type="submit" class="btn btn-primary" :disabled="isSavingUser">
                                        <span v-if="isSavingUser" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
                                        {{ isSavingUser ? '保存中...' : '保存更改' }}
                                    </button>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <footer class="footer text-center py-3 mt-auto">
                <p class="mb-0 text-muted">API Router v0.6.11-preview.6 由 JustSong 构建,源代码遵循 <a href="#" class="text-decoration-none">MIT 协议</a></p>
            </footer>
        </div>

    <!-- Vue 3 CDN -->
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
    <!-- Bootstrap 5.3 JS CDN -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <!-- Custom Vue.js App Logic -->
    <script type="module" src="/static/js/admin/users.js"></script>
</body>
</html>