geqintan commited on
Commit
c16f98d
·
1 Parent(s): 8d7d15e
static/admin.html CHANGED
@@ -13,7 +13,53 @@
13
  </head>
14
  <body>
15
  <div id="app">
16
- <div v-html="adminNavbar"></div> <!-- 引入共享导航栏 -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  <div class="container mt-5 pt-5">
19
  <h2 class="mb-4">后台管理</h2>
@@ -31,3 +77,5 @@
31
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
32
  <!-- Custom Vue.js App Logic -->
33
  <script type="module" src="/static/js/admin.js"></script>
 
 
 
13
  </head>
14
  <body>
15
  <div id="app">
16
+ <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
17
+ <div class="container-fluid">
18
+ <a class="navbar-brand d-flex align-items-center" href="/">
19
+ <img src="/static/images/ShareAPI.png" alt="API Router Logo" width="30" height="30" class="d-inline-block align-text-top me-2">
20
+ <span class="fw-bold fs-5">API Router</span>
21
+ </a>
22
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
23
+ <span class="navbar-toggler-icon"></span>
24
+ </button>
25
+ <div class="collapse navbar-collapse" id="navbarNav">
26
+ <ul class="navbar-nav me-auto mb-2 mb-lg-0">
27
+ <li class="nav-item">
28
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin' }" href="/admin">
29
+ <i class="fas fa-home me-1"></i> 后台首页
30
+ </a>
31
+ </li>
32
+ <li class="nav-item">
33
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin/users' }" href="/admin/users">
34
+ <i class="fas fa-users-cog me-1"></i> 用户管理
35
+ </a>
36
+ </li>
37
+ <li class="nav-item">
38
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin/pictures' }" href="/admin/pictures">
39
+ <i class="fas fa-images me-1"></i> 图片管理
40
+ </a>
41
+ </li>
42
+ </ul>
43
+ <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
44
+ <li class="nav-item dropdown" v-if="isLoggedIn">
45
+ <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">
46
+ <i class="fas fa-user me-1"></i> {{ userEmail }}
47
+ </a>
48
+ <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
49
+ <li><a class="dropdown-item" href="#" @click.prevent="handleShowChangePasswordModal">修改密码</a></li>
50
+ <li><hr class="dropdown-divider"></li>
51
+ <li><a class="dropdown-item" href="#" @click.prevent="logout">退出</a></li>
52
+ </ul>
53
+ </li>
54
+ <li class="nav-item" v-else>
55
+ <a class="nav-link d-flex align-items-center" href="/login">
56
+ <i class="fas fa-user me-1"></i> 登录
57
+ </a>
58
+ </li>
59
+ </ul>
60
+ </div>
61
+ </div>
62
+ </nav>
63
 
64
  <div class="container mt-5 pt-5">
65
  <h2 class="mb-4">后台管理</h2>
 
77
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
78
  <!-- Custom Vue.js App Logic -->
79
  <script type="module" src="/static/js/admin.js"></script>
80
+ </body>
81
+ </html>
static/admin/pictures.html CHANGED
@@ -13,7 +13,53 @@
13
  </head>
14
  <body>
15
  <div id="app">
16
- <div v-html="adminNavbar"></div> <!-- 引入共享导航栏 -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  <div class="container mt-5 pt-5">
19
  <h2 class="mb-4">图片管理</h2>
 
13
  </head>
14
  <body>
15
  <div id="app">
16
+ <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
17
+ <div class="container-fluid">
18
+ <a class="navbar-brand d-flex align-items-center" href="/">
19
+ <img src="/static/images/ShareAPI.png" alt="API Router Logo" width="30" height="30" class="d-inline-block align-text-top me-2">
20
+ <span class="fw-bold fs-5">API Router</span>
21
+ </a>
22
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
23
+ <span class="navbar-toggler-icon"></span>
24
+ </button>
25
+ <div class="collapse navbar-collapse" id="navbarNav">
26
+ <ul class="navbar-nav me-auto mb-2 mb-lg-0">
27
+ <li class="nav-item">
28
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin' }" href="/admin">
29
+ <i class="fas fa-home me-1"></i> 后台首页
30
+ </a>
31
+ </li>
32
+ <li class="nav-item">
33
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin/users' }" href="/admin/users">
34
+ <i class="fas fa-users-cog me-1"></i> 用户管理
35
+ </a>
36
+ </li>
37
+ <li class="nav-item">
38
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin/pictures' }" href="/admin/pictures">
39
+ <i class="fas fa-images me-1"></i> 图片管理
40
+ </a>
41
+ </li>
42
+ </ul>
43
+ <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
44
+ <li class="nav-item dropdown" v-if="isLoggedIn">
45
+ <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">
46
+ <i class="fas fa-user me-1"></i> {{ userEmail }}
47
+ </a>
48
+ <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
49
+ <li><a class="dropdown-item" href="#" @click.prevent="handleShowChangePasswordModal">修改密码</a></li>
50
+ <li><hr class="dropdown-divider"></li>
51
+ <li><a class="dropdown-item" href="#" @click.prevent="logout">退出</a></li>
52
+ </ul>
53
+ </li>
54
+ <li class="nav-item" v-else>
55
+ <a class="nav-link d-flex align-items-center" href="/login">
56
+ <i class="fas fa-user me-1"></i> 登录
57
+ </a>
58
+ </li>
59
+ </ul>
60
+ </div>
61
+ </div>
62
+ </nav>
63
 
64
  <div class="container mt-5 pt-5">
65
  <h2 class="mb-4">图片管理</h2>
static/admin/users.html CHANGED
@@ -13,7 +13,53 @@
13
  </head>
14
  <body>
15
  <div id="app">
16
- <div v-html="adminNavbar"></div> <!-- 引入共享导航栏 -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  <div class="container mt-5 pt-5">
19
  <h2 class="mb-4">用户管理</h2>
@@ -108,18 +154,21 @@
108
  <div class="mb-3 form-check">
109
  <input type="checkbox" class="form-check-input" id="editIsDisabled" v-model="editingUser.disabled">
110
  <label class="form-check-label" for="editIsDisabled">禁用</label>
111
- </div>
112
- <button type="submit" class="btn btn-primary" :disabled="isSavingUser">
113
- <span v-if="isSavingUser" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
114
- {{ isSavingUser ? '保存中...' : '保存更改' }}
115
- </button>
116
- </form>
 
117
  </div>
118
  </div>
119
  </div>
120
  </div>
 
 
 
121
  </div>
122
- </div>
123
 
124
  <!-- Vue 3 CDN -->
125
  <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
 
13
  </head>
14
  <body>
15
  <div id="app">
16
+ <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
17
+ <div class="container-fluid">
18
+ <a class="navbar-brand d-flex align-items-center" href="/">
19
+ <img src="/static/images/ShareAPI.png" alt="API Router Logo" width="30" height="30" class="d-inline-block align-text-top me-2">
20
+ <span class="fw-bold fs-5">API Router</span>
21
+ </a>
22
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
23
+ <span class="navbar-toggler-icon"></span>
24
+ </button>
25
+ <div class="collapse navbar-collapse" id="navbarNav">
26
+ <ul class="navbar-nav me-auto mb-2 mb-lg-0">
27
+ <li class="nav-item">
28
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin' }" href="/admin">
29
+ <i class="fas fa-home me-1"></i> 后台首页
30
+ </a>
31
+ </li>
32
+ <li class="nav-item">
33
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin/users' }" href="/admin/users">
34
+ <i class="fas fa-users-cog me-1"></i> 用户管理
35
+ </a>
36
+ </li>
37
+ <li class="nav-item">
38
+ <a class="nav-link d-flex align-items-center me-3" :class="{ active: currentPath === '/admin/pictures' }" href="/admin/pictures">
39
+ <i class="fas fa-images me-1"></i> 图片管理
40
+ </a>
41
+ </li>
42
+ </ul>
43
+ <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
44
+ <li class="nav-item dropdown" v-if="isLoggedIn">
45
+ <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">
46
+ <i class="fas fa-user me-1"></i> {{ userEmail }}
47
+ </a>
48
+ <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
49
+ <li><a class="dropdown-item" href="#" @click.prevent="handleShowChangePasswordModal">修改密码</a></li>
50
+ <li><hr class="dropdown-divider"></li>
51
+ <li><a class="dropdown-item" href="#" @click.prevent="logout">退出</a></li>
52
+ </ul>
53
+ </li>
54
+ <li class="nav-item" v-else>
55
+ <a class="nav-link d-flex align-items-center" href="/login">
56
+ <i class="fas fa-user me-1"></i> 登录
57
+ </a>
58
+ </li>
59
+ </ul>
60
+ </div>
61
+ </div>
62
+ </nav>
63
 
64
  <div class="container mt-5 pt-5">
65
  <h2 class="mb-4">用户管理</h2>
 
154
  <div class="mb-3 form-check">
155
  <input type="checkbox" class="form-check-input" id="editIsDisabled" v-model="editingUser.disabled">
156
  <label class="form-check-label" for="editIsDisabled">禁用</label>
157
+ </div>
158
+ <button type="submit" class="btn btn-primary" :disabled="isSavingUser">
159
+ <span v-if="isSavingUser" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
160
+ {{ isSavingUser ? '保存中...' : '保存更改' }}
161
+ </button>
162
+ </form>
163
+ </div>
164
  </div>
165
  </div>
166
  </div>
167
  </div>
168
+ <footer class="footer text-center py-3 mt-auto">
169
+ <p class="mb-0 text-muted">API Router v0.6.11-preview.6 由 JustSong 构建,源代码遵循 <a href="#" class="text-decoration-none">MIT 协议</a></p>
170
+ </footer>
171
  </div>
 
172
 
173
  <!-- Vue 3 CDN -->
174
  <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
static/components/admin_navbar.html CHANGED
@@ -1,32 +1,61 @@
1
- <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
2
- <div class="container-fluid">
3
- <a class="navbar-brand d-flex align-items-center" href="/">
4
- <img src="/static/images/ShareAPI.png" alt="API Router Logo" width="30" height="30" class="d-inline-block align-text-top me-2">
5
- <span class="fw-bold fs-5">API Router</span>
6
- </a>
7
- <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
8
- <span class="navbar-toggler-icon"></span>
9
- </button>
10
- <div class="collapse navbar-collapse" id="navbarNav">
11
- <ul class="navbar-nav me-auto mb-2 mb-lg-0">
12
- <li class="nav-item">
13
- <a class="nav-link d-flex align-items-center me-3" href="/admin/users">
14
- <i class="fas fa-users-cog me-1"></i> 用户管理
15
- </a>
16
- </li>
17
- <li class="nav-item">
18
- <a class="nav-link d-flex align-items-center me-3" href="/admin/pictures">
19
- <i class="fas fa-images me-1"></i> 图片管理
20
- </a>
21
- </li>
22
- </ul>
23
- <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
24
- <li class="nav-item">
25
- <a class="nav-link d-flex align-items-center" href="/login">
26
- <i class="fas fa-user me-1"></i> 登录
27
- </a>
28
- </li>
29
- </ul>
 
 
 
 
 
 
 
 
 
 
 
 
30
  </div>
31
- </div>
32
- </nav>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <template>
2
+ <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
3
+ <div class="container-fluid">
4
+ <a class="navbar-brand d-flex align-items-center" href="/">
5
+ <img src="/static/images/ShareAPI.png" alt="API Router Logo" width="30" height="30" class="d-inline-block align-text-top me-2">
6
+ <span class="fw-bold fs-5">API Router</span>
7
+ </a>
8
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
9
+ <span class="navbar-toggler-icon"></span>
10
+ </button>
11
+ <div class="collapse navbar-collapse" id="navbarNav">
12
+ <ul class="navbar-nav me-auto mb-2 mb-lg-0">
13
+ <li class="nav-item">
14
+ <a class="nav-link d-flex align-items-center me-3" href="/admin/users">
15
+ <i class="fas fa-users-cog me-1"></i> 用户管理
16
+ </a>
17
+ </li>
18
+ <li class="nav-item">
19
+ <a class="nav-link d-flex align-items-center me-3" href="/admin/pictures">
20
+ <i class="fas fa-images me-1"></i> 图片管理
21
+ </a>
22
+ </li>
23
+ </ul>
24
+ <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
25
+ <li class="nav-item dropdown" v-if="isLoggedIn">
26
+ <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">
27
+ <i class="fas fa-user me-1"></i> {{ userEmail }}
28
+ </a>
29
+ <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
30
+ <li><a class="dropdown-item" href="#" @click.prevent="emitShowChangePasswordModal">修改密码</a></li>
31
+ <li><hr class="dropdown-divider"></li>
32
+ <li><a class="dropdown-item" href="#" @click.prevent="emitLogout">退出</a></li>
33
+ </ul>
34
+ </li>
35
+ <li class="nav-item" v-else>
36
+ <a class="nav-link d-flex align-items-center" href="/login">
37
+ <i class="fas fa-user me-1"></i> 登录
38
+ </a>
39
+ </li>
40
+ </ul>
41
+ </div>
42
  </div>
43
+ </nav>
44
+ </template>
45
+
46
+ <script>
47
+ export default {
48
+ props: {
49
+ isLoggedIn: Boolean,
50
+ userEmail: String
51
+ },
52
+ methods: {
53
+ emitLogout() {
54
+ this.$emit('logout');
55
+ },
56
+ emitShowChangePasswordModal() {
57
+ this.$emit('show-change-password-modal');
58
+ }
59
+ }
60
+ }
61
+ </script>
static/js/admin.js CHANGED
@@ -5,148 +5,48 @@ const { createApp } = Vue;
5
 
6
  import { authData, authMethods, authMounted } from './auth.js';
7
  import { proxyData, proxyMethods } from './proxy.js';
8
- import { appData, appMethods, appMounted } from './store.js'; // Corrected import names
9
-
10
- const app = createApp({
 
 
 
11
  data() {
12
  return {
13
  ...authData(),
14
  ...proxyData(),
15
- ...appData(), // Corrected data spread
16
  selectedFile: null,
17
  isUploading: false,
18
  uploadMessage: '',
19
  uploadedImageUrl: '',
20
- showImageUpload: false, // 控制图片上传模块的显示 (默认不显示)
21
- showUserManagement: false, // 控制用户管理模块的显示 (已移除)
22
- showImageManagement: false, // 控制图片管理模块的显示 (已移除)
23
- images: [], // 存储图片列表 (已移除)
24
- imageMessage: '', // 图片管理模块的消息 (已移除)
25
- adminNavbar: '', // 存储 admin_navbar.html 的内容
26
-
27
- // 用户管理相关数据 (已移除,现在在 users.js 中处理)
28
- // users: [],
29
- // userSearchQuery: '',
30
- // currentPage: 1,
31
- // pageSize: 10,
32
- // totalUsers: 0,
33
- // totalPages: 0,
34
- // userMessage: '',
35
- // editingUser: {
36
- // id: null,
37
- // email: '',
38
- // password: '',
39
- // email_verified: false,
40
- // is_admin: false,
41
- // disabled: false
42
- // },
43
- // isSavingUser: false,
44
- // editUserModal: null // Bootstrap Modal instance
45
  };
46
  },
47
  methods: {
48
  ...authMethods(this),
49
  ...proxyMethods(),
50
- ...appMethods(this), // Corrected methods spread
51
  handleFileUpload(event) {
52
  this.selectedFile = event.target.files[0];
53
  },
54
- // async uploadImage() { // Moved to pictures.js
55
- // if (!this.selectedFile) {
56
- // this.uploadMessage = '请选择一个文件。';
57
- // return;
58
- // }
59
-
60
- // this.isUploading = true;
61
- // this.uploadMessage = '';
62
- // this.uploadedImageUrl = '';
63
-
64
- // const formData = new FormData();
65
- // formData.append('file', this.selectedFile);
66
-
67
- // try {
68
- // const token = localStorage.getItem('access_token');
69
- // const response = await fetch('/api/admin/upload-image', {
70
- // method: 'POST',
71
- // headers: {
72
- // 'Authorization': `Bearer ${token}`
73
- // },
74
- // body: formData
75
- // });
76
- // const data = await response.json();
77
-
78
- // if (response.ok) {
79
- // this.uploadMessage = data.message || '图片上传成功!';
80
- // this.uploadedImageUrl = data.path;
81
- // document.getElementById('imageUpload').value = '';
82
- // this.selectedFile = null;
83
- // } else {
84
- // this.uploadMessage = data.detail || '图片上传失败。';
85
- // }
86
- // } catch (error) {
87
- // this.uploadMessage = '网络错误或服务器无响应。';
88
- // console.error('图片上传错误:', error);
89
- // } finally {
90
- // this.isUploading = false;
91
- // }
92
- // },
93
- // async fetchImages() { // Moved to pictures.js
94
- // this.imageMessage = '加载图片中...';
95
- // try {
96
- // const token = localStorage.getItem('access_token');
97
- // const response = await fetch('/api/admin/images', {
98
- // headers: {
99
- // 'Authorization': `Bearer ${token}`
100
- // }
101
- // });
102
- // const data = await response.json();
103
-
104
- // if (response.ok) {
105
- // this.images = data;
106
- // this.imageMessage = '';
107
- // } else {
108
- // this.imageMessage = data.detail || '获取图片失败。';
109
- // }
110
- // } catch (error) {
111
- // this.imageMessage = '网络错误或服务器无响应。';
112
- // console.error('删除图片错误:', error);
113
- // }
114
- // },
115
- async loadAdminNavbar() {
116
- try {
117
- const response = await fetch('/static/components/admin_navbar.html');
118
- if (response.ok) {
119
- this.adminNavbar = await response.text();
120
- } else {
121
- console.error('Failed to load admin navbar:', response.statusText);
122
- }
123
- } catch (error) {
124
- console.error('Error loading admin navbar:', error);
125
- }
126
- },
127
- // Navigation methods for shared navbar
128
- navigateToUserManagement() {
129
- window.location.href = '/admin/users';
130
- },
131
- navigateToImageManagement() {
132
- window.location.href = '/admin/pictures'; // Navigate to pictures page
133
- },
134
- navigateToImageUpload() {
135
- // This method is no longer directly used as image upload is part of pictures.html
136
- window.location.href = '/admin/pictures';
137
  }
138
  },
139
  mounted() {
140
  authMounted(this);
141
  appMounted(this);
142
- this.loadAdminNavbar(); // Load the shared navbar
143
  console.log('Admin app mounted!');
144
- // No specific logic for admin.js as it only acts as a container now
145
  },
146
  watch: {
147
  // No specific watchers needed for this page
148
  }
149
- });
150
 
151
- app.mount('#app');
152
  console.log('Vue app successfully mounted to #app element.');
 
5
 
6
  import { authData, authMethods, authMounted } from './auth.js';
7
  import { proxyData, proxyMethods } from './proxy.js';
8
+ import { appData, appMethods, appMounted } from './store.js';
9
+ const AdminApp = {
10
+ components: {
11
+ // AdminNavbar // Register the component
12
+ },
13
+ // template: document.querySelector('#app template').innerHTML, // Removed template option
14
  data() {
15
  return {
16
  ...authData(),
17
  ...proxyData(),
18
+ ...appData(),
19
  selectedFile: null,
20
  isUploading: false,
21
  uploadMessage: '',
22
  uploadedImageUrl: '',
23
+ showImageUpload: false,
24
+ showUserManagement: false,
25
+ showImageManagement: false,
26
+ images: [],
27
+ imageMessage: '',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  };
29
  },
30
  methods: {
31
  ...authMethods(this),
32
  ...proxyMethods(),
33
+ ...appMethods(this),
34
  handleFileUpload(event) {
35
  this.selectedFile = event.target.files[0];
36
  },
37
+ handleShowChangePasswordModal() {
38
+ this.showChangePasswordModal = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  }
40
  },
41
  mounted() {
42
  authMounted(this);
43
  appMounted(this);
 
44
  console.log('Admin app mounted!');
 
45
  },
46
  watch: {
47
  // No specific watchers needed for this page
48
  }
49
+ };
50
 
51
+ createApp(AdminApp).mount('#app');
52
  console.log('Vue app successfully mounted to #app element.');
static/js/admin/pictures.js CHANGED
@@ -3,37 +3,30 @@ const { createApp } = Vue;
3
 
4
  import { authData, authMethods, authMounted } from '../auth.js';
5
  import { appData, appMethods, appMounted } from '../store.js';
 
6
 
7
- const app = createApp({
 
 
 
 
8
  data() {
9
  return {
10
  ...authData(),
11
  ...appData(),
12
- adminNavbar: '', // 存储 admin_navbar.html 的内容
13
 
14
  selectedFile: null,
15
  isUploading: false,
16
  uploadMessage: '',
17
  uploadedImageUrl: '',
18
- images: [], // 存储图片列表
19
- imageMessage: '', // 图片管理模块的消息
20
  };
21
  },
22
  methods: {
23
  ...authMethods(this),
24
  ...appMethods(this),
25
- async loadAdminNavbar() {
26
- try {
27
- const response = await fetch('/static/components/admin_navbar.html');
28
- if (response.ok) {
29
- this.adminNavbar = await response.text();
30
- } else {
31
- console.error('Failed to load admin navbar:', response.statusText);
32
- }
33
- } catch (error) {
34
- console.error('Error loading admin navbar:', error);
35
- }
36
- },
37
  handleFileUpload(event) {
38
  this.selectedFile = event.target.files[0];
39
  },
@@ -126,28 +119,21 @@ const app = createApp({
126
  console.error('删除图片错误:', error);
127
  }
128
  },
129
- // Navigation methods for shared navbar
130
- navigateToUserManagement() {
131
- window.location.href = '/admin/users';
132
- },
133
- navigateToImageManagement() {
134
- // Already on image management page, no need to navigate
135
- },
136
- navigateToImageUpload() {
137
- // Already on image management page, upload is part of this page
138
  }
139
  },
140
  mounted() {
141
  authMounted(this);
142
  appMounted(this);
143
- this.loadAdminNavbar(); // Load the shared navbar
144
  this.fetchImages(); // Fetch images on page load
145
  console.log('Image management app mounted!');
 
146
  },
147
  watch: {
148
  // No specific watchers needed for this standalone page yet
149
  }
150
- });
151
 
152
- app.mount('#app');
153
  console.log('Image management Vue app successfully mounted to #app element.');
 
3
 
4
  import { authData, authMethods, authMounted } from '../auth.js';
5
  import { appData, appMethods, appMounted } from '../store.js';
6
+ import AdminNavbar from '../components/AdminNavbar.js'; // Import the new component
7
 
8
+ const PictureManagementApp = {
9
+ components: {
10
+ AdminNavbar // Register the component
11
+ },
12
+ // template: document.querySelector('#app template').innerHTML, // Removed template option
13
  data() {
14
  return {
15
  ...authData(),
16
  ...appData(),
17
+ currentPath: window.location.pathname, // Add currentPath to data
18
 
19
  selectedFile: null,
20
  isUploading: false,
21
  uploadMessage: '',
22
  uploadedImageUrl: '',
23
+ images: [],
24
+ imageMessage: '',
25
  };
26
  },
27
  methods: {
28
  ...authMethods(this),
29
  ...appMethods(this),
 
 
 
 
 
 
 
 
 
 
 
 
30
  handleFileUpload(event) {
31
  this.selectedFile = event.target.files[0];
32
  },
 
119
  console.error('删除图片错误:', error);
120
  }
121
  },
122
+ handleShowChangePasswordModal() {
123
+ this.showChangePasswordModal = true;
 
 
 
 
 
 
 
124
  }
125
  },
126
  mounted() {
127
  authMounted(this);
128
  appMounted(this);
 
129
  this.fetchImages(); // Fetch images on page load
130
  console.log('Image management app mounted!');
131
+
132
  },
133
  watch: {
134
  // No specific watchers needed for this standalone page yet
135
  }
136
+ };
137
 
138
+ createApp(PictureManagementApp).mount('#app');
139
  console.log('Image management Vue app successfully mounted to #app element.');
static/js/admin/users.js CHANGED
@@ -3,13 +3,18 @@ const { createApp } = Vue;
3
 
4
  import { authData, authMethods, authMounted } from '../auth.js';
5
  import { appData, appMethods, appMounted } from '../store.js';
 
6
 
7
- const app = createApp({
 
 
 
 
8
  data() {
9
  return {
10
  ...authData(),
11
  ...appData(),
12
- adminNavbar: '', // 存储 admin_navbar.html 的内容
13
 
14
  // 用户管理相关数据
15
  users: [],
@@ -138,42 +143,23 @@ const app = createApp({
138
  console.error('删除用户错误:', error);
139
  }
140
  },
141
- async loadAdminNavbar() {
142
- try {
143
- const response = await fetch('/static/components/admin_navbar.html');
144
- if (response.ok) {
145
- this.adminNavbar = await response.text();
146
- } else {
147
- console.error('Failed to load admin navbar:', response.statusText);
148
- }
149
- } catch (error) {
150
- console.error('Error loading admin navbar:', error);
151
- }
152
- },
153
- // Navigation methods for shared navbar
154
- navigateToUserManagement() {
155
- // Already on user management page, no need to navigate
156
- },
157
- navigateToImageManagement() {
158
- window.location.href = '/admin/pictures'; // Navigate to pictures page
159
- },
160
- navigateToImageUpload() {
161
- window.location.href = '/admin/pictures'; // Navigate to pictures page
162
  }
163
  },
164
  mounted() {
165
  authMounted(this);
166
  appMounted(this);
167
- this.loadAdminNavbar(); // Load the shared navbar
168
  console.log('User management app mounted!');
169
 
170
  this.editUserModal = new bootstrap.Modal(document.getElementById('editUserModal'));
171
  this.fetchUsers(); // Fetch users on page load
 
172
  },
173
  watch: {
174
  // No specific watchers needed for this standalone page yet
175
  }
176
- });
177
 
178
- app.mount('#app');
179
  console.log('User management Vue app successfully mounted to #app element.');
 
3
 
4
  import { authData, authMethods, authMounted } from '../auth.js';
5
  import { appData, appMethods, appMounted } from '../store.js';
6
+ import AdminNavbar from '../components/AdminNavbar.js'; // Import the new component
7
 
8
+ const UserManagementApp = {
9
+ components: {
10
+ AdminNavbar // Register the component
11
+ },
12
+ // template: document.querySelector('#app template').innerHTML, // Removed template option
13
  data() {
14
  return {
15
  ...authData(),
16
  ...appData(),
17
+ currentPath: window.location.pathname, // Add currentPath to data
18
 
19
  // 用户管理相关数据
20
  users: [],
 
143
  console.error('删除用户错误:', error);
144
  }
145
  },
146
+ handleShowChangePasswordModal() {
147
+ this.showChangePasswordModal = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  }
149
  },
150
  mounted() {
151
  authMounted(this);
152
  appMounted(this);
 
153
  console.log('User management app mounted!');
154
 
155
  this.editUserModal = new bootstrap.Modal(document.getElementById('editUserModal'));
156
  this.fetchUsers(); // Fetch users on page load
157
+
158
  },
159
  watch: {
160
  // No specific watchers needed for this standalone page yet
161
  }
162
+ };
163
 
164
+ createApp(UserManagementApp).mount('#app');
165
  console.log('User management Vue app successfully mounted to #app element.');
static/js/components/AdminNavbar.js ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // static/js/components/AdminNavbar.js
2
+ export default {
3
+ template: `
4
+ <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
5
+ <div class="container-fluid">
6
+ <a class="navbar-brand d-flex align-items-center" href="/">
7
+ <img src="/static/images/ShareAPI.png" alt="API Router Logo" width="30" height="30" class="d-inline-block align-text-top me-2">
8
+ <span class="fw-bold fs-5">API Router</span>
9
+ </a>
10
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
11
+ <span class="navbar-toggler-icon"></span>
12
+ </button>
13
+ <div class="collapse navbar-collapse" id="navbarNav">
14
+ <ul class="navbar-nav me-auto mb-2 mb-lg-0">
15
+ <li class="nav-item">
16
+ <a class="nav-link d-flex align-items-center me-3" href="/admin/users">
17
+ <i class="fas fa-users-cog me-1"></i> 用户管理
18
+ </a>
19
+ </li>
20
+ <li class="nav-item">
21
+ <a class="nav-link d-flex align-items-center me-3" href="/admin/pictures">
22
+ <i class="fas fa-images me-1"></i> 图片管理
23
+ </a>
24
+ </li>
25
+ </ul>
26
+ <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
27
+ <li class="nav-item dropdown" v-if="isLoggedIn">
28
+ <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">
29
+ <i class="fas fa-user me-1"></i> {{ userEmail }}
30
+ </a>
31
+ <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
32
+ <li><a class="dropdown-item" href="#" @click.prevent="emitShowChangePasswordModal">修改密码</a></li>
33
+ <li><hr class="dropdown-divider"></li>
34
+ <li><a class="dropdown-item" href="#" @click.prevent="emitLogout">退出</a></li>
35
+ </ul>
36
+ </li>
37
+ <li class="nav-item" v-else>
38
+ <a class="nav-link d-flex align-items-center" href="/login">
39
+ <i class="fas fa-user me-1"></i> 登录
40
+ </a>
41
+ </li>
42
+ </ul>
43
+ </div>
44
+ </div>
45
+ </nav>
46
+ `,
47
+ props: {
48
+ isLoggedIn: Boolean,
49
+ userEmail: String
50
+ },
51
+ methods: {
52
+ emitLogout() {
53
+ this.$emit('logout');
54
+ },
55
+ emitShowChangePasswordModal() {
56
+ this.$emit('show-change-password-modal');
57
+ }
58
+ }
59
+ }