Initial commit

master
“foreverxiaoyu” 2 years ago
commit 51e7e86d7e

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1 @@
app.py

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="@localhost" uuid="09958162-8287-458e-a79b-cd88b552b135">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://localhost:3306</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

@ -0,0 +1,418 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DBNavigator.Project.DataEditorManager">
<record-view-column-sorting-type value="BY_INDEX" />
<value-preview-text-wrapping value="false" />
<value-preview-pinned value="false" />
</component>
<component name="DBNavigator.Project.DatabaseBrowserManager">
<autoscroll-to-editor value="false" />
<autoscroll-from-editor value="true" />
<show-object-properties value="true" />
<loaded-nodes />
</component>
<component name="DBNavigator.Project.DatabaseEditorStateManager">
<last-used-providers />
</component>
<component name="DBNavigator.Project.DatabaseFileManager">
<open-files />
</component>
<component name="DBNavigator.Project.Settings">
<connections />
<browser-settings>
<general>
<display-mode value="TABBED" />
<navigation-history-size value="100" />
<show-object-details value="false" />
</general>
<filters>
<object-type-filter>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="true" />
<object-type name="ROLE" enabled="true" />
<object-type name="PRIVILEGE" enabled="true" />
<object-type name="CHARSET" enabled="true" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED_VIEW" enabled="true" />
<object-type name="NESTED_TABLE" enabled="true" />
<object-type name="COLUMN" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET_TRIGGER" enabled="true" />
<object-type name="DATABASE_TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="true" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
<object-type name="ARGUMENT" enabled="true" />
<object-type name="DIMENSION" enabled="true" />
<object-type name="CLUSTER" enabled="true" />
<object-type name="DBLINK" enabled="true" />
</object-type-filter>
</filters>
<sorting>
<object-type name="COLUMN" sorting-type="NAME" />
<object-type name="FUNCTION" sorting-type="NAME" />
<object-type name="PROCEDURE" sorting-type="NAME" />
<object-type name="ARGUMENT" sorting-type="POSITION" />
<object-type name="TYPE ATTRIBUTE" sorting-type="POSITION" />
</sorting>
<default-editors>
<object-type name="VIEW" editor-type="SELECTION" />
<object-type name="PACKAGE" editor-type="SELECTION" />
<object-type name="TYPE" editor-type="SELECTION" />
</default-editors>
</browser-settings>
<navigation-settings>
<lookup-filters>
<lookup-objects>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="false" />
<object-type name="ROLE" enabled="false" />
<object-type name="PRIVILEGE" enabled="false" />
<object-type name="CHARSET" enabled="false" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED VIEW" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET TRIGGER" enabled="true" />
<object-type name="DATABASE TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="false" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="DIMENSION" enabled="false" />
<object-type name="CLUSTER" enabled="false" />
<object-type name="DBLINK" enabled="true" />
</lookup-objects>
<force-database-load value="false" />
<prompt-connection-selection value="true" />
<prompt-schema-selection value="true" />
</lookup-filters>
</navigation-settings>
<dataset-grid-settings>
<general>
<enable-zooming value="true" />
<enable-column-tooltip value="true" />
</general>
<sorting>
<nulls-first value="true" />
<max-sorting-columns value="4" />
</sorting>
<audit-columns>
<column-names value="" />
<visible value="true" />
<editable value="false" />
</audit-columns>
</dataset-grid-settings>
<dataset-editor-settings>
<text-editor-popup>
<active value="false" />
<active-if-empty value="false" />
<data-length-threshold value="100" />
<popup-delay value="1000" />
</text-editor-popup>
<values-actions-popup>
<show-popup-button value="true" />
<element-count-threshold value="1000" />
<data-length-threshold value="250" />
</values-actions-popup>
<general>
<fetch-block-size value="100" />
<fetch-timeout value="30" />
<trim-whitespaces value="true" />
<convert-empty-strings-to-null value="true" />
<select-content-on-cell-edit value="true" />
<large-value-preview-active value="true" />
</general>
<filters>
<prompt-filter-dialog value="true" />
<default-filter-type value="BASIC" />
</filters>
<qualified-text-editor text-length-threshold="300">
<content-types>
<content-type name="Text" enabled="true" />
<content-type name="Properties" enabled="true" />
<content-type name="XML" enabled="true" />
<content-type name="DTD" enabled="true" />
<content-type name="HTML" enabled="true" />
<content-type name="XHTML" enabled="true" />
<content-type name="CSS" enabled="true" />
<content-type name="SQL" enabled="true" />
<content-type name="PL/SQL" enabled="true" />
<content-type name="JavaScript" enabled="true" />
<content-type name="JSON" enabled="true" />
<content-type name="JSON5" enabled="true" />
<content-type name="YAML" enabled="true" />
</content-types>
</qualified-text-editor>
<record-navigation>
<navigation-target value="VIEWER" />
</record-navigation>
</dataset-editor-settings>
<code-editor-settings>
<general>
<show-object-navigation-gutter value="false" />
<show-spec-declaration-navigation-gutter value="true" />
<enable-spellchecking value="true" />
<enable-reference-spellchecking value="false" />
</general>
<confirmations>
<save-changes value="false" />
<revert-changes value="true" />
</confirmations>
</code-editor-settings>
<code-completion-settings>
<filters>
<basic-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="false" />
<filter-element type="OBJECT" id="view" selected="false" />
<filter-element type="OBJECT" id="materialized view" selected="false" />
<filter-element type="OBJECT" id="index" selected="false" />
<filter-element type="OBJECT" id="constraint" selected="false" />
<filter-element type="OBJECT" id="trigger" selected="false" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="false" />
<filter-element type="OBJECT" id="procedure" selected="false" />
<filter-element type="OBJECT" id="function" selected="false" />
<filter-element type="OBJECT" id="package" selected="false" />
<filter-element type="OBJECT" id="type" selected="false" />
<filter-element type="OBJECT" id="dimension" selected="false" />
<filter-element type="OBJECT" id="cluster" selected="false" />
<filter-element type="OBJECT" id="dblink" selected="false" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</basic-filter>
<extended-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</extended-filter>
</filters>
<sorting enabled="true">
<sorting-element type="RESERVED_WORD" id="keyword" />
<sorting-element type="RESERVED_WORD" id="datatype" />
<sorting-element type="OBJECT" id="column" />
<sorting-element type="OBJECT" id="table" />
<sorting-element type="OBJECT" id="view" />
<sorting-element type="OBJECT" id="materialized view" />
<sorting-element type="OBJECT" id="index" />
<sorting-element type="OBJECT" id="constraint" />
<sorting-element type="OBJECT" id="trigger" />
<sorting-element type="OBJECT" id="synonym" />
<sorting-element type="OBJECT" id="sequence" />
<sorting-element type="OBJECT" id="procedure" />
<sorting-element type="OBJECT" id="function" />
<sorting-element type="OBJECT" id="package" />
<sorting-element type="OBJECT" id="type" />
<sorting-element type="OBJECT" id="dimension" />
<sorting-element type="OBJECT" id="cluster" />
<sorting-element type="OBJECT" id="dblink" />
<sorting-element type="OBJECT" id="schema" />
<sorting-element type="OBJECT" id="role" />
<sorting-element type="OBJECT" id="user" />
<sorting-element type="RESERVED_WORD" id="function" />
<sorting-element type="RESERVED_WORD" id="parameter" />
</sorting>
<format>
<enforce-code-style-case value="true" />
</format>
</code-completion-settings>
<execution-engine-settings>
<statement-execution>
<fetch-block-size value="100" />
<execution-timeout value="20" />
<debug-execution-timeout value="600" />
<focus-result value="false" />
<prompt-execution value="false" />
</statement-execution>
<script-execution>
<command-line-interfaces />
<execution-timeout value="300" />
</script-execution>
<method-execution>
<execution-timeout value="30" />
<debug-execution-timeout value="600" />
<parameter-history-size value="10" />
</method-execution>
</execution-engine-settings>
<operation-settings>
<transactions>
<uncommitted-changes>
<on-project-close value="ASK" />
<on-disconnect value="ASK" />
<on-autocommit-toggle value="ASK" />
</uncommitted-changes>
<multiple-uncommitted-changes>
<on-commit value="ASK" />
<on-rollback value="ASK" />
</multiple-uncommitted-changes>
</transactions>
<session-browser>
<disconnect-session value="ASK" />
<kill-session value="ASK" />
<reload-on-filter-change value="false" />
</session-browser>
<compiler>
<compile-type value="KEEP" />
<compile-dependencies value="ASK" />
<always-show-controls value="false" />
</compiler>
<debugger>
<debugger-type value="JDBC" />
<use-generic-runners value="true" />
</debugger>
</operation-settings>
<ddl-file-settings>
<extensions>
<mapping file-type-id="VIEW" extensions="vw" />
<mapping file-type-id="TRIGGER" extensions="trg" />
<mapping file-type-id="PROCEDURE" extensions="prc" />
<mapping file-type-id="FUNCTION" extensions="fnc" />
<mapping file-type-id="PACKAGE" extensions="pkg" />
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
<mapping file-type-id="TYPE" extensions="tpe" />
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
</extensions>
<general>
<lookup-ddl-files value="true" />
<create-ddl-files value="false" />
<synchronize-ddl-files value="true" />
<use-qualified-names value="false" />
<make-scripts-rerunnable value="true" />
</general>
</ddl-file-settings>
<general-settings>
<regional-settings>
<date-format value="MEDIUM" />
<number-format value="UNGROUPED" />
<locale value="SYSTEM_DEFAULT" />
<use-custom-formats value="false" />
</regional-settings>
<environment>
<environment-types>
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
</environment-types>
<visibility-settings>
<connection-tabs value="true" />
<dialog-headers value="true" />
<object-editor-tabs value="true" />
<script-editor-tabs value="false" />
<execution-result-tabs value="true" />
</visibility-settings>
</environment>
</general-settings>
</component>
</project>

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="Flask">
<option name="enabled" value="true" />
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.8 (database) (2)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="jquery" level="application" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/templates" />
</list>
</option>
</component>
</module>

@ -0,0 +1,22 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="page_child2.html)}" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N802" />
</list>
</option>
</inspection_tool>
</profile>
</component>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="PROJECT" libraries="{jquery}" />
</component>
</project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (database) (2)" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/flask_html.iml" filepath="$PROJECT_DIR$/.idea/flask_html.iml" />
</modules>
</component>
</project>

384
app.py

@ -0,0 +1,384 @@
import random
import string
from flask import Flask, render_template, request, redirect, url_for, flash, session, get_flashed_messages, jsonify, g
from datetime import timedelta
import os
from flask_mail import Message
from flask_migrate import Migrate
from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename
import config
from exts import db, mail
from forms import RegisterForm, LoginForm
from models import UserModel, EmailCaptchaModel, VideoUri, FavoriteVideo
from sqlalchemy.orm import sessionmaker
app = Flask(__name__)
app.config.from_object(config)
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SECRET_KEY'] = os.urandom(24) # 随机数密钥
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=500) # 生成过期日期
db.init_app(app)
mail.init_app(app)
migration = Migrate(app, db)
video_information = []
connected_video_information = []
@app.route('/index')
def index():
return render_template("index.html")
@app.before_request
def my_before_request():
username = session.get('username')
if username:
user = UserModel.query.filter_by(username=username).first()
setattr(g, "user", user)
# print(f"{username}+cookie") # 已成功,测试用
else:
setattr(g, "user", None)
@app.route('/resources')
def resources():
Session_Mysql = sessionmaker()
session_Mysql = Session_Mysql()
id = session.get('user_id')
user_id = id
user = UserModel.query.filter_by(id=user_id).first()
# if user:
# session['user_url'] = user.user_avatar_url
# print(session.get('user_url'))
# session.update('user_url') 开了就会报错不想解决了就是要去更新session['user_url']的值,但是不知道怎么更新
video = session_Mysql.query(VideoUri.id, VideoUri.video_img_src, VideoUri.video_url,
VideoUri.video_tite).filter_by()
video_lists = db.session.execute(video).all()
video_information.clear()
for video_list in video_lists:
video_information.append({
'video_id': video_list[0],
'video_href': video_list[2],
'video_img_src': video_list[1],
'video_title': video_list[3]
})
user_name = session.get('username')
id = session.get('user_id')
favorite = session_Mysql.query(FavoriteVideo.video_id).filter_by(favorite_id=id)
favorite_list = db.session.execute(favorite).all() # 根据用户id获得所有收藏视频id
connected_video_information.clear()
for i in favorite_list: # 遍历
for j in i:
video = session_Mysql.query(VideoUri.id, VideoUri.video_img_src, VideoUri.video_url,
VideoUri.video_tite).filter_by(id=j)
video_list = db.session.execute(video).all()
for k in video_list: # 更新视频收藏表
connected_video_information.append({
'video_id': k[0],
'video_href': k[2],
'video_img_src': k[1],
'video_title': k[3]
})
print(f"connected_video_information={connected_video_information}")
# print(f"video_information={video_information}")
# print(f"first_session['video_information']={session.get('video_information')}")
return render_template("resources.html", video_information=video_information,
connected_video_information=connected_video_information, user= user)
@app.context_processor
def my_context_processor():
return {'user': g.user}
# g.user是全局变量可以在html中使用
# user的表
# 测试用实际要sql操作
# 有关数据库的操作(以UserModel表为例)
# 1.添加行
# user = UserModel(email=email, username=username, password=generate_password_hash(password),stu_id=stu_id)
# db.session.add(user)
# db.session.commit()
# 2.删除行,下面的所有first保证有值输出(在数据库中找不到会用NONE代替),以免报错
# user = UserModel.query.filter_by(email=email).first()
# UserModel表 表里的email字段=传入的email
# db.session.delete(user)
# db.session.commit()
# 3.修改行
# user = UserModel.query.filter_by(email=email).first()
# user.username = username
# db.session.commit()
# 4.查询行
# user = UserModel.query.filter_by(email=email).first()
# print(user.username)
# 5.查询所有行
# users = UserModel.query.all()
# for user in users:
# print(user.username)
# 测试用实际要sql操作
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
form = LoginForm(request.form)
if form.validate():
email = form.email.data
password = form.password.data
user = UserModel.query.filter_by(email=email).first()
if not user:
print("邮箱未注册")
return redirect('/login')
# 下面是验证密码是否正确,check_password_hash()函数的第一个参数是数据库中的密码,第二个参数是用户输入的密码
if check_password_hash(user.password, password):
print("登录成功")
# return jsonify({'code': 200, 'message': '登录成功'})
session['username'] = user.username
session['user_id'] = user.id
session['user_avatar_url'] = user.user_avatar_url
session['user_signature'] = user.user_say
print(f"session['user_signature']={session.get('user_signature')}")
# print(f"{session['username']}+test") # 已成功,测试用
return render_template("resources.html", user_name=user.username, video_information=video_information)
else:
print("密码错误")
return redirect('/login')
else:
print(form.errors)
return redirect('/login')
return render_template('login.html')
return render_template('login.html')
@app.route('/users_manage', methods=['POST', 'GET'])
def users_managing():
user_id = session.get('user_id')
user = UserModel.query.filter_by(id=user_id).first()
return render_template('user_manage.html', user=user)
@app.route('/upload-avatar', methods=['POST', 'GET'])
def upload_avatar():
file = request.files['avatar']
user_id = session.get('user_id')
user = UserModel.query.filter_by(id=user_id).first()
if file:
# Generate a secure filename
filename = secure_filename(file.filename)
print(f"filename={filename}")
# Specify the directory path for saving uploaded files
upload_folder = 'static/imgs/users'
os.makedirs(upload_folder, exist_ok=True)
# Save the file with the new name in the upload folder
new_filename = str(filename) # Provide the desired new filename with the appropriate extension
file.save(os.path.join(upload_folder, new_filename))
user.user_avatar_url = f"imgs/users/{new_filename}"
db.session.commit()
print(f"user.user_avatar_url={session.get('user_url')}")
# Continue processing or return a response
return 'File uploaded successfully.'
return 'No file uploaded.'
@app.route('/upload-stu_id', methods=['POST', 'GET'])
def upload_stu_id():
update_stu_id_dict = request.get_json()
user_id = update_stu_id_dict['user_id']
user = UserModel.query.filter_by(id=user_id).first()
user.stu_id = update_stu_id_dict['stu_id']
db.session.commit()
print(f"user.stu_id={user.stu_id}")
return jsonify(list({'statick', 'ok'}))
@app.route('/upload-email', methods=['POST', 'GET'])
def upload_email():
return 'ok'
@app.route('/upload-address', methods=['POST', 'GET'])
def upload_address():
update_address_dict = request.get_json()
user_id = update_address_dict['user_id']
user = UserModel.query.filter_by(id=user_id).first()
user.address = update_address_dict['address']
db.session.commit()
return jsonify(list({'statick', 'ok'}))
@app.route('/upload-enterprise', methods=['POST', 'GET'])
def upload_enterprise():
update_enterprise_dict = request.get_json()
user_id = update_enterprise_dict['user_id']
user = UserModel.query.filter_by(id=user_id).first()
user.enterprise = update_enterprise_dict['enterprise']
db.session.commit()
return jsonify(list({'statick', 'ok'}))
@app.route('/user_data', methods=['GET'])
def user_data():
username = session.get('username')
user_id = session.get('user_id')
user_url = session.get('user_avatar_url')
user_signature = session.get('user_signature')
print(f"{user_url}+1111111111111") # 已成功,测试用
# print(f"{username}+1111111111111") # 已成功,测试用
if username:
# 根据需要获取用户数据的逻辑,例如从数据库中查询用户信息
# ...
# 构造包含用户名的响应数据
# data = {'username': username}
data = {'username': username, 'user_id': user_id, 'user_url': user_url, 'user_signature': user_signature}
print(jsonify(data))
print(data)
# 返回 JSON 格式的响应数据
return jsonify(data)
else:
# 如果用户未登录,则返回空数据或错误信息
return jsonify({'error': 'User not logged in'})
@app.route('/logout')
def logout():
session.clear()
return redirect('/index')
'''@app.route('/user/favorite')
def get_favorite():
Session_Mysql = sessionmaker()
session_Mysql = Session_Mysql()
user = get_flashed_messages(session['username']) #从session中获取用户名
id = session_Mysql.query(UserModel.id).filter_by(username=user) #查找id
favorite = session_Mysql.query(FavoriteVideo.video_id).filter_by(favorite_id=id) #用id查找收藏的视频id
favorite_uri_list = [] #创建收藏视频地址的列表
for i in favorite:
favorite_uri_list.append(session_Mysql.query(VideoUri.video_uri).filter_by(id=i))
session['favorite_list'] = favorite_uri_list #将视频地址列表放入session中
return render_template()这里填一个页面
''' # 这个可能需要改进,还要完成用户收藏页面(应该也可以直接在用户页面显示)
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'GET':
return render_template('register.html')
else:
form = RegisterForm(request.form)
if form.validate():
email = form.email.data
username = form.username.data
password = form.password.data
stu_id = form.stu_id.data
user = UserModel(email=email, username=username, password=generate_password_hash(password), stu_id=stu_id)
db.session.add(user)
db.session.commit()
return redirect('/login')
else:
print(form.errors)
return redirect('/register')
@app.route('/captcha/email')
def captcha_email():
email = request.args.get('email')
source = string.digits * 4
captcha = ''.join(random.sample(source, 4))
message = Message(subject="数据库作业验证码", recipients=[email], body=f"验证码为:{captcha}")
mail.send(message)
email_captcha = EmailCaptchaModel(email=email, captcha=captcha)
db.session.add(email_captcha)
db.session.commit()
# RESTful API
# {code: 200/400/500, message: '', data: {}}
return jsonify({"code": 200, "message": '', "data": None})
@app.after_request
def add_header(response):
response.cache_control.no_store = True
return response
@app.route('/resources/video/collection_update', methods=['POST'])
def update_video_collection():
data = request.get_json() # Get the JSON data from the request
print(data)
username = data['username']
video_href = data['video_href']
id = data['id']
user_id = data['user_id']
# video_tite = data['video_tite']
favo = FavoriteVideo.query.filter_by(video_id=id,
favorite_id=user_id).first() # 这里查找是否已经收藏过了如果为空则没有收藏因为进入resources时就已经更新过了
if favo is None:
fav = FavoriteVideo(video_id=id, favorite_id=user_id)
db.session.add(fav)
db.session.commit()
video = VideoUri.query.filter_by(id=id).first()
video_information.append({
'video_id': id,
'video_href': video_href,
'video_img_src': video.video_img_src,
# 'video_tite': video_tite,
})
return jsonify({'static': 'OK'})
@app.route('/resources/video/collecting_cancel', methods=['POST'])
def cancel_collecting():
data = request.get_json()
print(data)
username = data['username']
video_href = data['video_href']
id = data['id']
user_id = data['user_id']
fav = FavoriteVideo.query.filter_by(favorite_id=user_id, video_id=id).first()
db.session.delete(fav)
db.session.commit()
return jsonify({'static': 'OK'})
@app.route('/resources/video/init', methods=['POST'])
def videoPage_init():
local_connected_video_information = []
Session_Mysql = sessionmaker()
session_Mysql = Session_Mysql()
id = request.get_json()['user_id']
favorite = session_Mysql.query(FavoriteVideo.video_id).filter_by(favorite_id=id)
favorite_list = db.session.execute(favorite).all() # 根据用户id获得所有收藏视频id
local_connected_video_information.clear()
for i in favorite_list: # 遍历
for j in i:
video = session_Mysql.query(VideoUri.id, VideoUri.video_img_src, VideoUri.video_url,
VideoUri.video_tite).filter_by(id=j)
video_list = db.session.execute(video).all()
print(f"video_list: {video_list}")
for k in video_list: # 更新视频收藏表
local_connected_video_information.append({
'video_id': k[0],
'video_href': k[2],
'video_img_src': k[1],
'video_tite': k[3]
})
print(f"local_connected_video_information: {local_connected_video_information}")
return jsonify(local_connected_video_information)
if __name__ == '__main__':
app.run(debug=True)

@ -0,0 +1,14 @@
HOSTNAME = '127.0.0.1'
PORT = '3306'
USERNAME = 'root'
PASSWORD = '123456'
DATABASE = 'database_homework'
DB_URI = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}'
SQLALCHEMY_DATABASE_URI = DB_URI
MAIL_SERVER = "smtp.163.com"
MAIL_USE_SSL = True
MAIL_PORT = 465
MAIL_USERNAME = "forever_love233@163.com"
MAIL_PASSWORD = ""
MAIL_DEFAULT_SENDER = "forever_love233@163.com"

@ -0,0 +1,12 @@
from functools import wraps
from flask import g, redirect, url_for
def login_required(func):
@wraps(func)
def inner(*args, **kwargs):
if g.user:
return func(*args, **kwargs)
else:
return redirect(url_for('login'))
return inner

@ -0,0 +1,5 @@
from flask_sqlalchemy import SQLAlchemy
from flask_mail import Mail
db = SQLAlchemy()
mail = Mail()

@ -0,0 +1,45 @@
import wtforms
from wtforms.validators import Email, Length
from models import UserModel, EmailCaptchaModel
class RegisterForm(wtforms.Form):
username = wtforms.StringField(validators=[Length(min=3, max=20, message='用户名长度不正确')])
email = wtforms.StringField(validators=[Email(message='邮箱格式不正确')])
captcha = wtforms.StringField(validators=[Length(min=4, max=4, message='验证码长度不正确')])
password = wtforms.StringField(validators=[Length(min=6, max=20, message='密码长度不正确')])
stu_id = wtforms.StringField(validators=[Length(min=10, max=20, message='学号长度不正确')])
def validate_email(self, filed):
email = filed.data
user = UserModel.query.filter_by(email=email).first()
if user:
raise wtforms.ValidationError(message='邮箱已经被注册')
def validate_captcha(self, filed):
captcha = filed.data
email = self.email.data
email_captcha = EmailCaptchaModel.query.filter_by(email=email, captcha=captcha).first()
if not email_captcha:
raise wtforms.ValidationError(message='邮箱验证码不正确')
# else:
# db.session.delete(email_captcha)
# db.session.commit()
class LoginForm(wtforms.Form):
email = wtforms.StringField(validators=[Email(message='邮箱格式不正确')])
password = wtforms.StringField(validators=[Length(min=6, max=20, message='密码长度不正确')])
# def validate_email(self, filed):
# email = filed.data
# user = UserModel.query.filter_by(email=email).first()
# if not user:
# raise wtforms.ValidationError(message='邮箱未注册')
#
# def validate_password(self, filed):
# password = filed.data
# email = self.email.data
# user = UserModel.query.filter_by(email=email).first()
# if not user.check_password(password):
# raise wtforms.ValidationError(message='密码错误')

Binary file not shown.

Binary file not shown.

@ -0,0 +1 @@
Single-database configuration for Flask.

@ -0,0 +1,50 @@
# A generic, single database configuration.
[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic,flask_migrate
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[logger_flask_migrate]
level = INFO
handlers =
qualname = flask_migrate
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

@ -0,0 +1,110 @@
import logging
from logging.config import fileConfig
from flask import current_app
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
def get_engine():
try:
# this works with Flask-SQLAlchemy<3 and Alchemical
return current_app.extensions['migrate'].db.get_engine()
except TypeError:
# this works with Flask-SQLAlchemy>=3
return current_app.extensions['migrate'].db.engine
def get_engine_url():
try:
return get_engine().url.render_as_string(hide_password=False).replace(
'%', '%%')
except AttributeError:
return str(get_engine().url).replace('%', '%%')
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
config.set_main_option('sqlalchemy.url', get_engine_url())
target_db = current_app.extensions['migrate'].db
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def get_metadata():
if hasattr(target_db, 'metadatas'):
return target_db.metadatas[None]
return target_db.metadata
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=get_metadata(), literal_binds=True
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
connectable = get_engine()
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=get_metadata(),
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

@ -0,0 +1,24 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

@ -0,0 +1,42 @@
"""empty message
Revision ID: 1f57157eb709
Revises: bb32a1d42ccd
Create Date: 2023-05-28 09:53:06.971726
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '1f57157eb709'
down_revision = 'bb32a1d42ccd'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.alter_column('address',
existing_type=mysql.VARCHAR(length=100),
nullable=True)
batch_op.alter_column('enterprise',
existing_type=mysql.VARCHAR(length=100),
nullable=True)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.alter_column('enterprise',
existing_type=mysql.VARCHAR(length=100),
nullable=False)
batch_op.alter_column('address',
existing_type=mysql.VARCHAR(length=100),
nullable=False)
# ### end Alembic commands ###

@ -0,0 +1,36 @@
"""empty message
Revision ID: 4bc1decf051d
Revises: 1f57157eb709
Create Date: 2023-05-28 09:54:00.011898
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '4bc1decf051d'
down_revision = '1f57157eb709'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.alter_column('user_say',
existing_type=mysql.VARCHAR(length=500),
nullable=True)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.alter_column('user_say',
existing_type=mysql.VARCHAR(length=500),
nullable=False)
# ### end Alembic commands ###

@ -0,0 +1,65 @@
"""empty message
Revision ID: bb32a1d42ccd
Revises:
Create Date: 2023-05-28 09:46:20.663367
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'bb32a1d42ccd'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('email_captcha',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('email', sa.String(length=100), nullable=False),
sa.Column('captcha', sa.String(length=100), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('username', sa.String(length=100), nullable=False),
sa.Column('password', sa.String(length=500), nullable=False),
sa.Column('email', sa.String(length=100), nullable=False),
sa.Column('stu_id', sa.String(length=100), nullable=False),
sa.Column('user_say', sa.String(length=500), nullable=False),
sa.Column('join_time', sa.DateTime(), nullable=True),
sa.Column('address', sa.String(length=100), nullable=False),
sa.Column('enterprise', sa.String(length=100), nullable=False),
sa.Column('user_avatar_url', sa.String(length=100), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email'),
sa.UniqueConstraint('stu_id')
)
op.create_table('videouri',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('video_url', sa.String(length=100), nullable=False),
sa.Column('video_img_src', sa.String(length=100), nullable=False),
sa.Column('video_tite', sa.String(length=100), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('favorite',
sa.Column('favorite_id', sa.Integer(), nullable=False),
sa.Column('video_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['favorite_id'], ['user.id'], ),
sa.ForeignKeyConstraint(['video_id'], ['videouri.id'], ),
sa.PrimaryKeyConstraint('favorite_id', 'video_id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('favorite')
op.drop_table('videouri')
op.drop_table('user')
op.drop_table('email_captcha')
# ### end Alembic commands ###

@ -0,0 +1,47 @@
# 此文件用于定义数据库表的模型
# 使用命令行创建数据库表
# flask db init # 初始化(只要执行一次)
# flask db migrate #检查模型文件,生成迁移文件
# flask db upgrade # 更新数据库
# 后续添加表只要执行 migrate 和 upgrade 命令即可
from exts import db
from datetime import datetime
class UserModel(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True, autoincrement=True) #也是视频收藏号与视频收藏表关联得到收藏号去视频收藏表中查找收藏的视频id
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(500), nullable=False)
email = db.Column(db.String(100), nullable=False, unique=True)
stu_id = db.Column(db.String(100), nullable=False, unique=True)
user_say = db.Column(db.String(500), nullable=True)
join_time = db.Column(db.DateTime, default=datetime.now)
address = db.Column(db.String(100), nullable=True)
enterprise = db.Column(db.String(100), nullable=True)
user_avatar_url = db.Column(db.String(100), nullable=False, default='/static/imgs/users/root.png')
class VideoUri(db.Model):
__tablename__ = 'videouri'
id = db.Column(db.Integer, primary_key=True, autoincrement=True) #视频id
video_url = db.Column(db.String(100), nullable=False)
video_img_src = db.Column(db.String(100), nullable=False)
video_tite = db.Column(db.String(100), nullable=False)
class FavoriteVideo(db.Model):
__tablename__ = 'favorite'
favorite_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
video_id = db.Column(db.Integer, db.ForeignKey('videouri.id'), primary_key=True)
class EmailCaptchaModel(db.Model):
__tablename__ = 'email_captcha'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
email = db.Column(db.String(100), nullable=False)
captcha = db.Column(db.String(100), nullable=False)

@ -0,0 +1,20 @@
V1.1 modify by jxy
1.添加了注册,登录功能,且与数据库连接上了,与数据库连接详见config.py
2.添加了有关数据库表的创建以及相关表的操作的代码注释
3.添加了register.html以及register.js
4.修改了login.html将部分代码移植到了register.html中去除了login.js的使用(原因:email是key而username可能重复,所以提交form是将username改成了email)
问题
1.还要在login.html和login.js中加入从/login跳转到/register的功能
V1.2 by ktp
1.修改了数据库结构
2.添加了一段关于收藏视频页面的代码(注释部分)
V1.3 modify by jxy
1.重构了底层代码已弃用原来的网页cookie以及g.user在resources.html的使用改用本地的session(cookie还是有只不过没用)
2.与HJ的代码进行了整合
3.加入从/login跳转到/register的功能
4.修改了V1.2的英语单词拼写错误以及部分表
计划:
1.用户登录后可以上传视频(video_url,以及pic_url)

@ -0,0 +1,41 @@
a{
text-decoration-line: none;
color:unset;
height: 0;width: 0;
}
footer{
height: 20px;
margin:0 auto ;
text-align: center;
clear: both;
}
footer a{
color: white;
font-weight: 100; font-size: 3px;
text-decoration: none;
margin: 2px;
}
footer a:hover{
color: blue;
}
body,div,span,ul,li,p,footer{
margin: 0;
padding: 0;
text-decoration: none;list-style: none;
}
.none{
margin: 0 auto;
width: 960px;height: 100px;
border: solid 3px rgba(78, 234, 234, 0.234);
text-align: center;
color: black;
background-color:#fff;
}
.none div{
color: antiquewhite;
font-size: 30px;
font-weight: 1500;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

@ -0,0 +1,257 @@
*{
background-repeat: repeat-y;
}
#main_div_mainPageImg{
border: 0;padding: 0;
height: 400px;width: 100%;
margin: 0;
background: url(../imgs/pexels-faik-akmd-1025469.png) no-repeat top ;
/*兼容浏览器版本*/
-webkit-background-size: cover;
-o-background-size: cover;
background-size: cover;
overflow: hidden;
}
body{
background-image: linear-gradient(to bottom, rgb(0, 19, 32) 50%, rgba(90, 130, 157, 0.684));
}
#main_div{
width: 1080px;height: 800px;
margin: 0 auto;border: 0;padding: 0;
opacity: 100%;
background-image:linear-gradient(to bottom, rgb(0, 19, 32) 20% ,rgba(90, 130, 157, 0.684))
}
#navs {
display: flex;
width:1077px; height: 30px;
padding: 0;margin: 0;
border: unset;
text-decoration: none;list-style: none;
}
#navs li{
flex-direction: row-reverse;
padding: 2px;
float:left;
width: 215px; height: 30px ;
margin: 0 1px 0;
border: 0;
/*border-left :1px solid rgb(12, 114, 203); border-right :1px solid rgb(12, 114, 203);*/
transition: all 0.6s;/*all 包括了transform*/
transform-style: preserve-3d;
position:relative;
}
#navs li:hover{
transform: rotateX(-90deg);
}
#navs li a{
position: absolute;/*子绝父相 */
left: 0; top:0;
display:block;
width: 214px;height: 100%;
text-align:center;
text-decoration:none; /* 去掉下划线 */
}
#navs li a:first-child{
color:#fff;
background:#3A4953;
transform: translateZ(15px);
}
#navs li a:last-child{
color:rgb(0, 0, 0);
background:#e1ecf4;
transform: rotateX(90deg) translateZ(15px); /* x转向后z轴方向也“躺平了” */
}
#main_page{
margin:0 ;padding: 0;
/* background-color: chartreuse; */
float: left;
}
#local{
margin: 0;padding: 0;
height: 340px; width: 1077px;
}
/* 轮播图 */
#local_pics{
margin: 10px; padding: 0;
width: 480px;height:340px ;
position: relative;
text-align: center;
display: inline-block;
}
#main_page_local_pics{
float: left;
margin:0px;
padding: 0;
list-style:none;
width: 480px;
height:270px;
position:absolute;
overflow: hidden;
background-color: #6b6de056;
}
#main_page_local_pics li{
float: left;
position:absolute;
list-style: none;
z-index: 0;
opacity: 0;
}
#local_pics_text{
float: left;
position:relative;
top: 270px;
width: 480px;height: 50px;
text-align: center;
background-color:#3A4953;
}
#mainPageImgsDescription{
color: white;
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
font-weight: 200;font-size: 3px;
float: left; clear: all;
width: 480px;height: 25px;
}
.Thepoint{
padding: 0;
list-style:none;
/* background-color: crimson; */
z-index: 100;
margin-left: 170px;
}
.points{
float: left;
height: 6px;
width: 6px;
margin-right: 10px;
border-style: solid;
border-radius: 100%;
background-color: rgb(255, 255, 255);
border-width:3px;
border-color: aliceblue;
}
.points.active{
background-color: black;
border-color:dodgerblue;
transition: all .5s;
}
.points:hover{
cursor: pointer;
}
.change{
height: 30px;
width: 30px;
border-width: 0px;
border-radius: 50%;
position:absolute;
opacity: 50%;
background-color: unset;
color: rgb(255, 255, 255); font-weight: 1800; font-size:25px;
z-index: 100;
top:130px;
}
.change:hover{
cursor: pointer;
}
.change:active{
background-color: rgb(204, 206, 207);
}
#change-left{
left: 10px;
}
#change-right{
right:10px;
}
#developers_said{
margin:20px 100px;
width: 330px;
height: 340px;
display: inline-block;
vertical-align:top;
}
#developers_said span{
color: #e1ecf4;
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
margin: 10px 20px 3px;
font-size: 20px;font-weight: 600;
}
marquee{
padding: 10px; margin-top: 40px ;
width: 330px;
height: 150px;
border: 3px solid #9d9d9d;
background-color: rgba(90, 130, 157, 0.684);
}
marquee blockquote{
font-size: 6px;
font-weight: 300;
color:snow;
transition: all 0.5s;
}
marquee:hover blockquote{
color:skyblue;
font-size:8px ;font-weight: 450;
}
#main_down{
width: 1080px;height: 400px;
}
#main_down ul{
display: flex;
flex-direction:row;/*row:行 column:列*/
justify-content: space-around;
}
#main_down li{
display:inline-block;
padding: 5px 10px 5px;
margin-top: 20px;
width: 160px;height: 290px;
border-radius: 12px;
border: double #839fbbb7;
text-align: center;
transition:all 1s;
/* background-color: chartreuse; */
}
#main_down li a{
text-decoration: none;
}
#main_down li span{
margin: 0 auto;
font-size: medium;
font-weight: 800;
color: #b2b4b680;
}
#main_down li:hover{
transform: rotateY(360deg);
box-shadow:inset 0 -10px 40px -2px #9b9b9b;
background-color: #ffffff;
}
#main_down li:hover span{
color: black;
}
#main_down li p{
margin: 20px 5px;
color: white;
font-size: small;
font-weight: 200;
}
#main_down li:hover p{
margin: 20px 5px;
color: #9b9b9b;
font-size: small;
font-weight: 200;
}
#main_down li:nth-child(1) div{background-image: url(../icons/群星华绽.png);}
#main_down li:nth-child(2) div{background-image: url(../icons/资源.png);}
#main_down li:nth-child(3) div{background-image: url(../icons/开发中.png);}
#main_down li:nth-child(4) div{background-image: url(../icons/记录1.png);}
#main_down li div{
margin: 0 auto;
width:60px ;height: 60px;
border-radius: 50%;
background-repeat: no-repeat;background-size: contain;
}

@ -0,0 +1,152 @@
.login-container {
width: 600px;
height: 60%;
margin: 0 auto;
margin-top: 10%;
border-radius: 15px;
box-shadow: 0 10px 50px 0px #CCFFFF;
}
.left-container {
display: inline-block;
width: 330px;
border-top-left-radius: 15px;
border-bottom-left-radius: 15px;
padding: 60px;
}
.title {
color: #fff;
font-size: 18px;
font-weight: 200;
}
.title span {
border-bottom: 3px solid rgb(237, 221, 22);
}
.input-container {
padding: 20px 0;
}
input {
border: 0;
background: none;
outline: none;
color: #fff;
margin: 20px 0;
display: block;
width: 100%;
padding: 5px 0;
transition: .2s;
border-bottom: 1px solid rgb(199, 191, 219);
}
input:hover
{
border-bottom-color: #fff;
}
::-webkit-input-placeholder {
color: rgb(199, 191, 219);
}
.message-container {
font-size: 14px;
transition: .2s;
color: rgb(199, 191, 219);
cursor: pointer;
}
.message-container:hover {
color: #fff;
}
.right-container {
width: 145px;
display: inline-block;
height: calc(100% - 120px);
vertical-align: top;
padding: 60px 0;
}
.regist-container {
text-align: center;
color: #fff;
font-size: 18px;
font-weight: 200;
}
.regist-container span {
border-bottom: 3px solid rgb(237, 221, 22);
cursor: pointer;
}
.action-container {
font-size: 10px;
color: #fff;
text-align: center;
position: relative;
top: 200px;
}
#enroll_enrolling{
top:200px;
}
#enroll_return{
top:100px;
}
.action-container span {
border: 1px solid rgb(237, 221, 22);
padding: 10px;
display: inline;
line-height: 20px;
border-radius: 20px;
position: absolute;
bottom: 10px;
left: calc(72px - 20px);
transition: .2s;
cursor: pointer;
}
.action-container span:hover {
background-color: rgb(237, 221, 22);
color: rgb(95, 76, 194);
}
.enroll-container {
display: inline-block;
width: 330px;
border-top-left-radius: 15px;
border-bottom-left-radius: 15px;
}
#login_video{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -10;
object-fit: cover;
}
.btn_btn-primary_btn-block{
background-color: unset;
border: solid gold 2px;
color: snow;
font-size: 10px;
font-weight: bolder;
cursor: pointer;
}
.btn_btn-primary_btn-block:hover{
background-color: gold;
color: rgb(95, 76, 194);
}
#submit_login{
color: #fff;
text-align: center;
border: solid gold 2px;
cursor: pointer;
}
#submit_login :hover{
background-color: gold;
color: rgb(95, 76, 194);
}
#submit_login div{
display: inline;
line-height: 20px;
border-radius: 20px;
position: absolute;
bottom: 10px;
left: calc(72px - 20px);
transition: .2s;
cursor: pointer;
}

@ -0,0 +1,9 @@
#preview{
width: 500px; height: 400px;
}
#preview iframe{
margin: 0;
width: 500px; height: 400px;
}

@ -0,0 +1,515 @@
main{
width: 100%;height:50rem;
position: relative;
border: solid rgb(13, 75, 106) 1px;box-shadow: 5px 0 5px black;
/*background-image: radial-gradient(rgba(90, 130, 157, 0.684),rgb(0, 19, 32))*/
background-image: url("../imgs/OrionPleiades-Imgur.jpg");
}
.head_bar{
position: absolute;
z-index: 1;
left:50%;top:2rem;
transform:translate(-50%, -50%);
width: 8rem;
height: 1.5rem;
padding-top: 0.25rem;
text-align: center;
color: rgb(255, 255, 255);
font-size: 15px;
font-weight: 1000;
font-family: monospace;
}
.head_bar::before {
content: ''; /* To generate the box */
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
border: solid rgb(13, 75, 106) 1px;
box-shadow: 0 0 5px rgb(8, 163, 230),0 -5px 5px black;
background:#234189;
transform: perspective(.5em) rotateX(-5deg);
}
.left_nav ul{
position: absolute;
left: 10rem;top: 3rem;
width: 25%;height:5rem;
display: flex;/* 该布局仅仅影响其直接子元素。 */
flex-direction: row;
justify-content: space-around;
}
.left_navs{
padding-top: 0.4rem;
width: 3rem; height:2.5rem;
border: solid rgb(142, 176, 192) 1px;box-shadow: 0 0 5px rgba(162, 209, 231, 0.618);
border-bottom-left-radius: 2rem; border-bottom-right-radius: 2rem;
text-align: center;
color: rgb(239, 239, 239);
font-size: 10px;
font-weight: 600;
font-family: monospace;
background: rgba(0, 19, 32, 0.578);
transition: all 0.5s;
-moz-transition: all 0.5s;
-webkit-transition: all 0.5s;
-o-transition:all 0.5s;
}
.left_navs_chosed{
padding-top: 0.4rem;
width: 3rem; height:3.5rem;
border: solid rgb(142, 176, 192) 1px;box-shadow: 0 -2px 10px rgba(162, 209, 231, 0.618);
color: rgb(0, 19, 32, 0.578);
text-align: center;
font-size: 10px;
font-weight: 1000;
font-family: monospace;
background:rgb(239, 239, 239);
transition: all 0.5s;
-moz-transition: all 0.5s;
-webkit-transition: all 0.5s;
-o-transition:all 0.5s;
}
#login
{
padding: 1rem;
position: absolute;
right: 10rem;top: 3rem;
width: 5rem;height:5rem;
}
.user_profile{
position: relative;
width: 8%;
height: 8%;
top:14%;
left: 82%;
background: snow;
text-align: center;
transition: opacity 1s;
z-index: 5;
opacity: 0;
}
.user_profile div{
margin: 1px;
color: black;
border: #66aee6 solid;
font-weight: bolder;
font-family: fangsong;
}
main div #id_p
{
height: 32px;
width: 32px;
border-radius: 16px;
background-color: #ececec;
display: inline-block;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
background-image:none;
}
main div #id_n
{
color: #ececec;
text-align: center;
font-size: 14px;
font-weight: 2000;
font-family: monospace;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100px;
display: inline-block;
}
.main_window{
position:relative;
left:50%;top:46%;
width: 80%;height: 80%;
transform:translate(-50%, -50%);
border: solid rgb(142, 176, 192) 1px;border-top: none; box-shadow: 0 4px 7px rgba(162, 209, 231, 0.618);
background: rgba(0, 19, 32, 0.578);
}
.container{
/*--box-size: 30%; !* 定义一个名为--box-size的变量值为50% *!*/
display: flex;
align-items: center;
flex-direction: column;
flex-wrap: wrap;
box-sizing: border-box;
padding: 10px;
border: 1px solid #ccc;
height: 100%;
width:100%;
}
img{
border-radius: 5%;
}
/*资源详情*/
/* 四个悬浮球的共同样式 */
.floating-ball {
margin:30px 30px 10px;
position: relative;
color: #fff;
padding: 10px;
transition: all 0.3s ease;
border-radius: 50%;
background: radial-gradient(circle, #224E79,#333333);
/*设置交叉轴的对齐方式为居中,同时可以使用将主轴方向设置为垂直方向,*/
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 16px;
font-weight: bold;
text-align: center;
cursor: pointer;
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2);
}
/* 悬浮球的鼠标悬停样式 */
.floating-ball:hover {
box-shadow: 0 0 20px #66aee6;
background: radial-gradient(circle, snow,#66aee6);
font-size: 18px;
font-weight: bolder;
color: #333333;
}
/* 悬浮球的标签样式 */
.floating-ball span {
width: 100px;
height: 30px;
margin: 20px;
font-size: 14px;
display: block;
font-weight: bold;
}
/* 悬浮球的介绍文字样式 */
.floating-ball p {
width: 100px;
height: 300px;
font-size: 12px;
}
/*video*/
.left-box {
padding: 10px;
display: flex;
flex-direction: column;
width: 25%; height: 100%;
}
.play_status{
float: left;
width: 1rem;height: 1rem;
border-radius: 50%;
background: green;
}
#main_video_span{
float: right;
width: 70%;height: 80%;
color: white;
text-align: right;
margin-top: 5%;
border-bottom: #fff000 solid;
}
.video_card_text-body{
float: right;
font-size: x-small;
font-weight: 300;
color: snow;
clear: both;
margin: 10% 2% 2%;
}
#video_left_autoplay{
width: 100%;height: auto;
margin: 3px;
border: solid rgb(142, 176, 192) 1px;border-top: none; box-shadow: 0 4px 7px rgba(162, 209, 231, 0.618);
}
#video_text{
width: 100%;height: 60%;
margin: 2px;padding: 5%;
font-family:fangsong;
font-size: medium;
font-weight: 300;
color: snow;
overflow-y: scroll;
}
.right-box {
display: flex;
flex-wrap: wrap;
padding: 10px;
width: 70%;height: 100%;
overflow-y: scroll;
overflow-x: hidden;
-ms-overflow-style:none; /* IE and Edge 隐藏 IE、Edge的滚动条*/
}
right-box::-webkit-scrollbar {
display: none; /* 隐藏 Chrome、Safari 和 Opera 的滚动条 */
width: 0;
height: 0;
}
.video_card_texts{
width: 25%;height: 30%;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
overflow: hidden;
margin: 20px;
}
.video_cards {
display: flex;
flex-wrap: wrap;
width: 20%;
height: 23%;
border-radius: 10px;
box-shadow: 0 0 20px 3px rgba(0, 123, 255, 0.8);
margin: 20px;
}
.video_card-img-top-div {
width: 100%;
height: 100%;
text-align: center;
padding: 2px;
}
.video_card_text {
width: 100%;
padding: 10px;
background: linear-gradient(rgba(0, 123, 255, 0.8), transparent);
border-radius: 0 0 10px 10px;
transition: background-color 0.3s ease;
}
.video_card_text div{
float: left;
width: 15px;
height: 15px;
margin: 2px;
background-repeat: no-repeat;
background-size: contain;
cursor: pointer;
}
.video_card_text a {
float: right;
width: 70%;
height: 100%;
display: block;
color: #fff;
font-size: xx-small;
}
.video_card_text:hover {
background: linear-gradient(rgba(0, 105, 217, 0.8), transparent);
}
/* "我的"界面*/
/* Container */
#index_mine {
justify-content: space-between;
font-family: Arial, sans-serif;
color: #fff;
padding: 10px;
}
#left-box-mine{
padding: 5%;
margin: 0 auto 0;
}
#left-box-mine div{
width: 50%;
height: 60%;
padding: 10%;
border: white solid 1px;
border-radius: 6%;
box-shadow: 0 0 1rem .5rem #E4FEFF;
}
.left-box img {
width: 50%;
height: 30%;
border-radius: 50%;
margin: 10% 25% 0;
}
.signature {
width: 50%;
height: 20%;
margin: 10% 25% 0;
}
.user-options{
width: 80%;height: 10%;
float: left;
display: flex;
flex-direction:row;/*row:行 column:列*/
justify-content: flex-start;
}
.user-options li{
width: 30%;height: 10%;
padding: 5%;
margin: 5%;
color: white;
font-family: , serif;
font-size: x-small;
font-weight: normal;
cursor: pointer;
}
.user-options li:hover{
color: #66aee6;
}
.user-options li:first-child{
float: left;
}
.user-options li:last-child{
float: right;
}
#right-box-mine{
display: unset;
padding: 10px;
margin-right: 3%;
width: 60%;height: 100%;
overflow-y: scroll;
overflow-x: hidden;
}
#right-box-mine::-webkit-scrollbar {
display: none; /* 隐藏 Chrome、Safari 和 Opera 的滚动条 */
width: 0;
height: 0;
}
#right-box-mine h2 {
margin-bottom: 20px;
}
.mine_rightbox_chosed{
padding: 0;
margin: 0;
width: 90%;height: 10%;
background-color: #00152b;
}
.mine_rightbox_chosed ul{
width: 80%;height: 100%;
float: left;
display: flex;
flex-direction:row;/*row:行 column:列*/
justify-content: flex-start;
}
.mine_rightbox_chosed ul li{
width: 15%;height: 50%;
float: left;
padding: 2%;
margin: 1%;
color: white;
font-family: , serif;
font-size: x-small;
font-weight: normal;
border-top-left-radius: 10%;
border-top-right-radius: 10%;
cursor: pointer;
transition: all 1s;
}
.mine_command{
float: right;
color: #66aee6;
font-family: fangsong;
font-weight: bold;
cursor:pointer;
}
.mine_command:hover{
color: snow;
}
.record-row {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
border: #E4FEFF solid 1px;
box-shadow: 0 0 1rem .5rem #436495;
}
.record-block {
width: 100%;
height: 30%;
background-color: #032541;
padding: 20px;
border-radius: 5px;
margin-bottom: 20px;
}
.NoContent{
display: block;
width: 100%;
height: 70%;
margin: 0 auto 0;
color: gray;
}
.record-block h3 {
color: #fff;
margin-bottom: 10px;
}
.record-block ul {
display: flex;
flex-wrap: wrap-reverse;
width: 100%;
height: 100%;
list-style-type: none;
padding: 0;
margin-bottom: 10px;
}
.record-block ul li {
width: 25%;
height: 25%;
margin: 2% 2% 5px;
box-shadow: 0 0 2px 0 #E4FEFF;
}
.record-block .delete_icon{
display: none;
float: right;
width: 15px;
height: 15px;
margin: 2px;
background-repeat: no-repeat;
background-size: contain;
cursor: pointer;
}
#mine_video_card_text{
width: 85%;
}
#mine_video_card_text a{
float: unset;
width: 100%;
}
/*.video_card_text-img-top {*/
/* width: 100%;*/
/* height: 100%;*/
/* object-fit: cover;*/
/*}*/
/*.video_card_text {*/
/* display: block;*/
/* width: 100%;*/
/* margin-top: 10px;*/
/* background-color: #007bff;*/
/* border-radius: 5px;*/
/*}*/
/*.video_card_text a {*/
/* color: #fff;*/
/* text-align: center;*/
/* font-size: 1em;*/
/* text-decoration: none;*/
/*}*/
/*.video_card_text:hover{*/
/* background-color: #0069d9;*/
/*}*/

@ -0,0 +1,121 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
position: absolute;
left: 25%;
top: 25%;
width: 50%;
height: 100vh;
background-color: white;
}
.user-info {
display: flex;
align-items: center;
padding: 20px;
border-bottom: 1px solid #ccc;
}
.user-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
margin-right: 20px;
}
.user-id {
font-size: 24px;
font-weight: bold;
}
.user-signature {
font-size: 16px;
color: #666;
}
.user-list {
list-style: none;
}
.user-list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 15px 20px;
border-bottom: 1px solid #ccc;
}
.user-list-item-label {
font-size: 18px;
}
.user-list-item-value {
font-size: 18px;
color: #333;
}
.user-list-item-icon {
width: 20px;
height: 20px;
margin-left: 10px;
}
.user-list-item-dropdown {
display: none;
background: white;
width: 200px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.user-list-item-dropdown-input {
width: calc(100% - 20px);
margin: 10px auto;
padding-left: 10px;
border-radius: 5px;
border: none;
}
.user-list-item-dropdown-button {
width: calc(100% - 40px);
margin-left: auto;
margin-right:auto;
margin-bottom :10px ;
padding :10px ;
background-color :#2196f3 ;
color :white ;
border-radius :5px ;
border :none ;
cursor :pointer ;
}
.return_btn{
position: absolute;
left: 80%;
top: 55%;
width: 6%;
height: 5%;
margin-left: auto;
margin-right:auto;
margin-bottom :10px ;
box-shadow: 0 0 10px #66aee6;
border: solid 1px #66aee6;
border-radius: 40%;
text-align: center;
font-size: 20px;
font-weight: bolder;
background-color: #66aee6;
font-family: "Microsoft YaHei";
color: snow;
transition: all 1s;
cursor: pointer;
}
.return_btn:hover{
background-color: snow;
color: #66aee6;
box-shadow: 0 0 10px darkgray;
border: solid 1px #arkgray;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -0,0 +1,6 @@
function cont(){
if(confirm("这里是实践测试网站,相关功能可能并不成熟,是否继续?"))
return true;
else return false;
}
document.ready = cont();

@ -0,0 +1,97 @@
function Gid(id){
return document.getElementById(id);
}
let lock = false;
// 轮播图
let lis = document.getElementsByClassName("mainpage_imgs")
lis[0].style.zIndex = '10';
lis[0].style.opacity = '1';
let points=document.getElementsByClassName("points");
let timer=null;//计时器
let index=0;
let len = lis.length
let preIndex = 0
function goNext(){
mainpageImgs_descChange(index);
lis[preIndex].style.zIndex = '0';
lis[preIndex].style.opacity = '0';
lis[index].style.zIndex = '10';
lis[index].style.opacity = '1';
lis[index].style.transition ='opacity .5s';
for(let Choose = 0;Choose <=6 ; Choose++){
if (Choose !==index){
points[Choose].className = "points" ;
}
else
points[Choose].className = "points active" ;
}
}//对目标元素显示
//按钮切换
Gid("change-right").addEventListener("click",function(){
preIndex = index;
index=(index+1)%7;
goNext();
})
Gid("change-left").addEventListener("click",function(){
preIndex = index;
if(index==0) index=6;
else index--;
goNext();
})
//辅助切换
function points_change(thePrt){
preIndex = index;
index=thePrt;
goNext();
}
for(let i=0;i<points.length;i++){
points[i].addEventListener("mouseover",function(){
clearTimeout(timer);
timer = null;
})
points[i].addEventListener("mouseout",function(){
timer=setInterval('timerGoNext()',2500);
})
}
//计时切换
function timerGoNext(){
preIndex =index;
index=(index+1)%7;
goNext();
}
//初始化
function init(){
timer=setInterval('timerGoNext()',5000);
points[0].className = "points active"
}
$(document).ready(function(){
init()
});
function mainpageImgs_descChange(num2){
switch(num2){
case 0:Gid("mainPageImgsDescription").innerText = "^AI,gYY与地外文明共同奏响驶向群星的交响^";break;
case 1:Gid("mainPageImgsDescription").innerText = "^欢迎加入湘潭大学网络技术部!^";break;
case 2:Gid("mainPageImgsDescription").innerText = "^湘潭大学:军魂^";break;
case 3:Gid("mainPageImgsDescription").innerText = "^湘潭大学:一角^";break;
case 4:Gid("mainPageImgsDescription").innerText = "^前进:中国空间站^";break;
case 5:Gid("mainPageImgsDescription").innerText = "^旅程:南昌^";break;
case 6:Gid("mainPageImgsDescription").innerText = "^旧乡:晴空^";break;
}
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,84 @@
$(document).ready(function (){
close_all();
$("#login_window").show();
$("#login_enroll").on("click",function (){
close_all();
$("#enroll_window").show();
})
$("#enroll_return").on("click",function (){
close_all();
$("#login_window").show();
})
console.log("3");
//注册界面响应
$("#enroll_enrolling").on("clilk",function (){
let username = $("#username").val();
let password = $("#password").val();
let email = $("#email").val();
let study_password = $("#study_password").val();
if (username === "" || password === "" || email === "" || study_password === "")
{
alert("不能为空!");
return
}
//…………………………填充邮箱功能……………………………………//
//…………………………end……………………………………//
$.post("login",
{
"username" :username,
"password" :password,
"email":email,
"study_password":study_password
},
function(data,status) {
alert("注册成功!");
close_all();
$("#login_window").show();
}
)
})
//登录界面响应
//jquery .on对应原js中 .addEventListener
$("#submit_login").on('click', function() {
let username = $("#username").val();
let password = $("#password").val();
let email = $("#email").val();
let user_id
let user_avatar_url
if (username === "" || password === "") {
alert("用户名或密码不能为空!");
return;
}
$.post("login", {
"email": email,
"password": password,
}, function(data, status) {
// 在登录成功后,发送 AJAX 请求获取用户数据
$.get('/user_data', function(response) {
localStorage.setItem('username', response.username); // 使用响应中的用户名
localStorage.setItem('user_id', response.user_id);
localStorage.setItem('user_url',response.user_url); // 用户头像地址
localStorage.setItem('user_signature', response.user_signature);
// 在这里可以根据需要对获取到的数据进行处理
// 更新界面等操作
window.parent.location.reload();
console.log(response)
console.log(response.user_avatar_url)
window.close();
});
});
});
});
// Flask 会将一次性消息存储在名为 flash 的 cookie 中,并在响应中发送该 cookie。
// 可以使用 jQuery 插件来轻松地访问 cookie。例如可以使用 jquery.cookie 插件来获取名为 flash 的 cookie 中存储的消息。
function close_all(){
$("#enroll_window").hide();
$("#login_window").hide();
}

@ -0,0 +1,39 @@
function bindEmailCaptchaClick(){
$("#captcha-btn").click(function (event) {
var $this = $(this);
event.preventDefault();
var email = $("input[name='email']").val();
$.ajax({
url: "/captcha/email?email="+email,
method: 'GET',
success: function (result){
var code = result['code'];
if(code == 200){
var countdown = 60;
$this.off('click');
var timer = setInterval(function (){
$this.text(countdown);
countdown--;
if(countdown <= 0) {
clearInterval(timer);
$this.text('获取验证码');
bindEmailCaptchaClick();
}
},1000);
alert('验证码发送成功!');
}else {
alert(result['message']);
}
console.log(result);
},
fail: function (error){
console.log(error);
}
})
});
}
$(function (){
bindEmailCaptchaClick();
});

@ -0,0 +1,517 @@
// 获得浏览器中session中的username,未设置为null
let username;
let user_id;
let video_tite;
let resources = $("#index_resources")
let video = $("#index_video")
let music = $("#index_music")
let doc = $("#index_doc")
let mine = $("#index_mine")
let video_left_autoplay = document.querySelector("#video_left_autoplay") //为原生js对象
let collection_list = [];
let liked_list = [];
$(document).ready(function () {
let left_navs = document.getElementsByClassName('left_navs');
for (let i = 0; i < left_navs.length; i++) {
left_navs[i].addEventListener('mouseenter', function () {
this.className = 'left_navs_chosed';
})
left_navs[i].addEventListener('mouseout', function () {
this.className = 'left_navs';
})
}
for (let t = 0; t < left_navs.length; t++) {
switch (t) {
case 4:
left_navs[t].addEventListener('click', function () {
login_config()
})
}
}
//定时检测更新用户登录状态
timer = setInterval(user_init, 1000);
// window.addEventListener('message', function(event) {
// if (event.origin !== window.location.origin) return; // 必须校验消息来源
// if (event.data.type === 'login') {
// // 更新页面内容
// alert(event.data.username)
// // }
// }) 对应的login.js中未使用的通信方式
let ball = $(".floating-ball")
let container = $(".container")
//为导航栏绑定事件
let navs = $(".left_nav ul")
navs.on('click', 'li', function () {
var id = $(this).attr('id');
// 根据 ID 匹配不同的事件
switch (id) {
case 'item1':
close_all();
resources.show();
break;
case 'item2':
close_all();
video.show();
video_left_autoplay.play();
break;
case 'item3':
close_all();
music.show();
break;
case 'item4':
close_all();
doc.show();
break;
case 'item5':
close_all();
mine.show();
break;
default:
// 如果都不匹配,不执行任何操作
break;
}
})
// 资源详情页
ball.each(function () {
let w = container.width();
$(this).css("width", w * 0.15);
$(this).css("height", w * 0.15);
})
setInterval(function () {
ball.each(function () {
moveBall($(this));
})
}, 1000)
// 获取四个悬浮球元素
let docBall = document.querySelector('#doc-ball');
let videoBall = document.querySelector('#video-ball');
let myBall = document.querySelector('#my-ball');
let musicBall = document.querySelector('#music-ball');
close_all()
//默认主页为资源概述界面
resources.show()
// 为四个悬浮球元素绑定点击事件
docBall.addEventListener('click', () => {
resources.hide();
doc.show();
});
videoBall.addEventListener('click', () => {
// 点击视频悬浮球时的操作
resources.hide();
$("#video_left_autoplay").play();
video.show();
});
myBall.addEventListener('click', () => {
// 点击我的悬浮球时的操作
resources.hide();
mine.show();
});
musicBall.addEventListener('click', () => {
// 点击音乐悬浮球时的操作
resources.hide();
music.show();
});
//登录球
let login_user = $('#login')
let user_profile = $('.user_profile')
if (username !== null) {
user_profile.children('#profile').text(localStorage.getItem('user_signature'))
user_profile.find('#user_id').text(localStorage.getItem('user_id'))
}
login_user.on('click', function () {
if (username === null) {
login_config()
} else {
// ****** 打开管理界面******//
window.open('/users_manage')
}
})
login_user.on('mouseenter', function () {
user_profile.css('opacity', '100%')
})
login_user.on('mouseleave', function () {
user_profile.css('opacity', '0')
})
//……………………非“资源详情页”……………………//
//video
let play_status = $(".play_status");
play_status.css("background-color", "green");
//主页的视频
video_left_autoplay.addEventListener("pause", function () {
$(".play_status").css("background-color", "red");
})
video_left_autoplay.addEventListener("play", function () {
$(".play_status").css("background-color", "green");
})
video_left_autoplay.addEventListener("click", function () {
});
//收藏
$(".video_cards .video_card_text").each(function () {
let this_video_card_id = $(this).attr("id");
$(this).on('click', ".collection_icon", function () { //事件委托
let id = this_video_card_id
let video_href = $(this).siblings('a').attr("href");//.siblings() 表示选中兄弟元素,
if ($.inArray(id, collection_list) === -1) // 直接用in是不行的in处理的是对象
{ //不要写成this.……这个是dom对象
if (send_collecting_request(id, video_href)) {
collection_list.push(id)
console.log('collection_list:' + collection_list)
$(this).css("background-image", "url('/static/icons/收藏后.png')"); // 不要加“../”
alert("收藏成功")
} else {
alert("收藏失败,请你稍后再试!")
}
} else {
// 发送请求取消收藏请求
if (send_NoCollecting_request(id, video_href)) {
collection_list.splice($.inArray(id, collection_list), 1) //splice(索引,数量)splice在未找到是会删去最后一个元素这里已经排除了这种情况
console.log('collection_list:' + collection_list)
$(this).css("background-image", "url('/static/icons/收藏.png')"); // 不要加“../”
alert("取消收藏成功")
} else {
alert("收藏失败,请你稍后再试!")
}
}
})
$(this).on('click', ".likeit_icon", function () {
let id = this_video_card_id
// let video_href = $(this).siblings('a').attr("href");
if ($.inArray(id, liked_list) === -1)
// { //不要写成this.……这个是dom对象
// if(send_Liking_request(id,video_href)){
// collection_list.push(id)
// console.log($.inArray(id, collection_list))
{
liked_list.push(id)
$(this).css("background-image", "url('/static/icons/喜欢后.png')");
} // 不要加“../”
// alert("已添加")
// }
// else
// {
// }
else {
// 发送请求取消喜欢的请求
// if(send_NoLiked_request(id,video_href))
// {
// collection_list.splice(this_video_card_id)
$(this).css("background-image", "url('/static/icons/喜欢.png')"); // 不要加“../”
// }
// else
// {
// }
}
})
})
let rightBox = document.querySelector('.right-box');
let isScrolling = false;
rightBox.addEventListener('scroll', function () {
isScrolling = true;
});
let scroll_t = setInterval(function () {
if (isScrolling) {
isScrolling = false;
let visibleRows = Math.ceil(rightBox.clientHeight / 220);
let totalRows = document.querySelectorAll('.row').length;
if (visibleRows + rightBox.scrollTop >= totalRows) {
// 加载更多数据
}
}
}, 250);
// **********************“我的界面”控制********************//
//左侧部分
let user_options = $('.user-options')
user_options.children('li').eq(0).on('click', function () {
alert('更改信息')
})
user_options.children('li').eq(1).on('click', function () {
reLoad()
})
//右侧部分
let page_index_before = 0;
let mine_righe_page_change = $(".mine_rightbox_chosed ul li")
mine_righe_page_change.eq(0).css({
'background-color': '#00215A', 'border': '#E4FEFF solid 1px',
'box-shadow': '0 0 1rem .5rem #436495', 'color': '#F3F3F3', 'font-weight': '700'
}) //eq()方法选择对应索引的元素
mine_righe_page_change.each(function (index) {
$(this).on("click", function () {
mine_righe_page_change.eq(page_index_before).css({
'background-color': 'unset', 'font-size': 'x-small', 'box-shadow': 'none', 'border': 'none'
, 'color': 'white', 'font-weight': 'normal'
})
mine_righe_page_change.eq(index).css({
'background-color': '#00215A', 'border': '#E4FEFF solid 1px',
'box-shadow': '0 0 1rem .5rem #436495', 'color': '#F3F3F3', 'font-weight': '700'
})
page_index_before = index
})
})
let command = $('.mine_command')
let is_Nocommand = true
let delete_icon = $('.delete_icon')
command.on('click', function () {
if (is_Nocommand) {
is_Nocommand = false
delete_icon.css('display', 'block')
} else {
is_Nocommand = true
delete_icon.css('display', 'none')
}
})
$('.record-block ul li').each(function () {
$(this).children('.delete_icon').on('click', function () {
let video_id = $(this).parent('li').attr('id')
let video_href = $(this).siblings('#mine_video_card_text').children('a').attr('href')
if (send_NoCollecting_request(video_id, video_href)) {
console.log("delete:" + video_id)
collection_list.splice(video_id)
$(this).parent('li').remove()
update_video_list()
}
})
})
});
function login_config() {
if (username === null) {
if (confirm("您还未登入,是否登入用户")) {
window.open("/login")
}
}
}
function cont() {
return confirm("网站测试中,相关功能可能并不成熟,是否继续?");
}
// function user_init() {
// $.get('/user_data', function(response) {
// localStorage.setItem('username', response.username); // 使用响应中的用户名
// localStorage.setItem('user_id', response.user_id);
// localStorage.setItem('user_url',response.user_url); // 用户头像地址
// // 在这里可以根据需要对获取到的数据进行处理
// // 更新界面等操作
// console.log(response)
// console.log(response.user_avatar_url)
// window.close();
// });
//
// username = localStorage.getItem('username');
// user_id = localStorage.getItem('user_id')
// let user_head_img = localStorage.getItem('user_url')
//
// if (username !== null) {
// $('#id_n').text(username);
// alert(`欢迎您:${username}`)
// $('#id_p').css('background-image', 'url(' + user_head_img + ')')
// console.log("user_id:" + user_id)
// console.log(user_head_img)
// $(".signature").text("欢迎您," + username + "")
// clearInterval(timer)
// // 从后端获取该用户的收藏喜欢信息
// let user = {
// 'user_id': user_id,
// 'username': username,
// }
// $.ajax({
// type: 'POST',
// url: '/resources/video/init',
// contentType: 'application/json',
// data: JSON.stringify(user),
// success: function (response) {
// if (response.length === 0) $('#NoVideo').css('display', 'block')
// else $('#NoVideo').css('display', 'none')
// for (let i = 0; i < response.length; i++) {
// let videoId = response[i].video_id;
// collection_list.push(videoId); // 将 video_id 值添加到数组中
// console.log(response)
// }
//
// },
// error: function (e) {
// console.log(e)
// alert('用户信息获取失败!请检测登录状态或检测网络')
// },
// dataType: "json"
// });
// }
// }
function user_init() {
username = localStorage.getItem('username');
user_id = localStorage.getItem('user_id');
let user_head_img = localStorage.getItem('user_url')
user_head_img = "/static/" + user_head_img
if (username !== null) {
$('#id_n').text(username);
alert(`欢迎您:${username}`)
$('#id_p').css('background-image', 'url(' + user_head_img + ')')
console.log("user_id:" + user_id)
console.log(user_head_img)
$(".signature").text("欢迎您," + username + "")
clearInterval(timer)
// 从后端获取该用户的收藏喜欢信息
let user = {
'user_id': user_id,
'username': username,
}
$.ajax({
type: 'POST',
url: '/resources/video/init',
contentType: 'application/json',
data: JSON.stringify(user),
success: function (response) {
if (response.length === 0) $('#NoVideo').css('display', 'block')
else $('#NoVideo').css('display', 'none')
for (let i = 0; i < response.length; i++) {
let videoId = response[i].video_id;
collection_list.push(videoId); // 将 video_id 值添加到数组中
$(".video_cards").find('#'+videoId).children('.collection_icon').css("background-image", "url('/static/icons/收藏后.png')")
}
console.log(collection_list)
},
error: function (e) {
console.log(e)
alert('用户信息获取失败!请检测登录状态或检测网络')
},
dataType: "json"
});
}
}
// 为每个悬浮球随机生成运动方向和速度
function getRandomPos() {
var len = $(".floating-ball");
var w = len.width() - 150; // 可移动范围
var h = len.height() - 150;
var left = Math.floor(Math.random() * w); // 随机生成位置
var top = Math.floor(Math.random() * h);
return {
left: left,
top: top
};
}
function moveBall($ball) {
var pos = getRandomPos();
pos = getRandomPos();
$ball.animate({
left: pos.left,
top: pos.top
}, 5000, function () {
moveBall($ball);
});
}
// 发送收藏视频请求
function send_collecting_request(video_id, video_href) {
let collect_video = {
'user_id': user_id,
'username': username,
'video_href': video_href,
'id': video_id
}
let static_flag = true
$.ajax({
type: 'POST',
url: '/resources/video/collection_update',
contentType: 'application/json',
data: JSON.stringify(collect_video),
success: function (response) {
console.log(response)
static_flag = true
},
error: function () {
static_flag = false
},
dataType: "json"
});
return static_flag
}
//取消视频收藏
function send_NoCollecting_request(video_id, video_href) {
let collect_video = {
'user_id': user_id,
'username': username,
'video_tite': video_tite,
'video_href': video_href,
'id': video_id
}
let static_flag = true
$.ajax({
type: 'POST',
url: '/resources/video/collecting_cancel',
contentType: 'application/json',
data: JSON.stringify(collect_video),
success: function (response) {
console.log(response)
static_flag = true
},
error: function () {
static_flag = false
},
dataType: "json"
});
return static_flag
}
// 检测collection-list中的内容用于我的页面的局部更新
function update_video_list() {
if (collection_list.length === 0) $('#NoVideo').css('display', 'block')
else $('#NoVideo').css('display', 'none')
}
function close_all() {
resources.hide()
music.hide()
doc.hide()
mine.hide()
video.hide()
video_left_autoplay.pause()
}
function reLoad() {
// 清除浏览器中的localStorage内容
localStorage.clear();
// 刷新页面
location.reload();
}
document.ready = cont();

@ -0,0 +1,207 @@
$(document).ready(function(){
let user_id = localStorage.getItem('user_id')
let username = localStorage.getItem('username')
// Get the list items and dropdowns
let emailItem = $("#email-item");
let emailDropdown = $("#email-dropdown");
let addressItem = $("#address-item");
let addressDropdown = $("#address-dropdown");
let enterpriseItem = $("#enterprise-item");
let enterpriseDropdown = $("#enterprise-dropdown");
let stu_idItem = $("#stu_id-item");
let stu_idDropdown = $("#stu_id-dropdown");
let useravatarItem = $("#user_avatar-item");
let useravatarDropdown = $("#user_avatar-dropdown");
// Get the input fields and buttons
let emailInput = $("#email-input");
let emailButton = $("#email-button");
let addressInput = $("#address-input");
let addressButton = $("#address-button");
let enterpriseInput = $("#enterprise-input");
let enterpriseButton = $("#enterprise-button");
let stu_idInput = $("#stu_id-input");
let stu_idButton = $("#stu_id-button");
let useravatarInput = $("#user_avatar-input");
let useravatarButton = $("#user_avatar-button");
let user_list_item = $('.user-list-item')
user_list_item.each(function (){
$(this).children('img').on('click',function (){
$(this).siblings('.user-list-item-dropdown').css('display','block')
})
$(this).children('.user-list-item-dropdown').children('button').eq(1).on('click',function (){
$(this).parent('.user-list-item-dropdown').css('display','none')
})
})
// Change the list item value when clicking on the buttons
emailButton.click(function() {
let newEmail = emailInput.val();
if (change_email(user_id,newEmail)) {
emailItem.find(".user-list-item-value").text(newEmail);
emailInput.val("");
alert("Email changed successfully!");
} else {
alert("Email changed successfully!");
}
});
addressButton.click(function() {
let newAddress = addressInput.val();
if (change_address(user_id,newAddress)) {
addressItem.find(".user-list-item-value").text(newAddress);
addressInput.val("");
alert("Address changed successfully!");
} else {
alert("Address changed successfully!");
}
});
enterpriseButton.click(function() {
let newEnterprise = enterpriseInput.val();
if (change_enterprise(user_id,newEnterprise)){
enterpriseItem.find(".user-list-item-value").text(newEnterprise);
enterpriseInput.val("");
alert("Enterprise changed successfully!");
} else {
alert("Enterprise changed successfully!");
}
});
stu_idButton.click(function() {
let newstu_id = stu_idInput.val();
console.log(user_id)
console.log(newstu_id)
if (change_stu_id(user_id,newstu_id) !== 'true') {
enterpriseItem.find(".user-list-item-value").text(newstu_id);
enterpriseInput.val("");
alert("stu_id changed successfully!");
} else {
alert("stu_id changed successfully!");
}
});
useravatarInput.on("change", function() {
var file = this.files[0]; // Get the selected file
// Create a new FormData object
var formData = new FormData();
formData.append("avatar", file); // Append the file to the FormData object
alert("ok")
$.ajax({
url: "/upload-avatar", // Replace with your server-side endpoint for handling the avatar upload
type: "POST",
data: formData,
processData: false,
contentType: false,
success: function(response) {
console.log("Avatar uploaded successfully!");
},
error: function(e) {
console.log(e)
}
});
})
// Add more event handlers here
$('.return_btn').on('click',function (){
window.parent.location.reload()
window.close()
})
})
function change_stu_id(user_id,changed_data){
let sta = false;
let data = {
'user_id':user_id,
'stu_id':changed_data,
}
$.ajax({
url: "/upload-stu_id", // Replace with your server-side endpoint for handling the avatar upload
type: "POST",
data: JSON.stringify(data),
contentType: 'application/json',
success: function(response) {
console.log("Avatar uploaded successfully!");
sta = true;
},
error: function(xhr, status, error) {
console.error("Error uploading avatar:", error);
sta = false;
}
});
return sta
}
function change_email(user_id,changed_data){
let sta = 'false';
let data = {
'user_id':user_id,
'email':changed_data,
}
$.ajax({
url: "/upload-email", // Replace with your server-side endpoint for handling the avatar upload
type: "POST",
data: JSON.stringify(data),
contentType:'application/json',
success: function() {
console.log("email uploaded successfully!");
sta = 'true'
},
error: function() {
console.log("error")
sta = 'false'
}
});
return sta
}
function change_address(user_id,changed_data){
let sta = false;
let data = {
'user_id':user_id,
'address':changed_data,
}
$.ajax({
url: "/upload-address", // Replace with your server-side endpoint for handling the avatar upload
type: "POST",
data: JSON.stringify(data),
contentType: 'application/json',
success: function(response) {
console.log("address uploaded successfully!");
sta = true
},
error: function(xhr, status, error) {
console.error("Error uploading address:", error);
sta = false
}
});
return sta
}
function change_enterprise(user_id,changed_data){
let sta = false;
let data = {
'user_id':user_id,
'enterprise':changed_data,
}
$.ajax({
url: "/upload-enterprise", // Replace with your server-side endpoint for handling the avatar upload
type: "POST",
data: JSON.stringify(data),
contentType: 'application/json',
success: function(response) {
console.log("enterprise uploaded successfully!");
sta = true
},
error: function(xhr, status, error) {
console.error("Error uploading enterprise:", error);
sta = false
}
});
return sta
}

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save