mistpe commited on
Commit
b2947f6
1 Parent(s): 2fd4cb4

Upload index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +311 -0
templates/index.html ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>电影信息管理系统</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
8
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
10
+ </head>
11
+ <body class="bg-gray-100">
12
+ <div class="container mx-auto px-4 py-8">
13
+ <h1 class="text-4xl font-bold mb-8 text-center text-blue-600">电影信息管理系统</h1>
14
+
15
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
16
+ <div class="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow duration-300">
17
+ <h2 class="text-xl font-semibold mb-4 text-blue-500">评分最高的电影</h2>
18
+ <div id="highest-rated-movie" class="text-gray-700"></div>
19
+ </div>
20
+
21
+ <div class="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow duration-300">
22
+ <h2 class="text-xl font-semibold mb-4 text-blue-500">票房最高的电影</h2>
23
+ <div id="highest-grossing-movie" class="text-gray-700"></div>
24
+ </div>
25
+
26
+ <div class="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow duration-300">
27
+ <h2 class="text-xl font-semibold mb-4 text-blue-500">电影年份分布</h2>
28
+ <canvas id="movies-by-year-chart"></canvas>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="bg-white rounded-lg shadow-md p-6 mb-8 hover:shadow-lg transition-shadow duration-300">
33
+ <h2 class="text-2xl font-semibold mb-4 text-blue-500">电影数据分析</h2>
34
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
35
+ <div class="flex flex-col items-center">
36
+ <h3 class="text-lg font-semibold mb-2 text-gray-700">类型分布</h3>
37
+ <div style="width: 300px; height: 300px;">
38
+ <canvas id="genre-distribution-chart"></canvas>
39
+ </div>
40
+ </div>
41
+ <div class="flex flex-col items-center">
42
+ <h3 class="text-lg font-semibold mb-2 text-gray-700">评分与票房关系</h3>
43
+ <div style="width: 600px; height: 300px;">
44
+ <canvas id="rating-boxoffice-chart"></canvas>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="bg-white rounded-lg shadow-md p-6 mb-8 hover:shadow-lg transition-shadow duration-300">
51
+ <h2 class="text-2xl font-semibold mb-4 text-blue-500">电影搜索和筛选</h2>
52
+ <div class="flex flex-wrap gap-4 mb-4">
53
+ <input id="search-input" type="text" placeholder="搜索电影..." class="p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-400">
54
+ <select id="genre-filter" class="p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-400">
55
+ <option value="">所有类型</option>
56
+ </select>
57
+ <select id="year-filter" class="p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-400">
58
+ <option value="">所有年份</option>
59
+ </select>
60
+ <select id="language-filter" class="p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-400">
61
+ <option value="">所有语言</option>
62
+ </select>
63
+ <select id="sort-by" class="p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-400">
64
+ <option value="year">年份</option>
65
+ <option value="rating">评分</option>
66
+ <option value="box_office">票房</option>
67
+ </select>
68
+ <select id="sort-order" class="p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-400">
69
+ <option value="desc">降序</option>
70
+ <option value="asc">升序</option>
71
+ </select>
72
+ <button id="apply-filters" class="bg-blue-500 text-white p-2 rounded hover:bg-blue-600 transition-colors duration-300">应用筛选</button>
73
+ </div>
74
+ </div>
75
+
76
+ <div class="mt-8">
77
+ <h2 class="text-2xl font-semibold mb-4 text-blue-500">电影列表</h2>
78
+ <div id="movie-list" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"></div>
79
+ </div>
80
+ </div>
81
+
82
+ <script>
83
+ let allMovies = [];
84
+
85
+ async function fetchData() {
86
+ try {
87
+ const [movies, highestRated, highestGrossing, genres, languages] = await Promise.all([
88
+ axios.get('/api/movies'),
89
+ axios.get('/api/highest-rated'),
90
+ axios.get('/api/highest-grossing'),
91
+ axios.get('/api/genres'),
92
+ axios.get('/api/languages')
93
+ ]);
94
+
95
+ allMovies = movies.data;
96
+ displayHighestRated(highestRated.data);
97
+ displayHighestGrossing(highestGrossing.data);
98
+ displayMoviesByYearChart(allMovies);
99
+ displayGenreDistributionChart(allMovies);
100
+ displayRatingBoxOfficeChart(allMovies);
101
+ populateFilters(genres.data, languages.data);
102
+ displayAllMovies(allMovies);
103
+ } catch (error) {
104
+ console.error('Error fetching data:', error);
105
+ alert('加载数据时出错,请刷新页面重试。');
106
+ }
107
+ }
108
+
109
+ function displayHighestRated(movie) {
110
+ document.getElementById('highest-rated-movie').innerHTML = `
111
+ <p class="font-semibold">${movie.title} (${movie.year}年)</p>
112
+ <p>评分: ${movie.rating}</p>
113
+ <p>导演: ${movie.director}</p>
114
+ `;
115
+ }
116
+
117
+ function displayHighestGrossing(movie) {
118
+ document.getElementById('highest-grossing-movie').innerHTML = `
119
+ <p class="font-semibold">${movie.title} (${movie.year}年)</p>
120
+ <p>票房: ${movie.box_office}百万美元</p>
121
+ <p>导演: ${movie.director}</p>
122
+ `;
123
+ }
124
+
125
+ function displayMoviesByYearChart(movies) {
126
+ const years = movies.map(movie => movie.year);
127
+ const counts = {};
128
+ years.forEach(year => counts[year] = (counts[year] || 0) + 1);
129
+
130
+ const ctx = document.getElementById('movies-by-year-chart').getContext('2d');
131
+ new Chart(ctx, {
132
+ type: 'bar',
133
+ data: {
134
+ labels: Object.keys(counts).sort(),
135
+ datasets: [{
136
+ label: '电影数量',
137
+ data: Object.keys(counts).sort().map(year => counts[year]),
138
+ backgroundColor: 'rgba(59, 130, 246, 0.6)'
139
+ }]
140
+ },
141
+ options: {
142
+ scales: {
143
+ y: {
144
+ beginAtZero: true,
145
+ ticks: {
146
+ stepSize: 1
147
+ }
148
+ }
149
+ }
150
+ }
151
+ });
152
+ }
153
+
154
+ function displayGenreDistributionChart(movies) {
155
+ const genres = movies.map(movie => movie.genre);
156
+ const counts = {};
157
+ genres.forEach(genre => counts[genre] = (counts[genre] || 0) + 1);
158
+
159
+ const ctx = document.getElementById('genre-distribution-chart').getContext('2d');
160
+ new Chart(ctx, {
161
+ type: 'pie',
162
+ data: {
163
+ labels: Object.keys(counts),
164
+ datasets: [{
165
+ data: Object.values(counts),
166
+ backgroundColor: [
167
+ '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF',
168
+ '#FF9F40', '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0'
169
+ ]
170
+ }]
171
+ },
172
+ options: {
173
+ responsive: true,
174
+ maintainAspectRatio: false,
175
+ plugins: {
176
+ legend: {
177
+ position: 'right',
178
+ labels: {
179
+ boxWidth: 12
180
+ }
181
+ }
182
+ }
183
+ }
184
+ });
185
+ }
186
+
187
+ function displayRatingBoxOfficeChart(movies) {
188
+ const ctx = document.getElementById('rating-boxoffice-chart').getContext('2d');
189
+ new Chart(ctx, {
190
+ type: 'scatter',
191
+ data: {
192
+ datasets: [{
193
+ label: '评分 vs 票房',
194
+ data: movies.map(movie => ({
195
+ x: movie.rating,
196
+ y: movie.box_office
197
+ })),
198
+ backgroundColor: 'rgba(59, 130, 246, 0.6)'
199
+ }]
200
+ },
201
+ options: {
202
+ responsive: true,
203
+ maintainAspectRatio: false,
204
+ scales: {
205
+ x: {
206
+ title: {
207
+ display: true,
208
+ text: '评分'
209
+ },
210
+ min: 5,
211
+ max: 10
212
+ },
213
+ y: {
214
+ title: {
215
+ display: true,
216
+ text: '票房 (百万美元)'
217
+ },
218
+ min: 0
219
+ }
220
+ }
221
+ }
222
+ });
223
+ }
224
+
225
+ function populateFilters(genres, languages) {
226
+ const yearFilter = document.getElementById('year-filter');
227
+ const genreFilter = document.getElementById('genre-filter');
228
+ const languageFilter = document.getElementById('language-filter');
229
+
230
+ const years = [...new Set(allMovies.map(movie => movie.year))].sort((a, b) => b - a);
231
+ years.forEach(year => {
232
+ const option = document.createElement('option');
233
+ option.value = year;
234
+ option.textContent = year;
235
+ yearFilter.appendChild(option);
236
+ });
237
+ genres.forEach(genre => {
238
+ const option = document.createElement('option');
239
+ option.value = genre;
240
+ option.textContent = genre;
241
+ genreFilter.appendChild(option);
242
+ });
243
+
244
+ languages.forEach(language => {
245
+ const option = document.createElement('option');
246
+ option.value = language;
247
+ option.textContent = language;
248
+ languageFilter.appendChild(option);
249
+ });
250
+ }
251
+
252
+ function displayAllMovies(movies) {
253
+ const movieList = document.getElementById('movie-list');
254
+ movieList.innerHTML = movies.map(movie => `
255
+ <div class="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow duration-300">
256
+ <h3 class="text-lg font-semibold mb-2 text-blue-500">${movie.title} (${movie.year}年)</h3>
257
+ <p><span class="font-semibold">导演:</span> ${movie.director}</p>
258
+ <p><span class="font-semibold">类型:</span> ${movie.genre}</p>
259
+ <p><span class="font-semibold">评分:</span> ${movie.rating}</p>
260
+ <p><span class="font-semibold">时长:</span> ${movie.duration}分钟</p>
261
+ <p><span class="font-semibold">票房:</span> ${movie.box_office}百万美元</p>
262
+ <p><span class="font-semibold">语言:</span> ${movie.language}</p>
263
+ </div>
264
+ `).join('');
265
+ }
266
+
267
+ async function applyFilters() {
268
+ const searchQuery = document.getElementById('search-input').value;
269
+ const genre = document.getElementById('genre-filter').value;
270
+ const year = document.getElementById('year-filter').value;
271
+ const language = document.getElementById('language-filter').value;
272
+ const sortBy = document.getElementById('sort-by').value;
273
+ const sortOrder = document.getElementById('sort-order').value;
274
+
275
+ try {
276
+ const response = await axios.get('/api/movies/filter', {
277
+ params: { genre, year, language }
278
+ });
279
+
280
+ let filteredMovies = response.data;
281
+
282
+ if (searchQuery) {
283
+ filteredMovies = filteredMovies.filter(movie =>
284
+ movie.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
285
+ movie.director.toLowerCase().includes(searchQuery.toLowerCase())
286
+ );
287
+ }
288
+
289
+ filteredMovies.sort((a, b) => {
290
+ const valueA = a[sortBy];
291
+ const valueB = b[sortBy];
292
+ if (sortOrder === 'asc') {
293
+ return valueA > valueB ? 1 : -1;
294
+ } else {
295
+ return valueA < valueB ? 1 : -1;
296
+ }
297
+ });
298
+
299
+ displayAllMovies(filteredMovies);
300
+ } catch (error) {
301
+ console.error('Error applying filters:', error);
302
+ alert('应用筛选时出错,请重试。');
303
+ }
304
+ }
305
+
306
+ document.getElementById('apply-filters').addEventListener('click', applyFilters);
307
+
308
+ fetchData();
309
+ </script>
310
+ </body>
311
+ </html>