362 lines
10 KiB
HTML
362 lines
10 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>{{ movie.title }}</title>
|
||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
|
||
<script src="/static/chart.js"></script>
|
||
<style>
|
||
/* 页面基础样式 */
|
||
.body-container {
|
||
/*font-family: Arial, sans-serif;*/
|
||
background-color: #f9f9f9;
|
||
margin: 0;
|
||
padding: 20px;
|
||
}
|
||
|
||
h1 {
|
||
text-align: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* 基本容器样式 */
|
||
.container {
|
||
background-color: rgba(255, 255, 255, 0.8);
|
||
border-radius: 10px;
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.container h2, .container h3 {
|
||
margin-top: 0;
|
||
}
|
||
|
||
/* 评分分布样式 */
|
||
.rating-distribution {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.rating-distribution h2 {
|
||
font-size: 24px;
|
||
color: #333;
|
||
}
|
||
|
||
.rating-bar-container {
|
||
width: 100%;
|
||
margin-left: 20px;
|
||
}
|
||
|
||
.rating-bar-label {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.rating-bar {
|
||
height: 20px;
|
||
background-color: #4caf50;
|
||
border-radius: 5px;
|
||
margin: 5px 0;
|
||
}
|
||
|
||
/* 基础圆角矩形容器样式 */
|
||
.section-container {
|
||
background-color: rgba(255, 255, 255, 0.8);
|
||
border-radius: 10px;
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* 图表容器样式(去除圆角) */
|
||
.chart-container {
|
||
text-align: center; /* 居中对齐图表 */
|
||
}
|
||
|
||
/* 控制 canvas 尺寸 */
|
||
canvas {
|
||
width: 60%; /* 设置最大宽度为 400px */
|
||
height: auto; /* 高度自动调整 */
|
||
margin: 0 auto; /* 居中 */
|
||
display: block;
|
||
}
|
||
|
||
|
||
|
||
/* 返回按钮样式 */
|
||
/*a {*/
|
||
/* display: inline-block;*/
|
||
/* margin-top: 20px;*/
|
||
/* color: #007bff;*/
|
||
/* text-decoration: none;*/
|
||
/*}*/
|
||
|
||
/*a:hover {*/
|
||
/* text-decoration: underline;*/
|
||
/*}*/
|
||
|
||
.rating-value {
|
||
font-size: 32px; /* 字体大小 */
|
||
color: #ff5722; /* 字体颜色橙色 */
|
||
font-weight: bold; /* 加粗 */
|
||
margin-left: 5px; /* 左边距,使其与“Average Rating:”分开 */
|
||
}
|
||
|
||
.rating-value2 {
|
||
font-size: 55px;
|
||
color: red;
|
||
}
|
||
|
||
/* 设置 li 元素的基础样式 */
|
||
.section-container ul {
|
||
list-style-type: none; /* 去除默认的列表样式 */
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.section-container ul li {
|
||
font-size: 16px; /* 字体大小 */
|
||
color: #333; /* 字体颜色 */
|
||
padding: 5px 0; /* 上下间距 */
|
||
line-height: 1.5; /* 行高 */
|
||
border-bottom: 1px solid #e0e0e0; /* 底部边框,增加分隔感 */
|
||
}
|
||
|
||
.section-container ul li:last-child {
|
||
border-bottom: none; /* 去除最后一个条目的底部边框 */
|
||
}
|
||
|
||
.section-container ul li strong {
|
||
color: #4caf50; /* 将平均分的值设为绿色 */
|
||
font-weight: bold; /* 加粗 */
|
||
}
|
||
|
||
/* 电影卡片容器样式 */
|
||
.sim-container {
|
||
background-color: rgba(255, 255, 255, 0.8); /* 半透明背景 */
|
||
padding: 20px;
|
||
border-radius: 12px;
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影效果 */
|
||
margin: 20px 0;
|
||
}
|
||
|
||
/* 电影卡片样式 */
|
||
.sim-card {
|
||
width: calc(20% - 20px); /* 每行5个,包含间距 */
|
||
margin: 10px;
|
||
padding: 15px;
|
||
background-color: #fff;
|
||
border-radius: 12px;
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.sim-card:hover {
|
||
transform: translateY(-5px);
|
||
}
|
||
|
||
.sim-card h3 a {
|
||
color: #333;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.sim-card h3 a:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.sim-container .bighead {
|
||
font-size: 2.5em;
|
||
}
|
||
|
||
/* 电影卡片容器样式 */
|
||
.sim-cards-container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
padding: 20px;
|
||
gap: 10px;
|
||
}
|
||
|
||
.sim-rating {
|
||
font-weight: bold;
|
||
color: red;
|
||
}
|
||
|
||
|
||
</style>
|
||
|
||
</head>
|
||
<body>
|
||
<!-- 引入顶部栏模板 -->
|
||
{% include 'navbar.html' %}
|
||
|
||
<div class="body-container">
|
||
<h1>{{ movie.title }}</h1>
|
||
<div class="container">
|
||
<p><strong>Release Date:</strong> {{ movie.release_date }}</p>
|
||
<p><strong>Genres:</strong> {{ ", ".join(genre_names) }}</p>
|
||
<p><strong>Rating Count:</strong> {{ movie.rating_count }}</p>
|
||
<p><strong>Average Rating:</strong> <span class="rating-value">{{ movie.average_rating }}</span></p>
|
||
<p><strong>Actors:</strong> {{ movie.actor }}</p>
|
||
</div>
|
||
|
||
<!-- 用户评分分布 -->
|
||
<div class="container rating-distribution">
|
||
<div>
|
||
<h2>Average Rating: </h2><span class="rating-value2">{{ movie.average_rating }}</span>
|
||
<p>by {{ movie.rating_count }} user(s)</p>
|
||
</div>
|
||
<div class="rating-bar-container">
|
||
{% for rating in range(5, 0, -1) %}
|
||
<p class="rating-bar-label">{{ rating }} stars: {{ (rating_distribution[rating] * 100) | round(1) }}%</p>
|
||
<div class="rating-bar" style="width: {{ rating_distribution[rating] * 100 }}%;"></div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 用户喜好详细分析(仅制片人可见) -->
|
||
{% if user_type == 'P' %}
|
||
<div class="user-analysis-section">
|
||
<h2>User Preference Analysis</h2>
|
||
|
||
<!-- By Gender -->
|
||
<div class="section-container">
|
||
<h3>By Gender</h3>
|
||
<ul>
|
||
{% for gender, data in user_analysis.gender_analysis.items() %}
|
||
<li>{{ 'Male' if gender == 'M' else 'Female' }}: {{ data.average }} ({{ data.count }} ratings)</li>
|
||
{% endfor %}
|
||
</ul>
|
||
<div class="chart-container">
|
||
<canvas id="genderChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- By Age -->
|
||
<div class="section-container">
|
||
<h3>By Age</h3>
|
||
<ul>
|
||
{% for age_range, data in user_analysis.age_analysis.items() %}
|
||
<li>{{ age_range }} years: {{ data.average }} ({{ data.count }} ratings)</li>
|
||
{% endfor %}
|
||
</ul>
|
||
<div class="chart-container">
|
||
<canvas id="ageChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- By Occupation -->
|
||
<div class="section-container">
|
||
<h3>By Occupation</h3>
|
||
<ul>
|
||
{% for occupation, data in user_analysis.occupation_analysis.items() %}
|
||
<li>{{ occupation }}: {{ data.average }} ({{ data.count }} ratings)</li>
|
||
{% endfor %}
|
||
</ul>
|
||
<div class="chart-container">
|
||
<canvas id="occupationChart"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
{% endif %}
|
||
|
||
<!-- 相似电影推荐 -->
|
||
<div class="sim-container">
|
||
<h3 class="bighead">🌟More Like This</h3>
|
||
<div class="sim-cards-container">
|
||
{% for similar_movie in similar_movies %}
|
||
<div class="sim-card">
|
||
<h3><a href="{{ url_for('movies.detail', id=similar_movie.id) }}" target="_blank">{{ similar_movie.title }}</a></h3>
|
||
<p class="sim-rating">Average Rating: {{ similar_movie.average_rating }}</p>
|
||
<p>Release Date: {{ similar_movie.release_date }}</p>
|
||
<p>Genres: {{ similar_movie.genres }}</p>
|
||
<p>Rating Count: {{ similar_movie.rating_count }}</p>
|
||
<p>Actors: {{ similar_movie.actor }}</p>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- <a href="{{ url_for('dashboard') }}">Back to Dashboard</a>-->
|
||
{% include 'recommendations.html' %}
|
||
</div>
|
||
</body>
|
||
|
||
{% if user_analysis %}
|
||
<script>
|
||
// 数据传递
|
||
const genderData = {{ user_analysis.gender_analysis | tojson }};
|
||
const ageData = {{ user_analysis.age_analysis | tojson }};
|
||
const occupationData = {{ user_analysis.occupation_analysis | tojson }};
|
||
|
||
// 处理 By Gender 数据
|
||
const genderLabels = Object.keys(genderData).map(gender => gender === 'M' ? 'Male' : 'Female');
|
||
const genderRatings = Object.values(genderData).map(item => item.average);
|
||
|
||
const genderChart = new Chart(document.getElementById('genderChart'), {
|
||
type: 'bar',
|
||
data: {
|
||
labels: genderLabels,
|
||
datasets: [{
|
||
label: 'Average Rating by Gender',
|
||
data: genderRatings,
|
||
backgroundColor: ['#4caf50', '#2196f3']
|
||
}]
|
||
},
|
||
options: {
|
||
scales: {
|
||
y: { beginAtZero: true }
|
||
}
|
||
}
|
||
});
|
||
|
||
// 处理 By Age 数据
|
||
const ageLabels = Object.keys(ageData);
|
||
const ageRatings = Object.values(ageData).map(item => item.average);
|
||
|
||
const ageChart = new Chart(document.getElementById('ageChart'), {
|
||
type: 'bar',
|
||
data: {
|
||
labels: ageLabels,
|
||
datasets: [{
|
||
label: 'Average Rating by Age Group',
|
||
data: ageRatings,
|
||
backgroundColor: '#ff9800'
|
||
}]
|
||
},
|
||
options: {
|
||
scales: {
|
||
y: { beginAtZero: true }
|
||
}
|
||
}
|
||
});
|
||
|
||
// 处理 By Occupation 数据
|
||
const occupationLabels = Object.keys(occupationData);
|
||
const occupationRatings = Object.values(occupationData).map(item => item.average);
|
||
|
||
const occupationChart = new Chart(document.getElementById('occupationChart'), {
|
||
type: 'bar',
|
||
data: {
|
||
labels: occupationLabels,
|
||
datasets: [{
|
||
label: 'Average Rating by Occupation',
|
||
data: occupationRatings,
|
||
backgroundColor: '#9c27b0'
|
||
}]
|
||
},
|
||
options: {
|
||
scales: {
|
||
y: { beginAtZero: true }
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
{% endif %}
|
||
</html>
|