├── .gitignore ├── README.md ├── app ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20200210_1715.py │ ├── 0003_product_expire.py │ ├── 0004_remove_product_desc.py │ ├── 0005_auto_20200211_1132.py │ └── __init__.py ├── models.py ├── templatetags │ ├── __init__.py │ └── app_tag.py ├── tests.py ├── urls.py └── views.py ├── helpers.py ├── manage.py ├── mask.conf ├── mask ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py ├── python_mask.sql ├── requirements.txt ├── static ├── css │ ├── semantic.custom.css │ ├── style.css │ └── style_v2.css ├── img │ ├── .DS_Store │ ├── demo01.png │ ├── demo02.png │ ├── demo03.png │ ├── ic_buy.png │ ├── ic_consumer.png │ ├── ic_provider.png │ ├── ic_sell.png │ └── logo.png └── js │ ├── clipboard.min.js │ ├── common-v2.js │ ├── function-new.js │ ├── jquery.min.js │ ├── layer.js │ ├── m-detail.js │ ├── webcam.js │ └── webcam.min.js ├── templates ├── app │ ├── commit.html │ ├── demo.html │ ├── detail.html │ ├── index.html │ └── search.html └── base │ ├── base.html │ ├── footer.html │ ├── form_errors.html │ ├── form_messages.html │ ├── header.html │ └── page_nav.html └── 开发过程.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | __pycache__ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > 学习过程中,遇到问题可以付费咨询:lengqin1024(微信) 2 | 3 | ### 演示地址 4 | 5 | http://mask.gitapp.cn 6 | 7 | ### 项目简介 8 | 9 | 该项目是基于python的web类库django开发的一套web网站,给同学做的课程作业。 10 | 开发环境是python 3.8 + django 3.2 + mysql 5.7 11 | 12 | ### 运行步骤 13 | 14 | 1. 安装依赖包,运行命令:pip install -r requirements.txt 15 | 2. 恢复数据库,运行命令: python manage.py migrate 16 | 3. 运行项目,运行命令: python manage.py runserver 17 | 18 | 19 | **首页展示** 20 | 21 | ![](https://github.com/geeeeeeeek/mask/blob/master/static/img/demo01.png) 22 | 23 | 24 | **发布页** 25 | 26 | ![](https://github.com/geeeeeeeek/mask/blob/master/static/img/demo02.png) 27 | 28 | 29 | **详情页** 30 | 31 | ![](https://github.com/geeeeeeeek/mask/blob/master/static/img/demo03.png) 32 | 33 | 34 | ### 付费咨询 35 | 36 | 微信: lengqin1024 37 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | pymysql.install_as_MySQLdb() 3 | 4 | print("===============install pymysql==============") -------------------------------------------------------------------------------- /app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | from app.models import Product 5 | 6 | admin.site.register(Product) -------------------------------------------------------------------------------- /app/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AppConfig(AppConfig): 5 | name = 'app' 6 | -------------------------------------------------------------------------------- /app/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from app.models import Product 4 | 5 | 6 | class CommitForm(forms.ModelForm): 7 | class Meta: 8 | model = Product 9 | fields = ['title', 'type', 'contact', 'location', 'phone', 'weixin', 'expire'] 10 | -------------------------------------------------------------------------------- /app/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2020-02-10 06:35 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Product', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('title', models.CharField(blank=True, max_length=100, null=True)), 19 | ('hot', models.IntegerField(default=0)), 20 | ('desc', models.CharField(blank=True, max_length=200, null=True)), 21 | ('contact', models.CharField(blank=True, max_length=100, null=True)), 22 | ('phone', models.CharField(blank=True, max_length=13, null=True)), 23 | ('weixin', models.CharField(blank=True, max_length=50, null=True)), 24 | ('status', models.BooleanField(default=False)), 25 | ('timestamp', models.DateTimeField(auto_now_add=True, null=True)), 26 | ], 27 | options={ 28 | 'db_table': 'mask_product', 29 | }, 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /app/migrations/0002_auto_20200210_1715.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2020-02-10 17:15 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('app', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='product', 15 | old_name='hot', 16 | new_name='type', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /app/migrations/0003_product_expire.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2020-02-11 09:54 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('app', '0002_auto_20200210_1715'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='product', 15 | name='expire', 16 | field=models.IntegerField(default=1), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /app/migrations/0004_remove_product_desc.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2020-02-11 10:21 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('app', '0003_product_expire'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='product', 15 | name='desc', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /app/migrations/0005_auto_20200211_1132.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2020-02-11 11:32 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('app', '0004_remove_product_desc'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='product', 15 | name='location', 16 | field=models.CharField(blank=True, max_length=20, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='product', 20 | name='pv', 21 | field=models.IntegerField(default=0), 22 | ), 23 | migrations.AlterField( 24 | model_name='product', 25 | name='contact', 26 | field=models.CharField(blank=True, max_length=10, null=True), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /app/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/app/migrations/__init__.py -------------------------------------------------------------------------------- /app/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | 5 | class Product(models.Model): 6 | list_display = ("title", "type", "location") 7 | title = models.CharField(max_length=100,blank=True, null=True) 8 | type = models.IntegerField(default=0) 9 | pv = models.IntegerField(default=0) 10 | contact = models.CharField(max_length=10,blank=True, null=True) 11 | location = models.CharField(max_length=20,blank=True, null=True) 12 | phone = models.CharField(max_length=13, blank=True, null=True) 13 | weixin = models.CharField(max_length=50, blank=True, null=True) 14 | status = models.BooleanField(default=False) 15 | timestamp = models.DateTimeField(auto_now_add=True, null=True) 16 | expire = models.IntegerField(default=1) 17 | 18 | def __str__(self): 19 | return self.title 20 | 21 | class Meta: 22 | db_table = "mask_product" 23 | -------------------------------------------------------------------------------- /app/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/app/templatetags/__init__.py -------------------------------------------------------------------------------- /app/templatetags/app_tag.py: -------------------------------------------------------------------------------- 1 | from datetime import date, datetime 2 | from django.utils.timezone import is_aware, utc 3 | 4 | from django import template 5 | register = template.Library() 6 | 7 | @register.filter 8 | def time_since(value, default="刚刚"): 9 | if not isinstance(value, date): # datetime is a subclass of date 10 | return value 11 | now = datetime.now(utc if is_aware(value) else None) 12 | diff = now - value 13 | periods = ( 14 | (diff.days / 365, "年"), 15 | (diff.days / 30, "个月"), 16 | (diff.days / 7, "周"), 17 | (diff.days, "天"), 18 | (diff.seconds / 3600, "小时"), 19 | (diff.seconds / 60, "分钟"), 20 | (diff.seconds, "秒"), 21 | ) 22 | for period, singular in periods: 23 | if int(period) > 0: 24 | return "%d%s前" % (period, singular) 25 | return default 26 | 27 | 28 | @register.filter 29 | def check_expire(value): 30 | if not isinstance(value, date): # datetime is a subclass of date 31 | return value 32 | now = datetime.now(utc if is_aware(value) else None) 33 | diff = now - value 34 | return diff.days 35 | -------------------------------------------------------------------------------- /app/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /app/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = 'app' 5 | urlpatterns = [ 6 | path('index', views.IndexView.as_view(), name='index'), 7 | path('detail/', views.DetailView.as_view(), name='detail'), 8 | path('commit', views.CommitView.as_view(), name='commit') 9 | ] -------------------------------------------------------------------------------- /app/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib import messages 2 | from django.shortcuts import render 3 | 4 | # Create your views here. 5 | from django.urls import reverse 6 | from django.views import generic 7 | from ratelimit.decorators import ratelimit 8 | from app.forms import CommitForm 9 | from app.models import Product 10 | from helpers import get_page_list 11 | 12 | 13 | class IndexView(generic.ListView): 14 | model = Product 15 | template_name = 'app/index.html' 16 | context_object_name = 'product_list' 17 | paginate_by = 15 18 | c = None 19 | 20 | def get_context_data(self, *, object_list=None, **kwargs): 21 | context = super(IndexView, self).get_context_data(**kwargs) 22 | paginator = context.get('paginator') 23 | page = context.get('page_obj') 24 | page_list = get_page_list(paginator, page) 25 | context['c'] = self.c 26 | context['page_list'] = page_list 27 | return context 28 | 29 | def get_queryset(self): 30 | self.c = self.request.GET.get("c", None) 31 | if self.c: 32 | return Product.objects.filter(type=self.c).filter(status=1).order_by('-timestamp') 33 | else: 34 | return Product.objects.filter(status=1).order_by('-timestamp') 35 | 36 | 37 | class DetailView(generic.DetailView): 38 | model = Product 39 | template_name = 'app/detail.html' 40 | 41 | def get_object(self, queryset=None): 42 | obj = super().get_object() 43 | return obj 44 | 45 | def get_context_data(self, **kwargs): 46 | context = super(DetailView, self).get_context_data(**kwargs) 47 | return context 48 | 49 | 50 | class CommitView(generic.CreateView): 51 | 52 | model = Product 53 | form_class = CommitForm 54 | template_name = 'app/commit.html' 55 | 56 | @ratelimit(key='ip', rate='100/h') 57 | def post(self, request, *args, **kwargs): 58 | was_limited = getattr(request, 'limited', False) 59 | if was_limited: 60 | messages.warning(self.request, "操作太频繁了,请1分钟后再试") 61 | return render(request, 'app/commit.html', {'form': CommitForm()}) 62 | return super().post(request, *args, **kwargs) 63 | 64 | def get_success_url(self): 65 | messages.success(self.request, "发布成功! ") 66 | return reverse('app:commit') 67 | -------------------------------------------------------------------------------- /helpers.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import time 3 | 4 | from django.http import HttpResponseBadRequest 5 | 6 | 7 | def get_page_list(paginator, page): 8 | 9 | """ 10 | 分页逻辑 11 | if 页数>=10: 12 | 当前页<=5时,起始页为1 13 | 当前页>(总页数-5)时,起始页为(总页数-9) 14 | 其他情况 起始页为(当前页-5) 15 | """ 16 | 17 | page_list = [] 18 | 19 | if paginator.num_pages > 10: 20 | if page.number <= 5: 21 | start_page = 1 22 | elif page.number > paginator.num_pages - 5: 23 | start_page = paginator.num_pages - 9 24 | else: 25 | start_page = page.number - 5 26 | 27 | for i in range(start_page, start_page + 10): 28 | page_list.append(i) 29 | else: 30 | for i in range(1, paginator.num_pages + 1): 31 | page_list.append(i) 32 | 33 | return page_list 34 | 35 | def ajax_required(f): 36 | """Not a mixin, but a nice decorator to validate than a request is AJAX""" 37 | def wrap(request, *args, **kwargs): 38 | if not request.is_ajax(): 39 | return HttpResponseBadRequest() 40 | 41 | return f(request, *args, **kwargs) 42 | 43 | wrap.__doc__ = f.__doc__ 44 | wrap.__name__ = f.__name__ 45 | return wrap 46 | 47 | 48 | def string2timestamp(strValue): 49 | try: 50 | d = datetime.datetime.strptime(strValue, "%Y-%m-%d %H:%M:%S.%f") 51 | t = d.timetuple() 52 | timeStamp = int(time.mktime(t)) 53 | timeStamp = float(str(timeStamp) + str("%06d" % d.microsecond)) / 1000000 54 | return timeStamp 55 | except ValueError as e: 56 | print(e) 57 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mask.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /mask.conf: -------------------------------------------------------------------------------- 1 | 2 | upstream i { 3 | server 127.0.0.1:8004; 4 | } 5 | 6 | 7 | server { 8 | listen 80; 9 | server_name i.mypython.me; 10 | rewrite ^(.*) https://$host$1 permanent; 11 | } 12 | 13 | 14 | server { 15 | listen 443; 16 | server_name i.mypython.me; 17 | ssl on; 18 | ssl_certificate /home/ubuntu/1_i.mypython.me_bundle.crt; 19 | ssl_certificate_key /home/ubuntu/2_i.mypython.me.key; 20 | ssl_session_timeout 5m; 21 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 22 | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 23 | ssl_prefer_server_ciphers on; 24 | 25 | location /static/ { 26 | alias /var/www/mask/static/; 27 | } 28 | 29 | location / { 30 | include uwsgi_params; 31 | uwsgi_pass i; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /mask/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/mask/__init__.py -------------------------------------------------------------------------------- /mask/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for mask project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.1.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.1/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | # Quick-start development settings - unsuitable for production 19 | # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ 20 | 21 | # SECURITY WARNING: keep the secret key used in production secret! 22 | SECRET_KEY = '^0=kibvej3mquo#t+&-z+3bc15ahijvdb$q30g&0@q#!^5r$wo' 23 | 24 | # SECURITY WARNING: don't run with debug turned on in production! 25 | DEBUG = True 26 | 27 | ALLOWED_HOSTS = ['127.0.0.1'] 28 | 29 | # Application definition 30 | 31 | INSTALLED_APPS = [ 32 | 'django.contrib.admin', 33 | 'django.contrib.auth', 34 | 'django.contrib.contenttypes', 35 | 'django.contrib.sessions', 36 | 'django.contrib.messages', 37 | 'django.contrib.staticfiles', 38 | 'app' 39 | ] 40 | 41 | MIDDLEWARE = [ 42 | 'django.middleware.security.SecurityMiddleware', 43 | 'django.contrib.sessions.middleware.SessionMiddleware', 44 | 'django.middleware.common.CommonMiddleware', 45 | 'django.middleware.csrf.CsrfViewMiddleware', 46 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 47 | 'django.contrib.messages.middleware.MessageMiddleware', 48 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 49 | ] 50 | 51 | ROOT_URLCONF = 'mask.urls' 52 | 53 | TEMPLATES = [ 54 | { 55 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 56 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 57 | 'APP_DIRS': True, 58 | 'OPTIONS': { 59 | 'context_processors': [ 60 | 'django.template.context_processors.debug', 61 | 'django.template.context_processors.request', 62 | 'django.contrib.auth.context_processors.auth', 63 | 'django.contrib.messages.context_processors.messages', 64 | ], 65 | }, 66 | }, 67 | ] 68 | 69 | WSGI_APPLICATION = 'mask.wsgi.application' 70 | 71 | # Database 72 | # https://docs.djangoproject.com/en/2.1/ref/settings/#databases 73 | 74 | DATABASES = { 75 | 'default': { 76 | 'ENGINE': 'django.db.backends.mysql', 77 | 'NAME': 'python_mask', # 创建的数据库 78 | 'USER': 'root', 79 | 'PASSWORD': '123456', # 你的mysql密码 80 | 'HOST': '127.0.0.1', 81 | 'PORT': '3306', 82 | } 83 | } 84 | 85 | # Password validation 86 | # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators 87 | 88 | AUTH_PASSWORD_VALIDATORS = [ 89 | { 90 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 91 | }, 92 | { 93 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 94 | }, 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 100 | }, 101 | ] 102 | 103 | -------------------------------------------------------------------------------- /mask/urls.py: -------------------------------------------------------------------------------- 1 | """mask URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.1/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path, include 18 | 19 | from app import views 20 | 21 | urlpatterns = [ 22 | path('admin/', admin.site.urls), 23 | path('app/', include('app.urls')), 24 | path('', views.IndexView.as_view(), name='home'), # 默认首页 25 | ] 26 | -------------------------------------------------------------------------------- /mask/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mask project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mask.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /python_mask.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost连接 5 | Source Server Type : MySQL 6 | Source Server Version : 50737 7 | Source Host : localhost:3306 8 | Source Schema : python_mask 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50737 12 | File Encoding : 65001 13 | 14 | Date: 03/07/2023 16:46:59 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for auth_group 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `auth_group`; 24 | CREATE TABLE `auth_group` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `name` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 27 | PRIMARY KEY (`id`) USING BTREE, 28 | UNIQUE INDEX `name`(`name`) USING BTREE 29 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 30 | 31 | -- ---------------------------- 32 | -- Records of auth_group 33 | -- ---------------------------- 34 | 35 | -- ---------------------------- 36 | -- Table structure for auth_group_permissions 37 | -- ---------------------------- 38 | DROP TABLE IF EXISTS `auth_group_permissions`; 39 | CREATE TABLE `auth_group_permissions` ( 40 | `id` int(11) NOT NULL AUTO_INCREMENT, 41 | `group_id` int(11) NOT NULL, 42 | `permission_id` int(11) NOT NULL, 43 | PRIMARY KEY (`id`) USING BTREE, 44 | UNIQUE INDEX `auth_group_permissions_group_id_permission_id_0cd325b0_uniq`(`group_id`, `permission_id`) USING BTREE, 45 | INDEX `auth_group_permissio_permission_id_84c5c92e_fk_auth_perm`(`permission_id`) USING BTREE, 46 | CONSTRAINT `auth_group_permissio_permission_id_84c5c92e_fk_auth_perm` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, 47 | CONSTRAINT `auth_group_permissions_group_id_b120cbf9_fk_auth_group_id` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT 48 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 49 | 50 | -- ---------------------------- 51 | -- Records of auth_group_permissions 52 | -- ---------------------------- 53 | 54 | -- ---------------------------- 55 | -- Table structure for auth_permission 56 | -- ---------------------------- 57 | DROP TABLE IF EXISTS `auth_permission`; 58 | CREATE TABLE `auth_permission` ( 59 | `id` int(11) NOT NULL AUTO_INCREMENT, 60 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 61 | `content_type_id` int(11) NOT NULL, 62 | `codename` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 63 | PRIMARY KEY (`id`) USING BTREE, 64 | UNIQUE INDEX `auth_permission_content_type_id_codename_01ab375a_uniq`(`content_type_id`, `codename`) USING BTREE, 65 | CONSTRAINT `auth_permission_content_type_id_2f476e4b_fk_django_co` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT 66 | ) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 67 | 68 | -- ---------------------------- 69 | -- Records of auth_permission 70 | -- ---------------------------- 71 | INSERT INTO `auth_permission` VALUES (1, 'Can add log entry', 1, 'add_logentry'); 72 | INSERT INTO `auth_permission` VALUES (2, 'Can change log entry', 1, 'change_logentry'); 73 | INSERT INTO `auth_permission` VALUES (3, 'Can delete log entry', 1, 'delete_logentry'); 74 | INSERT INTO `auth_permission` VALUES (4, 'Can view log entry', 1, 'view_logentry'); 75 | INSERT INTO `auth_permission` VALUES (5, 'Can add permission', 2, 'add_permission'); 76 | INSERT INTO `auth_permission` VALUES (6, 'Can change permission', 2, 'change_permission'); 77 | INSERT INTO `auth_permission` VALUES (7, 'Can delete permission', 2, 'delete_permission'); 78 | INSERT INTO `auth_permission` VALUES (8, 'Can view permission', 2, 'view_permission'); 79 | INSERT INTO `auth_permission` VALUES (9, 'Can add group', 3, 'add_group'); 80 | INSERT INTO `auth_permission` VALUES (10, 'Can change group', 3, 'change_group'); 81 | INSERT INTO `auth_permission` VALUES (11, 'Can delete group', 3, 'delete_group'); 82 | INSERT INTO `auth_permission` VALUES (12, 'Can view group', 3, 'view_group'); 83 | INSERT INTO `auth_permission` VALUES (13, 'Can add user', 4, 'add_user'); 84 | INSERT INTO `auth_permission` VALUES (14, 'Can change user', 4, 'change_user'); 85 | INSERT INTO `auth_permission` VALUES (15, 'Can delete user', 4, 'delete_user'); 86 | INSERT INTO `auth_permission` VALUES (16, 'Can view user', 4, 'view_user'); 87 | INSERT INTO `auth_permission` VALUES (17, 'Can add content type', 5, 'add_contenttype'); 88 | INSERT INTO `auth_permission` VALUES (18, 'Can change content type', 5, 'change_contenttype'); 89 | INSERT INTO `auth_permission` VALUES (19, 'Can delete content type', 5, 'delete_contenttype'); 90 | INSERT INTO `auth_permission` VALUES (20, 'Can view content type', 5, 'view_contenttype'); 91 | INSERT INTO `auth_permission` VALUES (21, 'Can add session', 6, 'add_session'); 92 | INSERT INTO `auth_permission` VALUES (22, 'Can change session', 6, 'change_session'); 93 | INSERT INTO `auth_permission` VALUES (23, 'Can delete session', 6, 'delete_session'); 94 | INSERT INTO `auth_permission` VALUES (24, 'Can view session', 6, 'view_session'); 95 | INSERT INTO `auth_permission` VALUES (25, 'Can add product', 7, 'add_product'); 96 | INSERT INTO `auth_permission` VALUES (26, 'Can change product', 7, 'change_product'); 97 | INSERT INTO `auth_permission` VALUES (27, 'Can delete product', 7, 'delete_product'); 98 | INSERT INTO `auth_permission` VALUES (28, 'Can view product', 7, 'view_product'); 99 | 100 | -- ---------------------------- 101 | -- Table structure for auth_user 102 | -- ---------------------------- 103 | DROP TABLE IF EXISTS `auth_user`; 104 | CREATE TABLE `auth_user` ( 105 | `id` int(11) NOT NULL AUTO_INCREMENT, 106 | `password` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 107 | `last_login` datetime(6) NULL DEFAULT NULL, 108 | `is_superuser` tinyint(1) NOT NULL, 109 | `username` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 110 | `first_name` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 111 | `last_name` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 112 | `email` varchar(254) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 113 | `is_staff` tinyint(1) NOT NULL, 114 | `is_active` tinyint(1) NOT NULL, 115 | `date_joined` datetime(6) NOT NULL, 116 | PRIMARY KEY (`id`) USING BTREE, 117 | UNIQUE INDEX `username`(`username`) USING BTREE 118 | ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 119 | 120 | -- ---------------------------- 121 | -- Records of auth_user 122 | -- ---------------------------- 123 | INSERT INTO `auth_user` VALUES (1, 'pbkdf2_sha256$260000$wXFyqq31hD8pmV1excqj3Y$qsTuvbNxrBdEEEcmI8D0PriT7VDyvooTfEqdIUxR/9M=', '2023-07-03 16:14:15.257199', 1, 'admin', '', '', '', 1, 1, '2023-07-03 16:13:57.920874'); 124 | 125 | -- ---------------------------- 126 | -- Table structure for auth_user_groups 127 | -- ---------------------------- 128 | DROP TABLE IF EXISTS `auth_user_groups`; 129 | CREATE TABLE `auth_user_groups` ( 130 | `id` int(11) NOT NULL AUTO_INCREMENT, 131 | `user_id` int(11) NOT NULL, 132 | `group_id` int(11) NOT NULL, 133 | PRIMARY KEY (`id`) USING BTREE, 134 | UNIQUE INDEX `auth_user_groups_user_id_group_id_94350c0c_uniq`(`user_id`, `group_id`) USING BTREE, 135 | INDEX `auth_user_groups_group_id_97559544_fk_auth_group_id`(`group_id`) USING BTREE, 136 | CONSTRAINT `auth_user_groups_group_id_97559544_fk_auth_group_id` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, 137 | CONSTRAINT `auth_user_groups_user_id_6a12ed8b_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT 138 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 139 | 140 | -- ---------------------------- 141 | -- Records of auth_user_groups 142 | -- ---------------------------- 143 | 144 | -- ---------------------------- 145 | -- Table structure for auth_user_user_permissions 146 | -- ---------------------------- 147 | DROP TABLE IF EXISTS `auth_user_user_permissions`; 148 | CREATE TABLE `auth_user_user_permissions` ( 149 | `id` int(11) NOT NULL AUTO_INCREMENT, 150 | `user_id` int(11) NOT NULL, 151 | `permission_id` int(11) NOT NULL, 152 | PRIMARY KEY (`id`) USING BTREE, 153 | UNIQUE INDEX `auth_user_user_permissions_user_id_permission_id_14a6b632_uniq`(`user_id`, `permission_id`) USING BTREE, 154 | INDEX `auth_user_user_permi_permission_id_1fbb5f2c_fk_auth_perm`(`permission_id`) USING BTREE, 155 | CONSTRAINT `auth_user_user_permi_permission_id_1fbb5f2c_fk_auth_perm` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, 156 | CONSTRAINT `auth_user_user_permissions_user_id_a95ead1b_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT 157 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 158 | 159 | -- ---------------------------- 160 | -- Records of auth_user_user_permissions 161 | -- ---------------------------- 162 | 163 | -- ---------------------------- 164 | -- Table structure for django_admin_log 165 | -- ---------------------------- 166 | DROP TABLE IF EXISTS `django_admin_log`; 167 | CREATE TABLE `django_admin_log` ( 168 | `id` int(11) NOT NULL AUTO_INCREMENT, 169 | `action_time` datetime(6) NOT NULL, 170 | `object_id` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL, 171 | `object_repr` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 172 | `action_flag` smallint(5) UNSIGNED NOT NULL, 173 | `change_message` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 174 | `content_type_id` int(11) NULL DEFAULT NULL, 175 | `user_id` int(11) NOT NULL, 176 | PRIMARY KEY (`id`) USING BTREE, 177 | INDEX `django_admin_log_content_type_id_c4bce8eb_fk_django_co`(`content_type_id`) USING BTREE, 178 | INDEX `django_admin_log_user_id_c564eba6_fk_auth_user_id`(`user_id`) USING BTREE, 179 | CONSTRAINT `django_admin_log_content_type_id_c4bce8eb_fk_django_co` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, 180 | CONSTRAINT `django_admin_log_user_id_c564eba6_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT 181 | ) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 182 | 183 | -- ---------------------------- 184 | -- Records of django_admin_log 185 | -- ---------------------------- 186 | INSERT INTO `django_admin_log` VALUES (1, '2023-07-03 16:14:26.401647', '1', '二手macbook 2022电脑一台', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 187 | INSERT INTO `django_admin_log` VALUES (2, '2023-07-03 16:25:31.970956', '12', '求购自行车一辆校园内骑行', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 188 | INSERT INTO `django_admin_log` VALUES (3, '2023-07-03 16:25:35.544402', '12', '求购自行车一辆校园内骑行', 2, '[]', 7, 1); 189 | INSERT INTO `django_admin_log` VALUES (4, '2023-07-03 16:25:46.718319', '11', '求iphone8手机一台', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 190 | INSERT INTO `django_admin_log` VALUES (5, '2023-07-03 16:25:51.203646', '10', '求购电动车一辆小牛牌的', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 191 | INSERT INTO `django_admin_log` VALUES (6, '2023-07-03 16:25:54.070399', '10', '求购电动车一辆小牛牌的', 2, '[]', 7, 1); 192 | INSERT INTO `django_admin_log` VALUES (7, '2023-07-03 16:25:58.658377', '8', '二手浪潮服务器5台公司闲置800元处理', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 193 | INSERT INTO `django_admin_log` VALUES (8, '2023-07-03 16:26:02.881419', '7', '二手考研资料一套100元', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 194 | INSERT INTO `django_admin_log` VALUES (9, '2023-07-03 16:26:06.224045', '6', '二手雅迪电动车一辆900元', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 195 | INSERT INTO `django_admin_log` VALUES (10, '2023-07-03 16:26:10.781416', '5', '二手U盘1个50元位置北京', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 196 | INSERT INTO `django_admin_log` VALUES (11, '2023-07-03 16:26:14.364218', '4', '二手花盆9个100元', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 197 | INSERT INTO `django_admin_log` VALUES (12, '2023-07-03 16:26:17.743341', '3', '二手电脑包3个499元', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 198 | INSERT INTO `django_admin_log` VALUES (13, '2023-07-03 16:26:20.974880', '2', '二手苹果手机一台200元', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 199 | INSERT INTO `django_admin_log` VALUES (14, '2023-07-03 16:26:23.674672', '1', '二手macbook 2022电脑一台', 2, '[]', 7, 1); 200 | INSERT INTO `django_admin_log` VALUES (15, '2023-07-03 16:28:55.970229', '16', '出售联想主机一台带键盘800元', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 201 | INSERT INTO `django_admin_log` VALUES (16, '2023-07-03 16:28:59.616926', '15', '求购dell电脑一台笔记本优先', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 202 | INSERT INTO `django_admin_log` VALUES (17, '2023-07-03 16:29:03.198793', '14', '求购小米蓝牙耳机一套预算200', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 203 | INSERT INTO `django_admin_log` VALUES (18, '2023-07-03 16:29:06.304437', '13', '求购宠物狗狗一只', 2, '[{\"changed\": {\"fields\": [\"Status\"]}}]', 7, 1); 204 | 205 | -- ---------------------------- 206 | -- Table structure for django_content_type 207 | -- ---------------------------- 208 | DROP TABLE IF EXISTS `django_content_type`; 209 | CREATE TABLE `django_content_type` ( 210 | `id` int(11) NOT NULL AUTO_INCREMENT, 211 | `app_label` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 212 | `model` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 213 | PRIMARY KEY (`id`) USING BTREE, 214 | UNIQUE INDEX `django_content_type_app_label_model_76bd3d3b_uniq`(`app_label`, `model`) USING BTREE 215 | ) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 216 | 217 | -- ---------------------------- 218 | -- Records of django_content_type 219 | -- ---------------------------- 220 | INSERT INTO `django_content_type` VALUES (1, 'admin', 'logentry'); 221 | INSERT INTO `django_content_type` VALUES (7, 'app', 'product'); 222 | INSERT INTO `django_content_type` VALUES (3, 'auth', 'group'); 223 | INSERT INTO `django_content_type` VALUES (2, 'auth', 'permission'); 224 | INSERT INTO `django_content_type` VALUES (4, 'auth', 'user'); 225 | INSERT INTO `django_content_type` VALUES (5, 'contenttypes', 'contenttype'); 226 | INSERT INTO `django_content_type` VALUES (6, 'sessions', 'session'); 227 | 228 | -- ---------------------------- 229 | -- Table structure for django_migrations 230 | -- ---------------------------- 231 | DROP TABLE IF EXISTS `django_migrations`; 232 | CREATE TABLE `django_migrations` ( 233 | `id` int(11) NOT NULL AUTO_INCREMENT, 234 | `app` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 235 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 236 | `applied` datetime(6) NOT NULL, 237 | PRIMARY KEY (`id`) USING BTREE 238 | ) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 239 | 240 | -- ---------------------------- 241 | -- Records of django_migrations 242 | -- ---------------------------- 243 | INSERT INTO `django_migrations` VALUES (1, 'contenttypes', '0001_initial', '2023-07-03 16:10:18.297198'); 244 | INSERT INTO `django_migrations` VALUES (2, 'auth', '0001_initial', '2023-07-03 16:10:19.138902'); 245 | INSERT INTO `django_migrations` VALUES (3, 'admin', '0001_initial', '2023-07-03 16:10:19.293558'); 246 | INSERT INTO `django_migrations` VALUES (4, 'admin', '0002_logentry_remove_auto_add', '2023-07-03 16:10:19.300594'); 247 | INSERT INTO `django_migrations` VALUES (5, 'admin', '0003_logentry_add_action_flag_choices', '2023-07-03 16:10:19.305955'); 248 | INSERT INTO `django_migrations` VALUES (6, 'app', '0001_initial', '2023-07-03 16:10:19.346975'); 249 | INSERT INTO `django_migrations` VALUES (7, 'app', '0002_auto_20200210_1715', '2023-07-03 16:10:19.365179'); 250 | INSERT INTO `django_migrations` VALUES (8, 'app', '0003_product_expire', '2023-07-03 16:10:19.422313'); 251 | INSERT INTO `django_migrations` VALUES (9, 'app', '0004_remove_product_desc', '2023-07-03 16:10:19.474207'); 252 | INSERT INTO `django_migrations` VALUES (10, 'app', '0005_auto_20200211_1132', '2023-07-03 16:10:19.647441'); 253 | INSERT INTO `django_migrations` VALUES (11, 'contenttypes', '0002_remove_content_type_name', '2023-07-03 16:10:19.760042'); 254 | INSERT INTO `django_migrations` VALUES (12, 'auth', '0002_alter_permission_name_max_length', '2023-07-03 16:10:19.826327'); 255 | INSERT INTO `django_migrations` VALUES (13, 'auth', '0003_alter_user_email_max_length', '2023-07-03 16:10:19.894772'); 256 | INSERT INTO `django_migrations` VALUES (14, 'auth', '0004_alter_user_username_opts', '2023-07-03 16:10:19.910972'); 257 | INSERT INTO `django_migrations` VALUES (15, 'auth', '0005_alter_user_last_login_null', '2023-07-03 16:10:19.958209'); 258 | INSERT INTO `django_migrations` VALUES (16, 'auth', '0006_require_contenttypes_0002', '2023-07-03 16:10:19.960882'); 259 | INSERT INTO `django_migrations` VALUES (17, 'auth', '0007_alter_validators_add_error_messages', '2023-07-03 16:10:19.967942'); 260 | INSERT INTO `django_migrations` VALUES (18, 'auth', '0008_alter_user_username_max_length', '2023-07-03 16:10:20.041271'); 261 | INSERT INTO `django_migrations` VALUES (19, 'auth', '0009_alter_user_last_name_max_length', '2023-07-03 16:10:20.117562'); 262 | INSERT INTO `django_migrations` VALUES (20, 'auth', '0010_alter_group_name_max_length', '2023-07-03 16:10:20.233243'); 263 | INSERT INTO `django_migrations` VALUES (21, 'auth', '0011_update_proxy_permissions', '2023-07-03 16:10:20.252240'); 264 | INSERT INTO `django_migrations` VALUES (22, 'auth', '0012_alter_user_first_name_max_length', '2023-07-03 16:10:20.305523'); 265 | INSERT INTO `django_migrations` VALUES (23, 'sessions', '0001_initial', '2023-07-03 16:10:20.348509'); 266 | 267 | -- ---------------------------- 268 | -- Table structure for django_session 269 | -- ---------------------------- 270 | DROP TABLE IF EXISTS `django_session`; 271 | CREATE TABLE `django_session` ( 272 | `session_key` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 273 | `session_data` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 274 | `expire_date` datetime(6) NOT NULL, 275 | PRIMARY KEY (`session_key`) USING BTREE, 276 | INDEX `django_session_expire_date_a5c62663`(`expire_date`) USING BTREE 277 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 278 | 279 | -- ---------------------------- 280 | -- Records of django_session 281 | -- ---------------------------- 282 | INSERT INTO `django_session` VALUES ('rmphlsi5moh7kacfmplyj8ki2oi7wvdx', '.eJxVjMsOwiAQRf-FtSHMQKl16b7fQGYYkKqBpI-V8d-1SRe6veec-1KBtrWEbUlzmERdFKjT78YUH6nuQO5Ub03HVtd5Yr0r-qCLHpuk5_Vw_w4KLeVbM1pKkQAYkxnQmWgz9xwRBnDO2Ex95zvx7DEhuo4sEKJAtiJnm6N6fwDhxjfS:1qGEhL:cWZOYCh-mrQqDWFhwjZWvbl9XKHXv1BgyZviqBpXhno', '2023-07-17 16:14:15.261120'); 283 | 284 | -- ---------------------------- 285 | -- Table structure for mask_product 286 | -- ---------------------------- 287 | DROP TABLE IF EXISTS `mask_product`; 288 | CREATE TABLE `mask_product` ( 289 | `id` int(11) NOT NULL AUTO_INCREMENT, 290 | `title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 291 | `type` int(11) NOT NULL, 292 | `contact` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 293 | `phone` varchar(13) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 294 | `weixin` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 295 | `status` tinyint(1) NOT NULL, 296 | `timestamp` datetime(6) NULL DEFAULT NULL, 297 | `expire` int(11) NOT NULL, 298 | `location` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 299 | `pv` int(11) NOT NULL, 300 | PRIMARY KEY (`id`) USING BTREE 301 | ) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 302 | 303 | -- ---------------------------- 304 | -- Records of mask_product 305 | -- ---------------------------- 306 | INSERT INTO `mask_product` VALUES (1, '二手macbook 2022电脑一台', 0, '刘德华', '13581651532', NULL, 1, '2023-07-03 16:13:07.929340', 7, '北京市朝阳区人民路', 0); 307 | INSERT INTO `mask_product` VALUES (2, '二手苹果手机一台200元', 0, '刘德华', '13581651538', 'lengqin1024', 1, '2023-07-03 16:19:34.133943', 7, '北京市朝阳区人民路', 0); 308 | INSERT INTO `mask_product` VALUES (3, '二手电脑包3个499元', 0, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:19:58.803505', 3, '北京市朝阳区人民路', 0); 309 | INSERT INTO `mask_product` VALUES (4, '二手花盆9个100元', 0, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:20:17.764000', 3, '北京市朝阳区人民路', 0); 310 | INSERT INTO `mask_product` VALUES (5, '二手U盘1个50元位置北京', 0, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:22:05.907925', 3, '北京市朝阳区人民路', 0); 311 | INSERT INTO `mask_product` VALUES (6, '二手雅迪电动车一辆900元', 0, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:22:27.349068', 3, '北京市朝阳区人民路', 0); 312 | INSERT INTO `mask_product` VALUES (7, '二手考研资料一套100元', 0, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:22:56.163478', 1, '北京市朝阳区人民路', 0); 313 | INSERT INTO `mask_product` VALUES (8, '二手浪潮服务器5台公司闲置800元处理', 0, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:23:31.117385', 1, '北京市朝阳区人民路', 0); 314 | INSERT INTO `mask_product` VALUES (9, '二手小孩玩具一套', 0, '刘德华', '13581651532', 'lengqin1024', 0, '2023-07-03 16:23:50.572703', 3, '北京市朝阳区人民路', 0); 315 | INSERT INTO `mask_product` VALUES (10, '求购电动车一辆小牛牌的', 1, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:24:23.482116', 3, '北京市朝阳区人民路', 0); 316 | INSERT INTO `mask_product` VALUES (11, '求iphone8手机一台', 1, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:24:48.941805', 3, '北京市朝阳区人民路', 0); 317 | INSERT INTO `mask_product` VALUES (12, '求购自行车一辆校园内骑行', 1, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:25:14.534533', 3, '北京市朝阳区人民路', 0); 318 | INSERT INTO `mask_product` VALUES (13, '求购宠物狗狗一只', 1, '刘德华', '13581651532', NULL, 1, '2023-07-03 16:27:18.444386', 3, '北京市朝阳区人民路', 0); 319 | INSERT INTO `mask_product` VALUES (14, '求购小米蓝牙耳机一套预算200', 1, '刘德华', '13581651532', NULL, 1, '2023-07-03 16:27:56.325636', 1, '北京市朝阳区人民路', 0); 320 | INSERT INTO `mask_product` VALUES (15, '求购dell电脑一台笔记本优先', 1, '刘德华', '13581651532', 'lengqin1024', 1, '2023-07-03 16:28:23.609257', 3, '北京市朝阳区人民路', 0); 321 | INSERT INTO `mask_product` VALUES (16, '出售联想主机一台带键盘800元', 0, '刘德华', '13581651532', NULL, 1, '2023-07-03 16:28:47.531081', 3, '北京市朝阳区人民路', 0); 322 | INSERT INTO `mask_product` VALUES (17, '二手电脑桌2台', 0, '刘德华', '13581651532', NULL, 0, '2023-07-03 16:40:19.912767', 3, '北京市朝阳区人民路', 0); 323 | 324 | SET FOREIGN_KEY_CHECKS = 1; 325 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | django==3.2.11 2 | pymysql==1.0.2 3 | django-ratelimit==1.0.1 -------------------------------------------------------------------------------- /static/css/semantic.custom.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .ui.tiny.images .image, 4 | .ui.tiny.images img, 5 | .ui.tiny.images svg, 6 | .ui.tiny.image { 7 | width: 180px; 8 | height: auto; 9 | font-size: 0.85714286rem; 10 | } 11 | 12 | .ui.sm.images .image, 13 | .ui.sm.images img, 14 | .ui.sm.images svg, 15 | .ui.sm.image { 16 | width: 100px; 17 | height: auto; 18 | font-size: 0.92857143rem; 19 | } 20 | 21 | 22 | /*--------修改 pointer-events:none--------*/ 23 | .ui.icon.input > i.icon:not(.link) { 24 | 25 | } 26 | 27 | /* Inline Label width已修改 */ 28 | 29 | .ui.form .inline.fields > label, 30 | .ui.form .inline.fields .field > label, 31 | .ui.form .inline.fields .field > p, 32 | .ui.form .inline.field > label, 33 | .ui.form .inline.field > p { 34 | display: inline-block; 35 | width: 20%; 36 | margin-top: 0em; 37 | margin-bottom: 0em; 38 | vertical-align: baseline; 39 | font-size: 0.92857143em; 40 | font-weight: bold; 41 | color: rgba(0, 0, 0, 0.87); 42 | text-transform: none; 43 | } 44 | 45 | 46 | 47 | /* Inline Input width:auto-->70% */ 48 | 49 | .ui.form .inline.fields .field > input, 50 | .ui.form .inline.fields .field > select, 51 | .ui.form .inline.field > input, 52 | .ui.form .inline.field > select { 53 | display: inline-block; 54 | width: 70%; 55 | margin-top: 0em; 56 | margin-bottom: 0em; 57 | vertical-align: middle; 58 | font-size: 1em; 59 | } 60 | 61 | 62 | /*--- Icon ---*/ 63 | 64 | .ui.vertical.menu .item > i.icon { 65 | width: 1.18em; 66 | float: none; 67 | margin: 0em 0em 0em 0.5em; 68 | } 69 | 70 | 71 | .ui.card { 72 | margin: 1em auto; 73 | } 74 | 75 | .ui.comments .comment .avatar { 76 | display: block; 77 | width: 2.5em; 78 | height: 2.5em; 79 | float: left; 80 | margin: 0.2em 0em 0em; 81 | } 82 | 83 | /*-------------- 84 | 去掉了 border-radius: 0.25rem; 85 | ---------------*/ 86 | .ui.comments .comment img.avatar, 87 | .ui.comments .comment .avatar img { 88 | display: block; 89 | margin: 0em auto; 90 | width: 100%; 91 | height: 100%; 92 | } 93 | 94 | @media only screen and (max-width: 767px) { 95 | .ui.unstackable.items > .item > .image, 96 | .ui.unstackable.items > .item > .image > img { 97 | width: 80px !important; 98 | } 99 | } 100 | 101 | 102 | 103 | 104 | .ui.checkbox { 105 | position: relative; 106 | display: inline-block; 107 | -webkit-backface-visibility: hidden; 108 | backface-visibility: hidden; 109 | outline: none; 110 | vertical-align: middle; 111 | font-style: normal; 112 | min-height: 17px; 113 | font-size: 1rem; 114 | line-height: 17px; 115 | min-width: 17px; 116 | } 117 | 118 | 119 | .ui.dropdown > .text > img, 120 | .ui.dropdown > .text > .image, 121 | .ui.dropdown .menu > .item > .image, 122 | .ui.dropdown .menu > .item > img { 123 | display: inline-block; 124 | vertical-align: middle; 125 | width: auto; 126 | margin-top: -0.5em; 127 | margin-bottom: -0.5em; 128 | max-height: 2em; 129 | } 130 | -------------------------------------------------------------------------------- /static/css/style.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | margin:0px; 4 | background-color: #FFFFFF; 5 | } 6 | 7 | .color-black{ 8 | color:#000000; 9 | } 10 | 11 | .cursor{ 12 | cursor: pointer; 13 | } 14 | 15 | .n{ 16 | display:none; 17 | } 18 | 19 | .fl{ 20 | float:left; 21 | } 22 | .fr{ 23 | float:right; 24 | } 25 | 26 | .v-inline-middle{ 27 | display:inline-block; 28 | vertical-align: middle; 29 | } 30 | 31 | #v-content{ 32 | padding-top:5.2em; 33 | } 34 | 35 | #v-account-body{ 36 | background-color: #DADADA; 37 | } 38 | #v-account-body > .grid{ 39 | height: 100%; 40 | } 41 | 42 | .ui.menu .item img.logo { 43 | margin-right: 0.66rem; 44 | } 45 | 46 | .ui.footer.segment { 47 | margin: 2em 0em 0em; 48 | padding: 1em 0em; 49 | } 50 | 51 | .v-account { 52 | max-width: 450px; 53 | } 54 | 55 | .video{ 56 | width: 100%; 57 | height: auto; 58 | } 59 | 60 | .v-video-search{ 61 | margin-right: 3em; 62 | width: 30%; 63 | } 64 | 65 | .v-video-search i{ 66 | cursor: pointer; 67 | } 68 | 69 | .v-container-top{ 70 | height: 5.66em; 71 | } 72 | 73 | .v-header-extra{ 74 | position: relative; 75 | width:100%; 76 | text-align: right; 77 | padding-top: 0.60rem; 78 | } 79 | 80 | .v-play-icon{ 81 | position: absolute; 82 | left: 1.0rem; 83 | bottom: 1.0rem; 84 | color: #fff; 85 | } 86 | 87 | .ui .card .image{ 88 | cursor: pointer; 89 | } 90 | 91 | 92 | .v-icon{ 93 | float: left; 94 | } 95 | 96 | .video-duration{ 97 | position: absolute; 98 | bottom: 0px; 99 | left: 4px; 100 | color: #fff; 101 | } 102 | 103 | .header-title{ 104 | margin-top: 30px; 105 | font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif; 106 | font-weight: bold; 107 | font-size: 1.28571429em; 108 | color: rgba(0, 0, 0, 0.85); 109 | } 110 | 111 | .video-title{ 112 | color: var(--yt-primary-text-color); 113 | font-size: 1.28em; 114 | font-weight: 400; 115 | line-height: 1em; 116 | -ms-flex: 1 1 0.000000001px; 117 | -webkit-flex: 1; 118 | flex: 1; 119 | } 120 | 121 | .video-side-title{ 122 | color: var(--yt-primary-text-color); 123 | font-size: 1.28em; 124 | font-weight: 400; 125 | line-height: 1em; 126 | -ms-flex: 1 1 0.000000001px; 127 | -webkit-flex: 1; 128 | flex: 1; 129 | } 130 | 131 | .video-view-count{ 132 | margin-top: 16px; 133 | color: #888888; 134 | } 135 | 136 | .video-view-operation{ 137 | margin-top: 16px; 138 | color: #888888; 139 | } 140 | 141 | .video-info{ 142 | margin-top: 20px; 143 | } 144 | 145 | .video-page{ 146 | display: block; 147 | margin:1.28em; 148 | text-align: center; 149 | } 150 | 151 | .v-settings{ 152 | margin-top: 40px; 153 | } 154 | 155 | .v-settings-side{ 156 | border-right: 1px solid #e3e3e3; 157 | } 158 | 159 | .v-settings-content .form{ 160 | margin:0em auto; 161 | width: 400px; 162 | } 163 | 164 | .v-settings-nav{ 165 | position: relative; 166 | display: -webkit-box; 167 | display: -ms-flexbox; 168 | display: flex; 169 | width: 185px; 170 | min-height: 350px; 171 | margin-right: 100px; 172 | -webkit-box-orient: vertical; 173 | -webkit-box-direction: normal; 174 | -ms-flex-direction: column; 175 | flex-direction: column; 176 | } 177 | 178 | .v-settings-avatar{ 179 | display:inline-block; 180 | float:left; 181 | cursor:pointer; 182 | } 183 | 184 | .v-nav-title{ 185 | margin-left:1.0em; 186 | } 187 | 188 | .v-form-field{ 189 | padding-top:1em; 190 | padding-bottom:1em; 191 | vertical-align:middle; 192 | } 193 | 194 | .v-form-fix-avatar{ 195 | padding:2em; 196 | } 197 | 198 | .v-header-avatar{ 199 | line-height:34px; 200 | color:#000; 201 | } -------------------------------------------------------------------------------- /static/css/style_v2.css: -------------------------------------------------------------------------------- 1 | html,body { 2 | margin: 0; 3 | padding: 0; 4 | width: 100%; 5 | height: 100%; 6 | min-width: 320px; 7 | font-family: Microsoft Yahei,arial; 8 | -moz-min-width: 320px; 9 | -ms-min-width: 320px; 10 | -o-min-width: 320px; 11 | -webkit-min-width: 320px; 12 | } 13 | 14 | * { 15 | margin: 0; 16 | word-wrap: break-word; 17 | -moz-word-break: normal; 18 | -o-word-break: normal; 19 | word-break: normal; 20 | } 21 | 22 | #wrapper { 23 | margin: 0 auto -40px; 24 | height: auto!important; 25 | height: 100%; 26 | min-height: 100%; 27 | } 28 | 29 | a { 30 | color: #1e0fbe; 31 | text-decoration: none; 32 | } 33 | 34 | a:hover { 35 | text-decoration: underline; 36 | } 37 | 38 | a:visited { 39 | color: #609; 40 | } 41 | 42 | @media screen and (max-width:1080px) { 43 | #center-logo { 44 | margin-bottom: 50px!important; 45 | } 46 | 47 | #search-box #search { 48 | width: 400px!important; 49 | } 50 | } 51 | 52 | @media screen and (max-width:980px) { 53 | .header-div .nav-logo { 54 | display: none!important; 55 | } 56 | 57 | #wall,.adsense { 58 | margin: 0 5px!important; 59 | } 60 | 61 | #sort-bar { 62 | padding-left: 5px!important; 63 | } 64 | 65 | .download { 66 | display: inline-block!important; 67 | } 68 | 69 | #cpv6_right_lower { 70 | display: none; 71 | } 72 | } 73 | 74 | @media screen and (max-width:720px) { 75 | #center-logo { 76 | margin-bottom: 40px!important; 77 | } 78 | 79 | #search-box #search { 80 | width: 305px!important; 81 | } 82 | } 83 | 84 | @media screen and (max-width:665px) { 85 | #sort-bar b,#sort-bar a { 86 | padding: 0 4px!important; 87 | } 88 | } 89 | 90 | @media screen and (max-width:500px) { 91 | .ad { 92 | display: none; 93 | } 94 | } 95 | 96 | @media screen and (max-width:400px) { 97 | #search-box #search { 98 | width: 210px!important; 99 | } 100 | } 101 | 102 | img { 103 | border: none; 104 | } 105 | 106 | .ad { 107 | margin-bottom: 15px; 108 | } 109 | 110 | .header-div { 111 | position: relative; 112 | width: 100%; 113 | height: 79px; 114 | border-bottom: 1px solid #e5e5e5; 115 | background-color: #f1f1f1; 116 | vertical-align: middle; 117 | line-height: 79px; 118 | } 119 | 120 | .header-div form { 121 | margin-left: 5px; 122 | } 123 | 124 | .header-div form a { 125 | text-decoration: none; 126 | margin: 0px 14px; 127 | } 128 | 129 | .header-div .nav-logo { 130 | width: 32px; 131 | vertical-align: middle; 132 | } 133 | 134 | .header-div form #search { 135 | margin: 0; 136 | padding: 4px 7px; 137 | width: 68%; 138 | height: 32px; 139 | max-width: 550px; 140 | outline: none; 141 | border: 1px solid #b9b9b9; 142 | background-color: #fff; 143 | font: 16px arial; 144 | } 145 | 146 | .top-bar { 147 | z-index: 10; 148 | width: 100%; 149 | height: 30px; 150 | background-color: #2d2d2d; 151 | } 152 | 153 | .top-bar .first { 154 | margin-left: 20px; 155 | } 156 | 157 | .top-bar span { 158 | position: relative; 159 | display: inline-block; 160 | } 161 | 162 | .top-bar select { 163 | float: right; 164 | margin: 5px 5px 0 0; 165 | } 166 | 167 | .top-bar .highlight-bar { 168 | position: absolute; 169 | top: 0; 170 | display: inline-block; 171 | width: 40px; 172 | height: 2px; 173 | background-color: #dd4b39; 174 | } 175 | 176 | .top-bar span a { 177 | display: inline-block; 178 | width: 40px; 179 | color: #ccc; 180 | text-align: center; 181 | text-decoration: none; 182 | font-size: 13px; 183 | line-height: 30px; 184 | } 185 | 186 | .top-bar span a:hover { 187 | background-color: #4c4c4c; 188 | cursor: pointer; 189 | } 190 | 191 | .top-bar span a.selected { 192 | color: #fff; 193 | font-weight: 700; 194 | } 195 | 196 | #sort-bar { 197 | float: none; 198 | padding-left: 140px; 199 | height: 38px; 200 | background: #f8f8f8; 201 | line-height: 36px; 202 | } 203 | 204 | .top_fav { 205 | float: right; 206 | } 207 | 208 | .top_fav a { 209 | width: 80px!important; 210 | } 211 | 212 | #sort-bar b,#sort-bar a { 213 | display: inline-block; 214 | padding: 0 8px; 215 | color: #666; 216 | text-align: center; 217 | text-decoration: none; 218 | font-size: 14px; 219 | } 220 | 221 | #sort-bar a:hover { 222 | color: #323232; 223 | } 224 | 225 | #sort-bar b { 226 | border-bottom: 2px solid #38f; 227 | color: #323232; 228 | font-weight: 700; 229 | } 230 | 231 | #search:hover { 232 | border-color: silver!important; 233 | } 234 | 235 | #search:focus { 236 | border-color: #4d90fe!important; 237 | } 238 | 239 | #center-box-wrapper { 240 | display: table-cell; 241 | margin: 0; 242 | padding: 0; 243 | width: 659px; 244 | vertical-align: middle; 245 | } 246 | 247 | #center-box { 248 | margin: 0 auto; 249 | text-align: center; 250 | } 251 | 252 | #first-content { 253 | position: absolute; 254 | top: 30px; 255 | left: 0; 256 | display: table; 257 | margin: 0; 258 | padding: 0; 259 | width: 100%; 260 | height: 80%; 261 | } 262 | 263 | #center-logo { 264 | position: relative; 265 | margin-bottom: 60px; 266 | text-align: center; 267 | } 268 | 269 | #center-logo img { 270 | width: 22%; 271 | max-width:120px; 272 | min-width: 90px; 273 | -moz-min-width: 100px; 274 | -ms-min-width: 100px; 275 | -o-min-width: 100px; 276 | -webkit-min-width: 100px; 277 | } 278 | 279 | .info-box { 280 | margin-top: 10px; 281 | line-height: 1.6; 282 | } 283 | 284 | .info-box ul { 285 | padding: 0; 286 | text-decoration: none; 287 | } 288 | 289 | .info-box ul li { 290 | display: inline-block; 291 | } 292 | 293 | .info-box a { 294 | margin: 0 8px; 295 | color: #0360af; 296 | text-decoration: none; 297 | } 298 | 299 | button.blue,a.blue,input[type=submit].blue { 300 | margin-left: -6px; 301 | padding: 0; 302 | width: 80px; 303 | height: 32px; 304 | outline: medium; 305 | border: 0; 306 | border-bottom: 1px solid #2d78f4; 307 | -webkit-border-radius: 0; 308 | background: #3385ff; 309 | color: #fff; 310 | letter-spacing: 1px; 311 | font-size: 14px; 312 | cursor: pointer; 313 | -webkit-appearance: none; 314 | } 315 | 316 | input[type=submit].blue:hover { 317 | background: #317ef3; 318 | -webkit-box-shadow: 1px 1px 1px #ccc; 319 | box-shadow: 1px 1px 1px #ccc; 320 | -ms-box-shadow: 1px 1px 1px #ccc; 321 | } 322 | 323 | input[type=submit].blue:active { 324 | background: #3075dc; 325 | -webkit-box-shadow: inset 1px 1px 3px #2964bb; 326 | -moz-box-shadow: inset 1px 1px 3px #2964bb; 327 | box-shadow: inset 1px 1px 3px #2964bb; 328 | -ms-box-shadow: inset 1px 1px 3px #2964bb; 329 | -o-box-shadow: inset 1px 1px 3px #2964bb; 330 | } 331 | 332 | #content { 333 | padding: 15px 0 0; 334 | } 335 | 336 | .top a { 337 | color: #666; 338 | } 339 | 340 | #wall { 341 | overflow: hidden; 342 | margin: 0 10px; 343 | } 344 | 345 | #wall ol { 346 | margin-bottom: 10px; 347 | } 348 | 349 | #wall p { 350 | margin: 0; 351 | color: #333; 352 | word-wrap: break-word; 353 | line-height: 2; 354 | -moz-word-break: break-all; 355 | -o-word-break: break-all; 356 | word-break: break-all; 357 | } 358 | 359 | #wall p span { 360 | margin-left: 10px; 361 | } 362 | 363 | #wall p a { 364 | word-wrap: break-word; 365 | -moz-word-break: break-all; 366 | -o-word-break: break-all; 367 | word-break: break-all; 368 | } 369 | 370 | #search-info { 371 | padding: 10px 0; 372 | color: #999; 373 | font-size: 13px; 374 | } 375 | 376 | #search-box { 377 | position: relative; 378 | } 379 | 380 | #search-box #search { 381 | margin: 0; 382 | padding: 4px 7px!important; 383 | width: 520px; 384 | height: 32px; 385 | outline: none; 386 | border: 1px solid #dadada; 387 | background-color: #fff; 388 | vertical-align: top; 389 | font: 16px arial; 390 | } 391 | 392 | .search-statu { 393 | margin-bottom: 15px; 394 | padding-bottom: 10px; 395 | border-bottom: 1px solid #e4e4e4; 396 | color: #666; 397 | } 398 | 399 | .col-md-2,.col-md-8 { 400 | position: relative; 401 | min-height: 1px; 402 | } 403 | 404 | @media(min-width:992px) { 405 | .col-md-8 { 406 | float: left; 407 | width: 70%; 408 | } 409 | 410 | .col-md-2 { 411 | float: left; 412 | width: 30%; 413 | } 414 | } 415 | 416 | .search-notice { 417 | padding: 15px 10px; 418 | border-color: #dcdcdc; 419 | background-image: -webkit-linear-gradient(top,#e8e8e8 0%,#f5f5f5 100%); 420 | background-image: linear-gradient(to bottom,#e8e8e8 0%,#f5f5f5 100%); 421 | background-repeat: repeat-x; 422 | -webkit-box-shadow: inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1); 423 | box-shadow: inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1); 424 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0); 425 | } 426 | 427 | .search-item { 428 | margin: 0 10px 25px 0; 429 | } 430 | 431 | .search-item .item-title h3 { 432 | font-weight: 400; 433 | font-size: medium; 434 | line-height: 1.2; 435 | } 436 | 437 | .search-item .item-title h3 b { 438 | color: red; 439 | font-weight: 400; 440 | } 441 | 442 | .search-item em { 443 | color: #c00; 444 | font-style: normal; 445 | } 446 | 447 | .search-item .item-list { 448 | padding: 5px 0; 449 | } 450 | 451 | .search-item .item-list ul { 452 | margin: 0; 453 | padding: 0; 454 | } 455 | 456 | .search-item .item-list ul li { 457 | text-decoration: none; 458 | } 459 | 460 | .search-item .item-list,.search-item .item-list p { 461 | color: #222!important; 462 | word-wrap: break-word; 463 | font-size: 13px; 464 | line-height: 1.4!important; 465 | } 466 | 467 | .search-item .item-bar { 468 | color: #777; 469 | font-size: 13px; 470 | line-height: 16px; 471 | } 472 | 473 | .search-item .item-bar b { 474 | color: #00802a; 475 | } 476 | 477 | .search-item .item-bar span { 478 | margin-right: 15px; 479 | } 480 | 481 | .search-item .item-bar .download { 482 | display: none; 483 | margin-right: 10px; 484 | padding-left: 20px; 485 | height: 16px; 486 | background: url(/static/img/link.png) no-repeat left; 487 | } 488 | 489 | .highlight { 490 | color: red; 491 | } 492 | 493 | .bottom-pager { 494 | margin: 30px 0 15px; 495 | } 496 | 497 | .bottom-pager a,.bottom-pager span { 498 | display: inline-block; 499 | margin: 2px; 500 | padding: 8px 12px; 501 | border: 1px solid #a1a2a3; 502 | color: #1e0fbe; 503 | vertical-align: middle; 504 | text-align: center; 505 | text-decoration: none; 506 | font: 13px/1.22 arial,helvetica,clean,sans-serif; 507 | } 508 | 509 | .bottom-pager span { 510 | background-color: #eee; 511 | color: #888; 512 | font-weight: 700; 513 | } 514 | 515 | .bottom-pager a:hover { 516 | border: 1px solid #38f; 517 | background: #f2f8ff; 518 | } 519 | 520 | .bottom-pager a:visited { 521 | color: #1e0fbe; 522 | } 523 | 524 | .pagination { 525 | display: inline-block; 526 | margin: 20px 0 45px; 527 | padding-left: 0; 528 | border-radius: 4px; 529 | } 530 | 531 | .pagination li { 532 | display: inline; 533 | } 534 | 535 | .pagination li a,.pagination li span { 536 | position: relative; 537 | float: left; 538 | margin: 0; 539 | margin-left: 2px; 540 | padding: 6px 12px; 541 | border: 1px solid #ddd; 542 | background-color: #fff; 543 | color: #428bca; 544 | text-decoration: none; 545 | font-size: 1em; 546 | line-height: 1.42857143; 547 | } 548 | 549 | .pagination>.active>span { 550 | border-color: #428bca; 551 | background-color: #428bca; 552 | color: #fff; 553 | } 554 | 555 | .pagination>li:first-child>a,.pagination>li:first-child>span { 556 | margin-left: 0; 557 | } 558 | 559 | .new { 560 | position: relative; 561 | top: -4px; 562 | right: -4px; 563 | display: inline-block; 564 | overflow: hidden; 565 | padding: 2px; 566 | background-color: #f13f40; 567 | color: #fff; 568 | vertical-align: text-bottom; 569 | text-align: center; 570 | font-style: normal; 571 | font-size: 12px; 572 | line-height: 100%; 573 | } 574 | 575 | .baidu-box,.bdSug_app,.bdsug_copy { 576 | display: none; 577 | } 578 | 579 | .bdSug_wpr td { 580 | padding-left: 5px!important; 581 | } 582 | 583 | .bdshare-button-style0-16 { 584 | margin-left: 0!important; 585 | } 586 | 587 | .bdshare-button-style0-16:after { 588 | display: inline-block!important; 589 | content: inherit!important; 590 | } 591 | 592 | .bdshare-button-style0-16 a { 593 | margin: 0 10px 0 0!important; 594 | padding-left: 20px!important; 595 | font-size: 16px!important; 596 | } 597 | 598 | .push { 599 | clear: both; 600 | height: 40px; 601 | } 602 | 603 | .footer { 604 | position: relative; 605 | z-index: 99; 606 | width: 100%; 607 | height: 39px; 608 | border-top: 1px solid #e4e4e4; 609 | background: #f2f2f2; 610 | color: #666; 611 | text-align: center; 612 | font-size: small; 613 | line-height: 39px; 614 | } 615 | 616 | .footer a { 617 | color: #666!important; 618 | } 619 | 620 | h2 { 621 | display: block; 622 | margin: 0; 623 | color: #444; 624 | word-wrap: break-word; 625 | font-weight: 700; 626 | font-size: 18px; 627 | -webkit-margin-after: .2em; 628 | -webkit-margin-start: 0; 629 | -webkit-margin-end: 0; 630 | -moz-word-break: break-all; 631 | -o-word-break: break-all; 632 | word-break: break-all; 633 | } 634 | 635 | .fileDetail { 636 | position: relative; 637 | } 638 | 639 | .fileDetail p { 640 | color: #444!important; 641 | font-size: 16px; 642 | line-height: 2!important; 643 | } 644 | 645 | .fileDetail p a { 646 | margin-right: 3px; 647 | } 648 | 649 | .lightColor,.lightColor:visited { 650 | margin-left: 10px; 651 | color: #888; 652 | } 653 | 654 | .pill,.pill:visited { 655 | padding: 2px 4px; 656 | border: 1px solid #e1e1e8; 657 | background-color: #f7f7f9; 658 | color: #d14; 659 | white-space: nowrap; 660 | } 661 | 662 | .fileDetail .pill { 663 | white-space: normal; 664 | } 665 | 666 | .cpill { 667 | padding-right: 9px; 668 | padding-left: 9px; 669 | -webkit-border-radius: 9px; 670 | -moz-border-radius: 9px; 671 | border-radius: 9px; 672 | color: #fff!important; 673 | vertical-align: baseline; 674 | white-space: nowrap; 675 | -ms-border-radius: 9px; 676 | } 677 | 678 | .blue-pill { 679 | background-color: #3a87ad; 680 | } 681 | 682 | .yellow-pill { 683 | background-color: #f89406; 684 | } 685 | 686 | .fileType5 { 687 | background-color: red; 688 | } 689 | 690 | .fileType0,.fileType6 { 691 | background-color: #f89406; 692 | } 693 | 694 | .fileType1,.fileType2,.fileType3,.fileType4,.fileType7 { 695 | background-color: green; 696 | } 697 | 698 | ol li { 699 | color: #444; 700 | line-height: 1.5em; 701 | } 702 | 703 | #latest-search { 704 | float: left; 705 | margin-bottom: 40px; 706 | padding-top: 10px; 707 | border-top: 1px solid #e4e4e4; 708 | } 709 | 710 | #latest-search .latest-desc { 711 | display: block; 712 | margin: 5px; 713 | margin-right: 5px; 714 | color: #666; 715 | font-size: 18px; 716 | } 717 | 718 | #latest-search a { 719 | float: left; 720 | display: block; 721 | margin-right: 15px; 722 | margin-bottom: 6px; 723 | color: #1e0fbe!important; 724 | font-size: 15px; 725 | } 726 | 727 | .ads-badge { 728 | display: inline-block; 729 | margin-right: 5px; 730 | padding: 0 3px; 731 | border-radius: 2px; 732 | background-color: #edb802; 733 | color: #fff; 734 | vertical-align: baseline; 735 | font-size: 14px; 736 | line-height: 18px; 737 | -ms-border-radius: 2px; 738 | } 739 | 740 | .adsense { 741 | overflow: hidden; 742 | margin: 0 0 10px; 743 | max-width: 100%; 744 | } 745 | 746 | .detail-width { 747 | width: 100%; 748 | max-width: 700px; 749 | } 750 | 751 | .detail-table { 752 | margin: 10px 0; 753 | margin-top: 10px; 754 | border: 1px solid silver; 755 | border-collapse: collapse; 756 | text-align: center; 757 | } 758 | 759 | .detail-table tr { 760 | border-bottom: 1px solid silver; 761 | } 762 | 763 | .detail-header-bg th { 764 | padding: 5px; 765 | } 766 | 767 | .detail-table .detail-header-bg { 768 | background: #f1f1f1; 769 | } 770 | 771 | .detail-panel { 772 | margin: 10px 0; 773 | } 774 | 775 | .detail-panel .panel-header { 776 | padding: 5px 0 5px 10px; 777 | min-width: 80px; 778 | border: 1px solid silver; 779 | border-bottom: none; 780 | background-color: #f1f1f1; 781 | font-weight: 700; 782 | -moz-min-width: 80px; 783 | -ms-min-width: 80px; 784 | -o-min-width: 80px; 785 | -webkit-min-width: 80px; 786 | } 787 | 788 | .detail-panel .panel-body { 789 | overflow: hidden; 790 | padding: 5px; 791 | border: 1px solid silver; 792 | } 793 | 794 | .ds-powered-by,.ds-current { 795 | display: none!important; 796 | } 797 | 798 | .taglist_tag span { 799 | float: left; 800 | display: block; 801 | margin: 4px 20px 4px 0; 802 | font-size: 15px; 803 | } 804 | 805 | .taglist_tag a { 806 | color: #000; 807 | } 808 | 809 | #rand_content { 810 | display: none; 811 | } 812 | 813 | .rand_content { 814 | padding: 0; 815 | } 816 | 817 | .rand_content ul { 818 | margin-left: 0; 819 | padding: 0; 820 | } 821 | 822 | .rand_content li { 823 | list-style: none; 824 | line-height: 24px; 825 | } 826 | 827 | .rand_content li a { 828 | color: #333; 829 | font-size: 14px; 830 | } 831 | 832 | .link_op a { 833 | color: #333; 834 | } 835 | 836 | .link_op em { 837 | color: #c00; 838 | font-style: normal; 839 | font-size: 14px; 840 | } 841 | 842 | .fl { 843 | float: left!important; 844 | } 845 | 846 | .mt25 { 847 | margin-top: 25px!important; 848 | } 849 | 850 | .flink { 851 | font-size: 13px; 852 | } 853 | 854 | .flink a { 855 | margin-left: 5px; 856 | color: #1e6fb5; 857 | } 858 | 859 | .flink a:visited { 860 | color: #1e6fb5; 861 | } 862 | 863 | .contact { 864 | margin-top: 8px; 865 | color: #333; 866 | font-size: 13px; 867 | } 868 | 869 | #mg-link { 870 | position: absolute; 871 | left: -99999px; 872 | } 873 | 874 | .vcode-box { 875 | padding: 5px; 876 | } 877 | 878 | .vcode-box img { 879 | display: block; 880 | margin: 10px auto 20px; 881 | } 882 | 883 | .vcode-box #vcode { 884 | display: block; 885 | margin: 0 auto; 886 | padding-left: 10px; 887 | width: 230px; 888 | height: 36px; 889 | border: 1px solid #e6e6e6; 890 | color: #333; 891 | line-height: 30px; 892 | } 893 | 894 | .tras-tip { 895 | margin: 10px 0; 896 | text-align: center; 897 | font-weight: 700; 898 | font-size: 20px; 899 | } -------------------------------------------------------------------------------- /static/img/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/.DS_Store -------------------------------------------------------------------------------- /static/img/demo01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/demo01.png -------------------------------------------------------------------------------- /static/img/demo02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/demo02.png -------------------------------------------------------------------------------- /static/img/demo03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/demo03.png -------------------------------------------------------------------------------- /static/img/ic_buy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/ic_buy.png -------------------------------------------------------------------------------- /static/img/ic_consumer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/ic_consumer.png -------------------------------------------------------------------------------- /static/img/ic_provider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/ic_provider.png -------------------------------------------------------------------------------- /static/img/ic_sell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/ic_sell.png -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeek/python_mask/f2b7d92b80c4303fd707a51bb515c3bbbd73c09d/static/img/logo.png -------------------------------------------------------------------------------- /static/js/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v2.0.0 3 | * https://zenorocha.github.io/clipboard.js 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=3)}([function(t,e,n){var o,r,i;!function(a,c){r=[t,n(7)],o=c,void 0!==(i="function"==typeof o?o.apply(e,r):o)&&(t.exports=i)}(0,function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o=function(t){return t&&t.__esModule?t:{default:t}}(e),r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=(0,o.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=(0,o.default)(this.target),this.copyText()}},{key:"copyText",value:function(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==(void 0===t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),t}();t.exports=a})},function(t,e,n){function o(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!c.string(e))throw new TypeError("Second argument must be a String");if(!c.fn(n))throw new TypeError("Third argument must be a Function");if(c.node(t))return r(t,e,n);if(c.nodeList(t))return i(t,e,n);if(c.string(t))return a(t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function r(t,e,n){return t.addEventListener(e,n),{destroy:function(){t.removeEventListener(e,n)}}}function i(t,e,n){return Array.prototype.forEach.call(t,function(t){t.addEventListener(e,n)}),{destroy:function(){Array.prototype.forEach.call(t,function(t){t.removeEventListener(e,n)})}}}function a(t,e,n){return u(document.body,t,e,n)}var c=n(6),u=n(5);t.exports=o},function(t,e){function n(){}n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){function o(){r.off(t,o),e.apply(n,arguments)}var r=this;return o._=e,this.on(t,o,n)},emit:function(t){var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;for(o;o0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===d(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=(0,f.default)(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new l.default({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return u("action",t)}},{key:"defaultTarget",value:function(t){var e=u("target",t);if(e)return document.querySelector(e)}},{key:"defaultText",value:function(t){return u("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],e="string"==typeof t?[t]:t,n=!!document.queryCommandSupported;return e.forEach(function(t){n=n&&!!document.queryCommandSupported(t)}),n}}]),e}(s.default);t.exports=p})},function(t,e){function n(t,e){for(;t&&t.nodeType!==o;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}var o=9;if("undefined"!=typeof Element&&!Element.prototype.matches){var r=Element.prototype;r.matches=r.matchesSelector||r.mozMatchesSelector||r.msMatchesSelector||r.oMatchesSelector||r.webkitMatchesSelector}t.exports=n},function(t,e,n){function o(t,e,n,o,r){var a=i.apply(this,arguments);return t.addEventListener(n,a,r),{destroy:function(){t.removeEventListener(n,a,r)}}}function r(t,e,n,r,i){return"function"==typeof t.addEventListener?o.apply(null,arguments):"function"==typeof n?o.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return o(t,e,n,r,i)}))}function i(t,e,n,o){return function(n){n.delegateTarget=a(n.target,e),n.delegateTarget&&o.call(t,n)}}var a=n(4);t.exports=r},function(t,e){e.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},e.nodeList=function(t){var n=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===n||"[object HTMLCollection]"===n)&&"length"in t&&(0===t.length||e.node(t[0]))},e.string=function(t){return"string"==typeof t||t instanceof String},e.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,e){function n(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}return e}t.exports=n}])}); -------------------------------------------------------------------------------- /static/js/common-v2.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | $('#search').focus(); 4 | }); 5 | -------------------------------------------------------------------------------- /static/js/function-new.js: -------------------------------------------------------------------------------- 1 | eval(function(p, a, c, k, e, r) { 2 | e = function(c) { 3 | return (c < a ? '': e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) 4 | }; 5 | if (!''.replace(/^/, String)) { 6 | while (c--) r[e(c)] = k[c] || e(c); 7 | k = [function(e) { 8 | return r[e] 9 | }]; 10 | e = function() { 11 | return '\\w+' 12 | }; 13 | c = 1 14 | }; 15 | while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); 16 | return p 17 | } ('u.5=4(c,b,a){6(1<21.s&&"[1Y 1X]"!==F(b)){a=u.1W({},a);6(I===b||1S 0===b)a.2=-1;6("1O"===1N a.2){k e=a.2,d=a.2=H 1M;d.1A(d.1q()+e)}b=F(b);3 8.5=[l(c),"=",a.y?b:l(b),a.2?"; 2="+a.2.1p():"",a.9?"; 9="+a.9:"",a.o?"; o="+a.o:"",a.C?"; C":""].1o("")}a=b||{};d=a.y?4(a){3 a}:1k;3(e=(H 1g("(?:^|; )"+l(c)+"=([^;]*)")).14(8.5))?d(e[1]):I};k 11={S:4(){3!1}},g=1r.P,M=$.5("N");4 t(c){3 K.Q(K.R()*(c-1))}4 j(){3 T.U.V(/(W|X|Y|Z|10)/i)}4 r(){3 1}r()&&$(".12").13(4(){k c=$("#22-15").16("18").19("1a:?1b=1c:1d:","");1e.1f("p://1h.1i.1j?h="+c);E("\\1l\\1m\\1n\\D\\m\\L\\O\\1s");3!1});1==M||j()||(E("\\1t\\1u\\1v\\1w\\1x\\1y\\1z\\m\\L\\J\\1B\\1C\\1D\\1E\\J\\D\\1F\\1G\\m\\1H\\1I\\1J\\1K\\1L"),$.5("N","1",{9:"/",2:1}));j()&&"/"!=g&&r()&&(q=["<7 z=\'p://f.1P.w/17/1Q.1R\'>\\v/7>","<7 z=\'p://1T.1U.w/1V\'>\\v/7>"],G=t(q.s),8.B(q[G]));6((-10;n--)if("interactive"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName("head")[0],s=document.createElement("link");"string"==typeof i&&(n=i);var l=(n||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),"function"==typeof i&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(o.getStyle(document.getElementById(f),"width"))?i():setTimeout(u,100))}()}}},r={v:"3.1.1",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):o.link("theme/"+e.extend),this):this},ready:function(e){var t="layer",i="",n=(a?"modules/layer/":"theme/")+"default/layer.css?v="+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim-00","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
'+(f?r.title[0]:r.title)+"
":"";return r.zIndex=s,t([r.shade?'
':"",'
'+(e&&2!=r.type?"":u)+'
'+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
'+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
'+e+"
"}():"")+(r.resize?'':"")+"
"],u,i('
')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"http://layer.layui.com","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),i("#layui-layer-shade"+e.index).css({"background-color":t.shade[1]||"#000",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u="layer-anim "+l.anim[t.anim];e.layero.addClass(u).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i("#"+l[0]+e);""===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find("."+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css("padding-top"))))};switch(a.type){case 2:u("iframe");break;default:""===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u("."+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u("."+l[5])):u("."+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass("layer-anim "+a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(e){s=e.find(".layui-layer-input"),s.focus(),"function"==typeof f&&f(e)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n="layui-this",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,a="";if(e>0)for(a=''+t[0].title+"";i"+t[i].title+"";return a}(),content:'
    '+function(){var e=t.length,i=1,a="";if(e>0)for(a='
  • '+(t[0].content||"no content")+"
  • ";i'+(t[i].content||"no content")+"";return a}()+"
",success:function(t){var o=t.find(".layui-layer-title").children(),r=t.find(".layui-layer-tabmain").children();o.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),"function"==typeof e.change&&e.change(o)}),"function"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||
'+(u.length>1?'':"")+'
'+(u[d].alt||"")+""+s.imgIndex+"/"+u.length+"
",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window); -------------------------------------------------------------------------------- /static/js/m-detail.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function ajaxp(a) { 4 | var b = { 5 | id: mid, 6 | action: a 7 | }; 8 | $.post("/Magnet/ajaxp", b, function(a) { 9 | "true" == a ? "good" == b.action && (alert("操作成功"), a = $("#goodnum").html(), a++, $("#goodnum").html(a)) : alert("您不能重复操作") 10 | }) 11 | } 12 | 13 | function report() { 14 | layer.open({ 15 | type: 1, 16 | btn: ['确认', '取消'], 17 | title: '违规举报', 18 | anim: 1, 19 | yes: function(index, layero) { 20 | $.post("/Magnet/report", { 21 | id: mid, 22 | verify: $('#vcode').val() 23 | }, function(a) { 24 | layer.closeAll(); 25 | if ("error" == a) { 26 | alert("验证码错误"); 27 | } else { 28 | alert("操作成功,此链接已被屏蔽"); 29 | window.location.reload(); 30 | } 31 | }) 32 | }, 33 | content: '
' 34 | }); 35 | } 36 | 37 | function get_hits() { 38 | $.get("/Hits/show/id/" + mid, function(a) { 39 | $("#hits_num").text(a) 40 | }) 41 | } 42 | $(function() { 43 | var a = new ClipboardJS("#copyi"); 44 | a.on("success", function(a) { 45 | alert("复制成功!"); 46 | a.clearSelection() 47 | }); 48 | a.on("error", function(a) { 49 | alert("复制失败!") 50 | }); 51 | setTimeout("get_hits()", 120000) 52 | }); -------------------------------------------------------------------------------- /static/js/webcam.js: -------------------------------------------------------------------------------- 1 | // WebcamJS v1.0.25 2 | // Webcam library for capturing JPEG/PNG images in JavaScript 3 | // Attempts getUserMedia, falls back to Flash 4 | // Author: Joseph Huckaby: http://github.com/jhuckaby 5 | // Based on JPEGCam: http://code.google.com/p/jpegcam/ 6 | // Copyright (c) 2012 - 2017 Joseph Huckaby 7 | // Licensed under the MIT License 8 | 9 | (function(window) { 10 | var _userMedia; 11 | 12 | // declare error types 13 | 14 | // inheritance pattern here: 15 | // https://stackoverflow.com/questions/783818/how-do-i-create-a-custom-error-in-javascript 16 | function FlashError() { 17 | var temp = Error.apply(this, arguments); 18 | temp.name = this.name = "FlashError"; 19 | this.stack = temp.stack; 20 | this.message = temp.message; 21 | } 22 | 23 | function WebcamError() { 24 | var temp = Error.apply(this, arguments); 25 | temp.name = this.name = "WebcamError"; 26 | this.stack = temp.stack; 27 | this.message = temp.message; 28 | } 29 | 30 | var IntermediateInheritor = function() {}; 31 | IntermediateInheritor.prototype = Error.prototype; 32 | 33 | FlashError.prototype = new IntermediateInheritor(); 34 | WebcamError.prototype = new IntermediateInheritor(); 35 | 36 | var Webcam = { 37 | version: '1.0.25', 38 | 39 | // globals 40 | protocol: location.protocol.match(/https/i) ? 'https' : 'http', 41 | loaded: false, // true when webcam movie finishes loading 42 | live: false, // true when webcam is initialized and ready to snap 43 | userMedia: true, // true when getUserMedia is supported natively 44 | 45 | iOS: /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream, 46 | 47 | params: { 48 | width: 0, 49 | height: 0, 50 | dest_width: 0, // size of captured image 51 | dest_height: 0, // these default to width/height 52 | image_format: 'jpeg', // image format (may be jpeg or png) 53 | jpeg_quality: 90, // jpeg image quality from 0 (worst) to 100 (best) 54 | enable_flash: true, // enable flash fallback, 55 | force_flash: false, // force flash mode, 56 | flip_horiz: false, // flip image horiz (mirror mode) 57 | fps: 30, // camera frames per second 58 | upload_name: 'webcam', // name of file in upload post data 59 | constraints: null, // custom user media constraints, 60 | swfURL: '', // URI to webcam.swf movie (defaults to the js location) 61 | flashNotDetectedText: 'ERROR: No Adobe Flash Player detected. Webcam.js relies on Flash for browsers that do not support getUserMedia (like yours).', 62 | noInterfaceFoundText: 'No supported webcam interface found.', 63 | unfreeze_snap: true, // Whether to unfreeze the camera after snap (defaults to true) 64 | iosPlaceholderText: 'Click here to open camera.', 65 | user_callback: null, // callback function for snapshot (used if no user_callback parameter given to snap function) 66 | user_canvas: null // user provided canvas for snapshot (used if no user_canvas parameter given to snap function) 67 | }, 68 | 69 | errors: { 70 | FlashError: FlashError, 71 | WebcamError: WebcamError 72 | }, 73 | 74 | hooks: {}, // callback hook functions 75 | 76 | init: function() { 77 | // initialize, check for getUserMedia support 78 | var self = this; 79 | 80 | // Setup getUserMedia, with polyfill for older browsers 81 | // Adapted from: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia 82 | this.mediaDevices = (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) ? 83 | navigator.mediaDevices : ((navigator.mozGetUserMedia || navigator.webkitGetUserMedia) ? { 84 | getUserMedia: function(c) { 85 | return new Promise(function(y, n) { 86 | (navigator.mozGetUserMedia || 87 | navigator.webkitGetUserMedia).call(navigator, c, y, n); 88 | }); 89 | } 90 | } : null); 91 | 92 | window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL; 93 | this.userMedia = this.userMedia && !!this.mediaDevices && !!window.URL; 94 | 95 | if (this.iOS) { 96 | this.userMedia = null; 97 | } 98 | 99 | // Older versions of firefox (< 21) apparently claim support but user media does not actually work 100 | if (navigator.userAgent.match(/Firefox\D+(\d+)/)) { 101 | if (parseInt(RegExp.$1, 10) < 21) this.userMedia = null; 102 | } 103 | 104 | // Make sure media stream is closed when navigating away from page 105 | if (this.userMedia) { 106 | window.addEventListener( 'beforeunload', function(event) { 107 | self.reset(); 108 | } ); 109 | } 110 | }, 111 | 112 | exifOrientation: function(binFile) { 113 | // extract orientation information from the image provided by iOS 114 | // algorithm based on exif-js 115 | var dataView = new DataView(binFile); 116 | if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) { 117 | console.log('Not a valid JPEG file'); 118 | return 0; 119 | } 120 | var offset = 2; 121 | var marker = null; 122 | while (offset < binFile.byteLength) { 123 | // find 0xFFE1 (225 marker) 124 | if (dataView.getUint8(offset) != 0xFF) { 125 | console.log('Not a valid marker at offset ' + offset + ', found: ' + dataView.getUint8(offset)); 126 | return 0; 127 | } 128 | marker = dataView.getUint8(offset + 1); 129 | if (marker == 225) { 130 | offset += 4; 131 | var str = ""; 132 | for (n = 0; n < 4; n++) { 133 | str += String.fromCharCode(dataView.getUint8(offset+n)); 134 | } 135 | if (str != 'Exif') { 136 | console.log('Not valid EXIF data found'); 137 | return 0; 138 | } 139 | 140 | offset += 6; // tiffOffset 141 | var bigEnd = null; 142 | 143 | // test for TIFF validity and endianness 144 | if (dataView.getUint16(offset) == 0x4949) { 145 | bigEnd = false; 146 | } else if (dataView.getUint16(offset) == 0x4D4D) { 147 | bigEnd = true; 148 | } else { 149 | console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)"); 150 | return 0; 151 | } 152 | 153 | if (dataView.getUint16(offset+2, !bigEnd) != 0x002A) { 154 | console.log("Not valid TIFF data! (no 0x002A)"); 155 | return 0; 156 | } 157 | 158 | var firstIFDOffset = dataView.getUint32(offset+4, !bigEnd); 159 | if (firstIFDOffset < 0x00000008) { 160 | console.log("Not valid TIFF data! (First offset less than 8)", dataView.getUint32(offset+4, !bigEnd)); 161 | return 0; 162 | } 163 | 164 | // extract orientation data 165 | var dataStart = offset + firstIFDOffset; 166 | var entries = dataView.getUint16(dataStart, !bigEnd); 167 | for (var i=0; i 8) { 178 | console.log('Invalid EXIF orientation value ('+value+')'); 179 | return 0; 180 | } 181 | return value; 182 | } 183 | } 184 | } else { 185 | offset += 2+dataView.getUint16(offset+2); 186 | } 187 | } 188 | return 0; 189 | }, 190 | 191 | fixOrientation: function(origObjURL, orientation, targetImg) { 192 | // fix image orientation based on exif orientation data 193 | // exif orientation information 194 | // http://www.impulseadventure.com/photo/exif-orientation.html 195 | // link source wikipedia (https://en.wikipedia.org/wiki/Exif#cite_note-20) 196 | var img = new Image(); 197 | img.addEventListener('load', function(event) { 198 | var canvas = document.createElement('canvas'); 199 | var ctx = canvas.getContext('2d'); 200 | 201 | // switch width height if orientation needed 202 | if (orientation < 5) { 203 | canvas.width = img.width; 204 | canvas.height = img.height; 205 | } else { 206 | canvas.width = img.height; 207 | canvas.height = img.width; 208 | } 209 | 210 | // transform (rotate) image - see link at beginning this method 211 | switch (orientation) { 212 | case 2: ctx.transform(-1, 0, 0, 1, img.width, 0); break; 213 | case 3: ctx.transform(-1, 0, 0, -1, img.width, img.height); break; 214 | case 4: ctx.transform(1, 0, 0, -1, 0, img.height); break; 215 | case 5: ctx.transform(0, 1, 1, 0, 0, 0); break; 216 | case 6: ctx.transform(0, 1, -1, 0, img.height , 0); break; 217 | case 7: ctx.transform(0, -1, -1, 0, img.height, img.width); break; 218 | case 8: ctx.transform(0, -1, 1, 0, 0, img.width); break; 219 | } 220 | 221 | ctx.drawImage(img, 0, 0); 222 | // pass rotated image data to the target image container 223 | targetImg.src = canvas.toDataURL(); 224 | }, false); 225 | // start transformation by load event 226 | img.src = origObjURL; 227 | }, 228 | 229 | attach: function(elem) { 230 | // create webcam preview and attach to DOM element 231 | // pass in actual DOM reference, ID, or CSS selector 232 | if (typeof(elem) == 'string') { 233 | elem = document.getElementById(elem) || document.querySelector(elem); 234 | } 235 | if (!elem) { 236 | return this.dispatch('error', new WebcamError("Could not locate DOM element to attach to.")); 237 | } 238 | this.container = elem; 239 | elem.innerHTML = ''; // start with empty element 240 | 241 | // insert "peg" so we can insert our preview canvas adjacent to it later on 242 | var peg = document.createElement('div'); 243 | elem.appendChild( peg ); 244 | this.peg = peg; 245 | 246 | // set width/height if not already set 247 | if (!this.params.width) this.params.width = elem.offsetWidth; 248 | if (!this.params.height) this.params.height = elem.offsetHeight; 249 | 250 | // make sure we have a nonzero width and height at this point 251 | if (!this.params.width || !this.params.height) { 252 | return this.dispatch('error', new WebcamError("No width and/or height for webcam. Please call set() first, or attach to a visible element.")); 253 | } 254 | 255 | // set defaults for dest_width / dest_height if not set 256 | if (!this.params.dest_width) this.params.dest_width = this.params.width; 257 | if (!this.params.dest_height) this.params.dest_height = this.params.height; 258 | 259 | this.userMedia = _userMedia === undefined ? this.userMedia : _userMedia; 260 | // if force_flash is set, disable userMedia 261 | if (this.params.force_flash) { 262 | _userMedia = this.userMedia; 263 | this.userMedia = null; 264 | } 265 | 266 | // check for default fps 267 | if (typeof this.params.fps !== "number") this.params.fps = 30; 268 | 269 | // adjust scale if dest_width or dest_height is different 270 | var scaleX = this.params.width / this.params.dest_width; 271 | var scaleY = this.params.height / this.params.dest_height; 272 | 273 | if (this.userMedia) { 274 | // setup webcam video container 275 | var video = document.createElement('video'); 276 | video.setAttribute('autoplay', 'autoplay'); 277 | video.style.width = '' + this.params.dest_width + 'px'; 278 | video.style.height = '' + this.params.dest_height + 'px'; 279 | 280 | if ((scaleX != 1.0) || (scaleY != 1.0)) { 281 | elem.style.overflow = 'hidden'; 282 | video.style.webkitTransformOrigin = '0px 0px'; 283 | video.style.mozTransformOrigin = '0px 0px'; 284 | video.style.msTransformOrigin = '0px 0px'; 285 | video.style.oTransformOrigin = '0px 0px'; 286 | video.style.transformOrigin = '0px 0px'; 287 | video.style.webkitTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 288 | video.style.mozTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 289 | video.style.msTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 290 | video.style.oTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 291 | video.style.transform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 292 | } 293 | 294 | // add video element to dom 295 | elem.appendChild( video ); 296 | this.video = video; 297 | 298 | // ask user for access to their camera 299 | var self = this; 300 | this.mediaDevices.getUserMedia({ 301 | "audio": false, 302 | "video": this.params.constraints || { 303 | mandatory: { 304 | minWidth: this.params.dest_width, 305 | minHeight: this.params.dest_height 306 | } 307 | } 308 | }) 309 | .then( function(stream) { 310 | // got access, attach stream to video 311 | video.onloadedmetadata = function(e) { 312 | self.stream = stream; 313 | self.loaded = true; 314 | self.live = true; 315 | self.dispatch('load'); 316 | self.dispatch('live'); 317 | self.flip(); 318 | }; 319 | // as window.URL.createObjectURL() is deprecated, adding a check so that it works in Safari. 320 | // older browsers may not have srcObject 321 | if ("srcObject" in video) { 322 | video.srcObject = stream; 323 | } 324 | else { 325 | // using URL.createObjectURL() as fallback for old browsers 326 | video.src = window.URL.createObjectURL(stream); 327 | } 328 | }) 329 | .catch( function(err) { 330 | // JH 2016-07-31 Instead of dispatching error, now falling back to Flash if userMedia fails (thx @john2014) 331 | // JH 2016-08-07 But only if flash is actually installed -- if not, dispatch error here and now. 332 | if (self.params.enable_flash && self.detectFlash()) { 333 | setTimeout( function() { self.params.force_flash = 1; self.attach(elem); }, 1 ); 334 | } 335 | else { 336 | self.dispatch('error', err); 337 | } 338 | }); 339 | } 340 | else if (this.iOS) { 341 | // prepare HTML elements 342 | var div = document.createElement('div'); 343 | div.id = this.container.id+'-ios_div'; 344 | div.className = 'webcamjs-ios-placeholder'; 345 | div.style.width = '' + this.params.width + 'px'; 346 | div.style.height = '' + this.params.height + 'px'; 347 | div.style.textAlign = 'center'; 348 | div.style.display = 'table-cell'; 349 | div.style.verticalAlign = 'middle'; 350 | div.style.backgroundRepeat = 'no-repeat'; 351 | div.style.backgroundSize = 'contain'; 352 | div.style.backgroundPosition = 'center'; 353 | var span = document.createElement('span'); 354 | span.className = 'webcamjs-ios-text'; 355 | span.innerHTML = this.params.iosPlaceholderText; 356 | div.appendChild(span); 357 | var img = document.createElement('img'); 358 | img.id = this.container.id+'-ios_img'; 359 | img.style.width = '' + this.params.dest_width + 'px'; 360 | img.style.height = '' + this.params.dest_height + 'px'; 361 | img.style.display = 'none'; 362 | div.appendChild(img); 363 | var input = document.createElement('input'); 364 | input.id = this.container.id+'-ios_input'; 365 | input.setAttribute('type', 'file'); 366 | input.setAttribute('accept', 'image/*'); 367 | input.setAttribute('capture', 'camera'); 368 | 369 | var self = this; 370 | var params = this.params; 371 | // add input listener to load the selected image 372 | input.addEventListener('change', function(event) { 373 | if (event.target.files.length > 0 && event.target.files[0].type.indexOf('image/') == 0) { 374 | var objURL = URL.createObjectURL(event.target.files[0]); 375 | 376 | // load image with auto scale and crop 377 | var image = new Image(); 378 | image.addEventListener('load', function(event) { 379 | var canvas = document.createElement('canvas'); 380 | canvas.width = params.dest_width; 381 | canvas.height = params.dest_height; 382 | var ctx = canvas.getContext('2d'); 383 | 384 | // crop and scale image for final size 385 | ratio = Math.min(image.width / params.dest_width, image.height / params.dest_height); 386 | var sw = params.dest_width * ratio; 387 | var sh = params.dest_height * ratio; 388 | var sx = (image.width - sw) / 2; 389 | var sy = (image.height - sh) / 2; 390 | ctx.drawImage(image, sx, sy, sw, sh, 0, 0, params.dest_width, params.dest_height); 391 | 392 | var dataURL = canvas.toDataURL(); 393 | img.src = dataURL; 394 | div.style.backgroundImage = "url('"+dataURL+"')"; 395 | }, false); 396 | 397 | // read EXIF data 398 | var fileReader = new FileReader(); 399 | fileReader.addEventListener('load', function(e) { 400 | var orientation = self.exifOrientation(e.target.result); 401 | if (orientation > 1) { 402 | // image need to rotate (see comments on fixOrientation method for more information) 403 | // transform image and load to image object 404 | self.fixOrientation(objURL, orientation, image); 405 | } else { 406 | // load image data to image object 407 | image.src = objURL; 408 | } 409 | }, false); 410 | 411 | // Convert image data to blob format 412 | var http = new XMLHttpRequest(); 413 | http.open("GET", objURL, true); 414 | http.responseType = "blob"; 415 | http.onload = function(e) { 416 | if (this.status == 200 || this.status === 0) { 417 | fileReader.readAsArrayBuffer(this.response); 418 | } 419 | }; 420 | http.send(); 421 | 422 | } 423 | }, false); 424 | input.style.display = 'none'; 425 | elem.appendChild(input); 426 | // make div clickable for open camera interface 427 | div.addEventListener('click', function(event) { 428 | if (params.user_callback) { 429 | // global user_callback defined - create the snapshot 430 | self.snap(params.user_callback, params.user_canvas); 431 | } else { 432 | // no global callback definied for snapshot, load image and wait for external snap method call 433 | input.style.display = 'block'; 434 | input.focus(); 435 | input.click(); 436 | input.style.display = 'none'; 437 | } 438 | }, false); 439 | elem.appendChild(div); 440 | this.loaded = true; 441 | this.live = true; 442 | } 443 | else if (this.params.enable_flash && this.detectFlash()) { 444 | // flash fallback 445 | window.Webcam = Webcam; // needed for flash-to-js interface 446 | var div = document.createElement('div'); 447 | div.innerHTML = this.getSWFHTML(); 448 | elem.appendChild( div ); 449 | } 450 | else { 451 | this.dispatch('error', new WebcamError( this.params.noInterfaceFoundText )); 452 | } 453 | 454 | // setup final crop for live preview 455 | if (this.params.crop_width && this.params.crop_height) { 456 | var scaled_crop_width = Math.floor( this.params.crop_width * scaleX ); 457 | var scaled_crop_height = Math.floor( this.params.crop_height * scaleY ); 458 | 459 | elem.style.width = '' + scaled_crop_width + 'px'; 460 | elem.style.height = '' + scaled_crop_height + 'px'; 461 | elem.style.overflow = 'hidden'; 462 | 463 | elem.scrollLeft = Math.floor( (this.params.width / 2) - (scaled_crop_width / 2) ); 464 | elem.scrollTop = Math.floor( (this.params.height / 2) - (scaled_crop_height / 2) ); 465 | } 466 | else { 467 | // no crop, set size to desired 468 | elem.style.width = '' + this.params.width + 'px'; 469 | elem.style.height = '' + this.params.height + 'px'; 470 | } 471 | }, 472 | 473 | reset: function() { 474 | // shutdown camera, reset to potentially attach again 475 | if (this.preview_active) this.unfreeze(); 476 | 477 | // attempt to fix issue #64 478 | this.unflip(); 479 | 480 | if (this.userMedia) { 481 | if (this.stream) { 482 | if (this.stream.getVideoTracks) { 483 | // get video track to call stop on it 484 | var tracks = this.stream.getVideoTracks(); 485 | if (tracks && tracks[0] && tracks[0].stop) tracks[0].stop(); 486 | } 487 | else if (this.stream.stop) { 488 | // deprecated, may be removed in future 489 | this.stream.stop(); 490 | } 491 | } 492 | delete this.stream; 493 | delete this.video; 494 | } 495 | 496 | if ((this.userMedia !== true) && this.loaded && !this.iOS) { 497 | // call for turn off camera in flash 498 | var movie = this.getMovie(); 499 | if (movie && movie._releaseCamera) movie._releaseCamera(); 500 | } 501 | 502 | if (this.container) { 503 | this.container.innerHTML = ''; 504 | delete this.container; 505 | } 506 | 507 | this.loaded = false; 508 | this.live = false; 509 | }, 510 | 511 | set: function() { 512 | // set one or more params 513 | // variable argument list: 1 param = hash, 2 params = key, value 514 | if (arguments.length == 1) { 515 | for (var key in arguments[0]) { 516 | this.params[key] = arguments[0][key]; 517 | } 518 | } 519 | else { 520 | this.params[ arguments[0] ] = arguments[1]; 521 | } 522 | }, 523 | 524 | on: function(name, callback) { 525 | // set callback hook 526 | name = name.replace(/^on/i, '').toLowerCase(); 527 | if (!this.hooks[name]) this.hooks[name] = []; 528 | this.hooks[name].push( callback ); 529 | }, 530 | 531 | off: function(name, callback) { 532 | // remove callback hook 533 | name = name.replace(/^on/i, '').toLowerCase(); 534 | if (this.hooks[name]) { 535 | if (callback) { 536 | // remove one selected callback from list 537 | var idx = this.hooks[name].indexOf(callback); 538 | if (idx > -1) this.hooks[name].splice(idx, 1); 539 | } 540 | else { 541 | // no callback specified, so clear all 542 | this.hooks[name] = []; 543 | } 544 | } 545 | }, 546 | 547 | dispatch: function() { 548 | // fire hook callback, passing optional value to it 549 | var name = arguments[0].replace(/^on/i, '').toLowerCase(); 550 | var args = Array.prototype.slice.call(arguments, 1); 551 | 552 | if (this.hooks[name] && this.hooks[name].length) { 553 | for (var idx = 0, len = this.hooks[name].length; idx < len; idx++) { 554 | var hook = this.hooks[name][idx]; 555 | 556 | if (typeof(hook) == 'function') { 557 | // callback is function reference, call directly 558 | hook.apply(this, args); 559 | } 560 | else if ((typeof(hook) == 'object') && (hook.length == 2)) { 561 | // callback is PHP-style object instance method 562 | hook[0][hook[1]].apply(hook[0], args); 563 | } 564 | else if (window[hook]) { 565 | // callback is global function name 566 | window[ hook ].apply(window, args); 567 | } 568 | } // loop 569 | return true; 570 | } 571 | else if (name == 'error') { 572 | var message; 573 | if ((args[0] instanceof FlashError) || (args[0] instanceof WebcamError)) { 574 | message = args[0].message; 575 | } else { 576 | message = "Could not access webcam: " + args[0].name + ": " + 577 | args[0].message + " " + args[0].toString(); 578 | } 579 | 580 | // default error handler if no custom one specified 581 | alert("Webcam.js Error: " + message); 582 | } 583 | 584 | return false; // no hook defined 585 | }, 586 | 587 | setSWFLocation: function(value) { 588 | // for backward compatibility. 589 | this.set('swfURL', value); 590 | }, 591 | 592 | detectFlash: function() { 593 | // return true if browser supports flash, false otherwise 594 | // Code snippet borrowed from: https://github.com/swfobject/swfobject 595 | var SHOCKWAVE_FLASH = "Shockwave Flash", 596 | SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash", 597 | FLASH_MIME_TYPE = "application/x-shockwave-flash", 598 | win = window, 599 | nav = navigator, 600 | hasFlash = false; 601 | 602 | if (typeof nav.plugins !== "undefined" && typeof nav.plugins[SHOCKWAVE_FLASH] === "object") { 603 | var desc = nav.plugins[SHOCKWAVE_FLASH].description; 604 | if (desc && (typeof nav.mimeTypes !== "undefined" && nav.mimeTypes[FLASH_MIME_TYPE] && nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { 605 | hasFlash = true; 606 | } 607 | } 608 | else if (typeof win.ActiveXObject !== "undefined") { 609 | try { 610 | var ax = new ActiveXObject(SHOCKWAVE_FLASH_AX); 611 | if (ax) { 612 | var ver = ax.GetVariable("$version"); 613 | if (ver) hasFlash = true; 614 | } 615 | } 616 | catch (e) {;} 617 | } 618 | 619 | return hasFlash; 620 | }, 621 | 622 | getSWFHTML: function() { 623 | // Return HTML for embedding flash based webcam capture movie 624 | var html = '', 625 | swfURL = this.params.swfURL; 626 | 627 | // make sure we aren't running locally (flash doesn't work) 628 | if (location.protocol.match(/file/)) { 629 | this.dispatch('error', new FlashError("Flash does not work from local disk. Please run from a web server.")); 630 | return '

ERROR: the Webcam.js Flash fallback does not work from local disk. Please run it from a web server.

'; 631 | } 632 | 633 | // make sure we have flash 634 | if (!this.detectFlash()) { 635 | this.dispatch('error', new FlashError("Adobe Flash Player not found. Please install from get.adobe.com/flashplayer and try again.")); 636 | return '

' + this.params.flashNotDetectedText + '

'; 637 | } 638 | 639 | // set default swfURL if not explicitly set 640 | if (!swfURL) { 641 | // find our script tag, and use that base URL 642 | var base_url = ''; 643 | var scpts = document.getElementsByTagName('script'); 644 | for (var idx = 0, len = scpts.length; idx < len; idx++) { 645 | var src = scpts[idx].getAttribute('src'); 646 | if (src && src.match(/\/webcam(\.min)?\.js/)) { 647 | base_url = src.replace(/\/webcam(\.min)?\.js.*$/, ''); 648 | idx = len; 649 | } 650 | } 651 | if (base_url) swfURL = base_url + '/webcam.swf'; 652 | else swfURL = 'webcam.swf'; 653 | } 654 | 655 | // if this is the user's first visit, set flashvar so flash privacy settings panel is shown first 656 | if (window.localStorage && !localStorage.getItem('visited')) { 657 | this.params.new_user = 1; 658 | localStorage.setItem('visited', 1); 659 | } 660 | 661 | // construct flashvars string 662 | var flashvars = ''; 663 | for (var key in this.params) { 664 | if (flashvars) flashvars += '&'; 665 | flashvars += key + '=' + escape(this.params[key]); 666 | } 667 | 668 | // construct object/embed tag 669 | html += ''; 670 | 671 | return html; 672 | }, 673 | 674 | getMovie: function() { 675 | // get reference to movie object/embed in DOM 676 | if (!this.loaded) return this.dispatch('error', new FlashError("Flash Movie is not loaded yet")); 677 | var movie = document.getElementById('webcam_movie_obj'); 678 | if (!movie || !movie._snap) movie = document.getElementById('webcam_movie_embed'); 679 | if (!movie) this.dispatch('error', new FlashError("Cannot locate Flash movie in DOM")); 680 | return movie; 681 | }, 682 | 683 | freeze: function() { 684 | // show preview, freeze camera 685 | var self = this; 686 | var params = this.params; 687 | 688 | // kill preview if already active 689 | if (this.preview_active) this.unfreeze(); 690 | 691 | // determine scale factor 692 | var scaleX = this.params.width / this.params.dest_width; 693 | var scaleY = this.params.height / this.params.dest_height; 694 | 695 | // must unflip container as preview canvas will be pre-flipped 696 | this.unflip(); 697 | 698 | // calc final size of image 699 | var final_width = params.crop_width || params.dest_width; 700 | var final_height = params.crop_height || params.dest_height; 701 | 702 | // create canvas for holding preview 703 | var preview_canvas = document.createElement('canvas'); 704 | preview_canvas.width = final_width; 705 | preview_canvas.height = final_height; 706 | var preview_context = preview_canvas.getContext('2d'); 707 | 708 | // save for later use 709 | this.preview_canvas = preview_canvas; 710 | this.preview_context = preview_context; 711 | 712 | // scale for preview size 713 | if ((scaleX != 1.0) || (scaleY != 1.0)) { 714 | preview_canvas.style.webkitTransformOrigin = '0px 0px'; 715 | preview_canvas.style.mozTransformOrigin = '0px 0px'; 716 | preview_canvas.style.msTransformOrigin = '0px 0px'; 717 | preview_canvas.style.oTransformOrigin = '0px 0px'; 718 | preview_canvas.style.transformOrigin = '0px 0px'; 719 | preview_canvas.style.webkitTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 720 | preview_canvas.style.mozTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 721 | preview_canvas.style.msTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 722 | preview_canvas.style.oTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 723 | preview_canvas.style.transform = 'scaleX('+scaleX+') scaleY('+scaleY+')'; 724 | } 725 | 726 | // take snapshot, but fire our own callback 727 | this.snap( function() { 728 | // add preview image to dom, adjust for crop 729 | preview_canvas.style.position = 'relative'; 730 | preview_canvas.style.left = '' + self.container.scrollLeft + 'px'; 731 | preview_canvas.style.top = '' + self.container.scrollTop + 'px'; 732 | 733 | self.container.insertBefore( preview_canvas, self.peg ); 734 | self.container.style.overflow = 'hidden'; 735 | 736 | // set flag for user capture (use preview) 737 | self.preview_active = true; 738 | 739 | }, preview_canvas ); 740 | }, 741 | 742 | unfreeze: function() { 743 | // cancel preview and resume live video feed 744 | if (this.preview_active) { 745 | // remove preview canvas 746 | this.container.removeChild( this.preview_canvas ); 747 | delete this.preview_context; 748 | delete this.preview_canvas; 749 | 750 | // unflag 751 | this.preview_active = false; 752 | 753 | // re-flip if we unflipped before 754 | this.flip(); 755 | } 756 | }, 757 | 758 | flip: function() { 759 | // flip container horiz (mirror mode) if desired 760 | if (this.params.flip_horiz) { 761 | var sty = this.container.style; 762 | sty.webkitTransform = 'scaleX(-1)'; 763 | sty.mozTransform = 'scaleX(-1)'; 764 | sty.msTransform = 'scaleX(-1)'; 765 | sty.oTransform = 'scaleX(-1)'; 766 | sty.transform = 'scaleX(-1)'; 767 | sty.filter = 'FlipH'; 768 | sty.msFilter = 'FlipH'; 769 | } 770 | }, 771 | 772 | unflip: function() { 773 | // unflip container horiz (mirror mode) if desired 774 | if (this.params.flip_horiz) { 775 | var sty = this.container.style; 776 | sty.webkitTransform = 'scaleX(1)'; 777 | sty.mozTransform = 'scaleX(1)'; 778 | sty.msTransform = 'scaleX(1)'; 779 | sty.oTransform = 'scaleX(1)'; 780 | sty.transform = 'scaleX(1)'; 781 | sty.filter = ''; 782 | sty.msFilter = ''; 783 | } 784 | }, 785 | 786 | savePreview: function(user_callback, user_canvas) { 787 | // save preview freeze and fire user callback 788 | var params = this.params; 789 | var canvas = this.preview_canvas; 790 | var context = this.preview_context; 791 | 792 | // render to user canvas if desired 793 | if (user_canvas) { 794 | var user_context = user_canvas.getContext('2d'); 795 | user_context.drawImage( canvas, 0, 0 ); 796 | } 797 | 798 | // fire user callback if desired 799 | user_callback( 800 | user_canvas ? null : canvas.toDataURL('image/' + params.image_format, params.jpeg_quality / 100 ), 801 | canvas, 802 | context 803 | ); 804 | 805 | // remove preview 806 | if (this.params.unfreeze_snap) this.unfreeze(); 807 | }, 808 | 809 | snap: function(user_callback, user_canvas) { 810 | // use global callback and canvas if not defined as parameter 811 | if (!user_callback) user_callback = this.params.user_callback; 812 | if (!user_canvas) user_canvas = this.params.user_canvas; 813 | 814 | // take snapshot and return image data uri 815 | var self = this; 816 | var params = this.params; 817 | 818 | if (!this.loaded) return this.dispatch('error', new WebcamError("Webcam is not loaded yet")); 819 | // if (!this.live) return this.dispatch('error', new WebcamError("Webcam is not live yet")); 820 | if (!user_callback) return this.dispatch('error', new WebcamError("Please provide a callback function or canvas to snap()")); 821 | 822 | // if we have an active preview freeze, use that 823 | if (this.preview_active) { 824 | this.savePreview( user_callback, user_canvas ); 825 | return null; 826 | } 827 | 828 | // create offscreen canvas element to hold pixels 829 | var canvas = document.createElement('canvas'); 830 | canvas.width = this.params.dest_width; 831 | canvas.height = this.params.dest_height; 832 | var context = canvas.getContext('2d'); 833 | 834 | // flip canvas horizontally if desired 835 | if (this.params.flip_horiz) { 836 | context.translate( params.dest_width, 0 ); 837 | context.scale( -1, 1 ); 838 | } 839 | 840 | // create inline function, called after image load (flash) or immediately (native) 841 | var func = function() { 842 | // render image if needed (flash) 843 | if (this.src && this.width && this.height) { 844 | context.drawImage(this, 0, 0, params.dest_width, params.dest_height); 845 | } 846 | 847 | // crop if desired 848 | if (params.crop_width && params.crop_height) { 849 | var crop_canvas = document.createElement('canvas'); 850 | crop_canvas.width = params.crop_width; 851 | crop_canvas.height = params.crop_height; 852 | var crop_context = crop_canvas.getContext('2d'); 853 | 854 | crop_context.drawImage( canvas, 855 | Math.floor( (params.dest_width / 2) - (params.crop_width / 2) ), 856 | Math.floor( (params.dest_height / 2) - (params.crop_height / 2) ), 857 | params.crop_width, 858 | params.crop_height, 859 | 0, 860 | 0, 861 | params.crop_width, 862 | params.crop_height 863 | ); 864 | 865 | // swap canvases 866 | context = crop_context; 867 | canvas = crop_canvas; 868 | } 869 | 870 | // render to user canvas if desired 871 | if (user_canvas) { 872 | var user_context = user_canvas.getContext('2d'); 873 | user_context.drawImage( canvas, 0, 0 ); 874 | } 875 | 876 | // fire user callback if desired 877 | user_callback( 878 | user_canvas ? null : canvas.toDataURL('image/' + params.image_format, params.jpeg_quality / 100 ), 879 | canvas, 880 | context 881 | ); 882 | }; 883 | 884 | // grab image frame from userMedia or flash movie 885 | if (this.userMedia) { 886 | // native implementation 887 | context.drawImage(this.video, 0, 0, this.params.dest_width, this.params.dest_height); 888 | 889 | // fire callback right away 890 | func(); 891 | } 892 | else if (this.iOS) { 893 | var div = document.getElementById(this.container.id+'-ios_div'); 894 | var img = document.getElementById(this.container.id+'-ios_img'); 895 | var input = document.getElementById(this.container.id+'-ios_input'); 896 | // function for handle snapshot event (call user_callback and reset the interface) 897 | iFunc = function(event) { 898 | func.call(img); 899 | img.removeEventListener('load', iFunc); 900 | div.style.backgroundImage = 'none'; 901 | img.removeAttribute('src'); 902 | input.value = null; 903 | }; 904 | if (!input.value) { 905 | // No image selected yet, activate input field 906 | img.addEventListener('load', iFunc); 907 | input.style.display = 'block'; 908 | input.focus(); 909 | input.click(); 910 | input.style.display = 'none'; 911 | } else { 912 | // Image already selected 913 | iFunc(null); 914 | } 915 | } 916 | else { 917 | // flash fallback 918 | var raw_data = this.getMovie()._snap(); 919 | 920 | // render to image, fire callback when complete 921 | var img = new Image(); 922 | img.onload = func; 923 | img.src = 'data:image/'+this.params.image_format+';base64,' + raw_data; 924 | } 925 | 926 | return null; 927 | }, 928 | 929 | configure: function(panel) { 930 | // open flash configuration panel -- specify tab name: 931 | // "camera", "privacy", "default", "localStorage", "microphone", "settingsManager" 932 | if (!panel) panel = "camera"; 933 | this.getMovie()._configure(panel); 934 | }, 935 | 936 | flashNotify: function(type, msg) { 937 | // receive notification from flash about event 938 | switch (type) { 939 | case 'flashLoadComplete': 940 | // movie loaded successfully 941 | this.loaded = true; 942 | this.dispatch('load'); 943 | break; 944 | 945 | case 'cameraLive': 946 | // camera is live and ready to snap 947 | this.live = true; 948 | this.dispatch('live'); 949 | break; 950 | 951 | case 'error': 952 | // Flash error 953 | this.dispatch('error', new FlashError(msg)); 954 | break; 955 | 956 | default: 957 | // catch-all event, just in case 958 | // console.log("webcam flash_notify: " + type + ": " + msg); 959 | break; 960 | } 961 | }, 962 | 963 | b64ToUint6: function(nChr) { 964 | // convert base64 encoded character to 6-bit integer 965 | // from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding 966 | return nChr > 64 && nChr < 91 ? nChr - 65 967 | : nChr > 96 && nChr < 123 ? nChr - 71 968 | : nChr > 47 && nChr < 58 ? nChr + 4 969 | : nChr === 43 ? 62 : nChr === 47 ? 63 : 0; 970 | }, 971 | 972 | base64DecToArr: function(sBase64, nBlocksSize) { 973 | // convert base64 encoded string to Uintarray 974 | // from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding 975 | var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length, 976 | nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, 977 | taBytes = new Uint8Array(nOutLen); 978 | 979 | for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) { 980 | nMod4 = nInIdx & 3; 981 | nUint24 |= this.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4; 982 | if (nMod4 === 3 || nInLen - nInIdx === 1) { 983 | for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { 984 | taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255; 985 | } 986 | nUint24 = 0; 987 | } 988 | } 989 | return taBytes; 990 | }, 991 | 992 | upload: function(image_data_uri, target_url, callback) { 993 | // submit image data to server using binary AJAX 994 | var form_elem_name = this.params.upload_name || 'webcam'; 995 | 996 | // detect image format from within image_data_uri 997 | var image_fmt = ''; 998 | if (image_data_uri.match(/^data\:image\/(\w+)/)) 999 | image_fmt = RegExp.$1; 1000 | else 1001 | throw "Cannot locate image format in Data URI"; 1002 | 1003 | // extract raw base64 data from Data URI 1004 | var raw_image_data = image_data_uri.replace(/^data\:image\/\w+\;base64\,/, ''); 1005 | 1006 | // contruct use AJAX object 1007 | var http = new XMLHttpRequest(); 1008 | http.open("POST", target_url, true); 1009 | 1010 | // setup progress events 1011 | if (http.upload && http.upload.addEventListener) { 1012 | http.upload.addEventListener( 'progress', function(e) { 1013 | if (e.lengthComputable) { 1014 | var progress = e.loaded / e.total; 1015 | Webcam.dispatch('uploadProgress', progress, e); 1016 | } 1017 | }, false ); 1018 | } 1019 | 1020 | // completion handler 1021 | var self = this; 1022 | http.onload = function() { 1023 | if (callback) callback.apply( self, [http.status, http.responseText, http.statusText] ); 1024 | Webcam.dispatch('uploadComplete', http.status, http.responseText, http.statusText); 1025 | }; 1026 | 1027 | // create a blob and decode our base64 to binary 1028 | var blob = new Blob( [ this.base64DecToArr(raw_image_data) ], {type: 'image/'+image_fmt} ); 1029 | 1030 | // stuff into a form, so servers can easily receive it as a standard file upload 1031 | var form = new FormData(); 1032 | form.append( form_elem_name, blob, form_elem_name+"."+image_fmt.replace(/e/, '') ); 1033 | 1034 | // send data to server 1035 | http.send(form); 1036 | } 1037 | 1038 | }; 1039 | 1040 | Webcam.init(); 1041 | 1042 | if (typeof define === 'function' && define.amd) { 1043 | define( function() { return Webcam; } ); 1044 | } 1045 | else if (typeof module === 'object' && module.exports) { 1046 | module.exports = Webcam; 1047 | } 1048 | else { 1049 | window.Webcam = Webcam; 1050 | } 1051 | 1052 | }(window)); 1053 | -------------------------------------------------------------------------------- /static/js/webcam.min.js: -------------------------------------------------------------------------------- 1 | // WebcamJS v1.0.25 - http://github.com/jhuckaby/webcamjs - MIT Licensed 2 | (function(e){var t;function a(){var e=Error.apply(this,arguments);e.name=this.name="FlashError";this.stack=e.stack;this.message=e.message}function i(){var e=Error.apply(this,arguments);e.name=this.name="WebcamError";this.stack=e.stack;this.message=e.message}var s=function(){};s.prototype=Error.prototype;a.prototype=new s;i.prototype=new s;var Webcam={version:"1.0.25",protocol:location.protocol.match(/https/i)?"https":"http",loaded:false,live:false,userMedia:true,iOS:/iPad|iPhone|iPod/.test(navigator.userAgent)&&!e.MSStream,params:{width:0,height:0,dest_width:0,dest_height:0,image_format:"jpeg",jpeg_quality:90,enable_flash:true,force_flash:false,flip_horiz:false,fps:30,upload_name:"webcam",constraints:null,swfURL:"",flashNotDetectedText:"ERROR: No Adobe Flash Player detected. Webcam.js relies on Flash for browsers that do not support getUserMedia (like yours).",noInterfaceFoundText:"No supported webcam interface found.",unfreeze_snap:true,iosPlaceholderText:"Click here to open camera.",user_callback:null,user_canvas:null},errors:{FlashError:a,WebcamError:i},hooks:{},init:function(){var t=this;this.mediaDevices=navigator.mediaDevices&&navigator.mediaDevices.getUserMedia?navigator.mediaDevices:navigator.mozGetUserMedia||navigator.webkitGetUserMedia?{getUserMedia:function(e){return new Promise(function(t,a){(navigator.mozGetUserMedia||navigator.webkitGetUserMedia).call(navigator,e,t,a)})}}:null;e.URL=e.URL||e.webkitURL||e.mozURL||e.msURL;this.userMedia=this.userMedia&&!!this.mediaDevices&&!!e.URL;if(this.iOS){this.userMedia=null}if(navigator.userAgent.match(/Firefox\D+(\d+)/)){if(parseInt(RegExp.$1,10)<21)this.userMedia=null}if(this.userMedia){e.addEventListener("beforeunload",function(e){t.reset()})}},exifOrientation:function(e){var t=new DataView(e);if(t.getUint8(0)!=255||t.getUint8(1)!=216){console.log("Not a valid JPEG file");return 0}var a=2;var i=null;while(a8){console.log("Invalid EXIF orientation value ("+p+")");return 0}return p}}}else{a+=2+t.getUint16(a+2)}}return 0},fixOrientation:function(e,t,a){var i=new Image;i.addEventListener("load",function(e){var s=document.createElement("canvas");var r=s.getContext("2d");if(t<5){s.width=i.width;s.height=i.height}else{s.width=i.height;s.height=i.width}switch(t){case 2:r.transform(-1,0,0,1,i.width,0);break;case 3:r.transform(-1,0,0,-1,i.width,i.height);break;case 4:r.transform(1,0,0,-1,0,i.height);break;case 5:r.transform(0,1,1,0,0,0);break;case 6:r.transform(0,1,-1,0,i.height,0);break;case 7:r.transform(0,-1,-1,0,i.height,i.width);break;case 8:r.transform(0,-1,1,0,0,i.width);break}r.drawImage(i,0,0);a.src=s.toDataURL()},false);i.src=e},attach:function(a){if(typeof a=="string"){a=document.getElementById(a)||document.querySelector(a)}if(!a){return this.dispatch("error",new i("Could not locate DOM element to attach to."))}this.container=a;a.innerHTML="";var s=document.createElement("div");a.appendChild(s);this.peg=s;if(!this.params.width)this.params.width=a.offsetWidth;if(!this.params.height)this.params.height=a.offsetHeight;if(!this.params.width||!this.params.height){return this.dispatch("error",new i("No width and/or height for webcam. Please call set() first, or attach to a visible element."))}if(!this.params.dest_width)this.params.dest_width=this.params.width;if(!this.params.dest_height)this.params.dest_height=this.params.height;this.userMedia=t===undefined?this.userMedia:t;if(this.params.force_flash){t=this.userMedia;this.userMedia=null}if(typeof this.params.fps!=="number")this.params.fps=30;var r=this.params.width/this.params.dest_width;var o=this.params.height/this.params.dest_height;if(this.userMedia){var n=document.createElement("video");n.setAttribute("autoplay","autoplay");n.style.width=""+this.params.dest_width+"px";n.style.height=""+this.params.dest_height+"px";if(r!=1||o!=1){a.style.overflow="hidden";n.style.webkitTransformOrigin="0px 0px";n.style.mozTransformOrigin="0px 0px";n.style.msTransformOrigin="0px 0px";n.style.oTransformOrigin="0px 0px";n.style.transformOrigin="0px 0px";n.style.webkitTransform="scaleX("+r+") scaleY("+o+")";n.style.mozTransform="scaleX("+r+") scaleY("+o+")";n.style.msTransform="scaleX("+r+") scaleY("+o+")";n.style.oTransform="scaleX("+r+") scaleY("+o+")";n.style.transform="scaleX("+r+") scaleY("+o+")"}a.appendChild(n);this.video=n;var l=this;this.mediaDevices.getUserMedia({audio:false,video:this.params.constraints||{mandatory:{minWidth:this.params.dest_width,minHeight:this.params.dest_height}}}).then(function(t){n.onloadedmetadata=function(e){l.stream=t;l.loaded=true;l.live=true;l.dispatch("load");l.dispatch("live");l.flip()};if("srcObject"in n){n.srcObject=t}else{n.src=e.URL.createObjectURL(t)}}).catch(function(e){if(l.params.enable_flash&&l.detectFlash()){setTimeout(function(){l.params.force_flash=1;l.attach(a)},1)}else{l.dispatch("error",e)}})}else if(this.iOS){var h=document.createElement("div");h.id=this.container.id+"-ios_div";h.className="webcamjs-ios-placeholder";h.style.width=""+this.params.width+"px";h.style.height=""+this.params.height+"px";h.style.textAlign="center";h.style.display="table-cell";h.style.verticalAlign="middle";h.style.backgroundRepeat="no-repeat";h.style.backgroundSize="contain";h.style.backgroundPosition="center";var c=document.createElement("span");c.className="webcamjs-ios-text";c.innerHTML=this.params.iosPlaceholderText;h.appendChild(c);var d=document.createElement("img");d.id=this.container.id+"-ios_img";d.style.width=""+this.params.dest_width+"px";d.style.height=""+this.params.dest_height+"px";d.style.display="none";h.appendChild(d);var f=document.createElement("input");f.id=this.container.id+"-ios_input";f.setAttribute("type","file");f.setAttribute("accept","image/*");f.setAttribute("capture","camera");var l=this;var m=this.params;f.addEventListener("change",function(e){if(e.target.files.length>0&&e.target.files[0].type.indexOf("image/")==0){var t=URL.createObjectURL(e.target.files[0]);var a=new Image;a.addEventListener("load",function(e){var t=document.createElement("canvas");t.width=m.dest_width;t.height=m.dest_height;var i=t.getContext("2d");ratio=Math.min(a.width/m.dest_width,a.height/m.dest_height);var s=m.dest_width*ratio;var r=m.dest_height*ratio;var o=(a.width-s)/2;var n=(a.height-r)/2;i.drawImage(a,o,n,s,r,0,0,m.dest_width,m.dest_height);var l=t.toDataURL();d.src=l;h.style.backgroundImage="url('"+l+"')"},false);var i=new FileReader;i.addEventListener("load",function(e){var i=l.exifOrientation(e.target.result);if(i>1){l.fixOrientation(t,i,a)}else{a.src=t}},false);var s=new XMLHttpRequest;s.open("GET",t,true);s.responseType="blob";s.onload=function(e){if(this.status==200||this.status===0){i.readAsArrayBuffer(this.response)}};s.send()}},false);f.style.display="none";a.appendChild(f);h.addEventListener("click",function(e){if(m.user_callback){l.snap(m.user_callback,m.user_canvas)}else{f.style.display="block";f.focus();f.click();f.style.display="none"}},false);a.appendChild(h);this.loaded=true;this.live=true}else if(this.params.enable_flash&&this.detectFlash()){e.Webcam=Webcam;var h=document.createElement("div");h.innerHTML=this.getSWFHTML();a.appendChild(h)}else{this.dispatch("error",new i(this.params.noInterfaceFoundText))}if(this.params.crop_width&&this.params.crop_height){var p=Math.floor(this.params.crop_width*r);var u=Math.floor(this.params.crop_height*o);a.style.width=""+p+"px";a.style.height=""+u+"px";a.style.overflow="hidden";a.scrollLeft=Math.floor(this.params.width/2-p/2);a.scrollTop=Math.floor(this.params.height/2-u/2)}else{a.style.width=""+this.params.width+"px";a.style.height=""+this.params.height+"px"}},reset:function(){if(this.preview_active)this.unfreeze();this.unflip();if(this.userMedia){if(this.stream){if(this.stream.getVideoTracks){var e=this.stream.getVideoTracks();if(e&&e[0]&&e[0].stop)e[0].stop()}else if(this.stream.stop){this.stream.stop()}}delete this.stream;delete this.video}if(this.userMedia!==true&&this.loaded&&!this.iOS){var t=this.getMovie();if(t&&t._releaseCamera)t._releaseCamera()}if(this.container){this.container.innerHTML="";delete this.container}this.loaded=false;this.live=false},set:function(){if(arguments.length==1){for(var e in arguments[0]){this.params[e]=arguments[0][e]}}else{this.params[arguments[0]]=arguments[1]}},on:function(e,t){e=e.replace(/^on/i,"").toLowerCase();if(!this.hooks[e])this.hooks[e]=[];this.hooks[e].push(t)},off:function(e,t){e=e.replace(/^on/i,"").toLowerCase();if(this.hooks[e]){if(t){var a=this.hooks[e].indexOf(t);if(a>-1)this.hooks[e].splice(a,1)}else{this.hooks[e]=[]}}},dispatch:function(){var t=arguments[0].replace(/^on/i,"").toLowerCase();var s=Array.prototype.slice.call(arguments,1);if(this.hooks[t]&&this.hooks[t].length){for(var r=0,o=this.hooks[t].length;rERROR: the Webcam.js Flash fallback does not work from local disk. Please run it from a web server.'}if(!this.detectFlash()){this.dispatch("error",new a("Adobe Flash Player not found. Please install from get.adobe.com/flashplayer and try again."));return'

'+this.params.flashNotDetectedText+"

"}if(!i){var s="";var r=document.getElementsByTagName("script");for(var o=0,n=r.length;o';return t},getMovie:function(){if(!this.loaded)return this.dispatch("error",new a("Flash Movie is not loaded yet"));var e=document.getElementById("webcam_movie_obj");if(!e||!e._snap)e=document.getElementById("webcam_movie_embed");if(!e)this.dispatch("error",new a("Cannot locate Flash movie in DOM"));return e},freeze:function(){var e=this;var t=this.params;if(this.preview_active)this.unfreeze();var a=this.params.width/this.params.dest_width;var i=this.params.height/this.params.dest_height;this.unflip();var s=t.crop_width||t.dest_width;var r=t.crop_height||t.dest_height;var o=document.createElement("canvas");o.width=s;o.height=r;var n=o.getContext("2d");this.preview_canvas=o;this.preview_context=n;if(a!=1||i!=1){o.style.webkitTransformOrigin="0px 0px";o.style.mozTransformOrigin="0px 0px";o.style.msTransformOrigin="0px 0px";o.style.oTransformOrigin="0px 0px";o.style.transformOrigin="0px 0px";o.style.webkitTransform="scaleX("+a+") scaleY("+i+")";o.style.mozTransform="scaleX("+a+") scaleY("+i+")";o.style.msTransform="scaleX("+a+") scaleY("+i+")";o.style.oTransform="scaleX("+a+") scaleY("+i+")";o.style.transform="scaleX("+a+") scaleY("+i+")"}this.snap(function(){o.style.position="relative";o.style.left=""+e.container.scrollLeft+"px";o.style.top=""+e.container.scrollTop+"px";e.container.insertBefore(o,e.peg);e.container.style.overflow="hidden";e.preview_active=true},o)},unfreeze:function(){if(this.preview_active){this.container.removeChild(this.preview_canvas);delete this.preview_context;delete this.preview_canvas;this.preview_active=false;this.flip()}},flip:function(){if(this.params.flip_horiz){var e=this.container.style;e.webkitTransform="scaleX(-1)";e.mozTransform="scaleX(-1)";e.msTransform="scaleX(-1)";e.oTransform="scaleX(-1)";e.transform="scaleX(-1)";e.filter="FlipH";e.msFilter="FlipH"}},unflip:function(){if(this.params.flip_horiz){var e=this.container.style;e.webkitTransform="scaleX(1)";e.mozTransform="scaleX(1)";e.msTransform="scaleX(1)";e.oTransform="scaleX(1)";e.transform="scaleX(1)";e.filter="";e.msFilter=""}},savePreview:function(e,t){var a=this.params;var i=this.preview_canvas;var s=this.preview_context;if(t){var r=t.getContext("2d");r.drawImage(i,0,0)}e(t?null:i.toDataURL("image/"+a.image_format,a.jpeg_quality/100),i,s);if(this.params.unfreeze_snap)this.unfreeze()},snap:function(e,t){if(!e)e=this.params.user_callback;if(!t)t=this.params.user_canvas;var a=this;var s=this.params;if(!this.loaded)return this.dispatch("error",new i("Webcam is not loaded yet"));if(!e)return this.dispatch("error",new i("Please provide a callback function or canvas to snap()"));if(this.preview_active){this.savePreview(e,t);return null}var r=document.createElement("canvas");r.width=this.params.dest_width;r.height=this.params.dest_height;var o=r.getContext("2d");if(this.params.flip_horiz){o.translate(s.dest_width,0);o.scale(-1,1)}var n=function(){if(this.src&&this.width&&this.height){o.drawImage(this,0,0,s.dest_width,s.dest_height)}if(s.crop_width&&s.crop_height){var a=document.createElement("canvas");a.width=s.crop_width;a.height=s.crop_height;var i=a.getContext("2d");i.drawImage(r,Math.floor(s.dest_width/2-s.crop_width/2),Math.floor(s.dest_height/2-s.crop_height/2),s.crop_width,s.crop_height,0,0,s.crop_width,s.crop_height);o=i;r=a}if(t){var n=t.getContext("2d");n.drawImage(r,0,0)}e(t?null:r.toDataURL("image/"+s.image_format,s.jpeg_quality/100),r,o)};if(this.userMedia){o.drawImage(this.video,0,0,this.params.dest_width,this.params.dest_height);n()}else if(this.iOS){var l=document.getElementById(this.container.id+"-ios_div");var h=document.getElementById(this.container.id+"-ios_img");var c=document.getElementById(this.container.id+"-ios_input");iFunc=function(e){n.call(h);h.removeEventListener("load",iFunc);l.style.backgroundImage="none";h.removeAttribute("src");c.value=null};if(!c.value){h.addEventListener("load",iFunc);c.style.display="block";c.focus();c.click();c.style.display="none"}else{iFunc(null)}}else{var d=this.getMovie()._snap();var h=new Image;h.onload=n;h.src="data:image/"+this.params.image_format+";base64,"+d}return null},configure:function(e){if(!e)e="camera";this.getMovie()._configure(e)},flashNotify:function(e,t){switch(e){case"flashLoadComplete":this.loaded=true;this.dispatch("load");break;case"cameraLive":this.live=true;this.dispatch("live");break;case"error":this.dispatch("error",new a(t));break;default:break}},b64ToUint6:function(e){return e>64&&e<91?e-65:e>96&&e<123?e-71:e>47&&e<58?e+4:e===43?62:e===47?63:0},base64DecToArr:function(e,t){var a=e.replace(/[^A-Za-z0-9\+\/]/g,""),i=a.length,s=t?Math.ceil((i*3+1>>2)/t)*t:i*3+1>>2,r=new Uint8Array(s);for(var o,n,l=0,h=0,c=0;c>>(16>>>o&24)&255}l=0}}return r},upload:function(e,t,a){var i=this.params.upload_name||"webcam";var s="";if(e.match(/^data\:image\/(\w+)/))s=RegExp.$1;else throw"Cannot locate image format in Data URI";var r=e.replace(/^data\:image\/\w+\;base64\,/,"");var o=new XMLHttpRequest;o.open("POST",t,true);if(o.upload&&o.upload.addEventListener){o.upload.addEventListener("progress",function(e){if(e.lengthComputable){var t=e.loaded/e.total;Webcam.dispatch("uploadProgress",t,e)}},false)}var n=this;o.onload=function(){if(a)a.apply(n,[o.status,o.responseText,o.statusText]);Webcam.dispatch("uploadComplete",o.status,o.responseText,o.statusText)};var l=new Blob([this.base64DecToArr(r)],{type:"image/"+s});var h=new FormData;h.append(i,l,i+"."+s.replace(/e/,""));o.send(h)}};Webcam.init();if(typeof define==="function"&&define.amd){define(function(){return Webcam})}else if(typeof module==="object"&&module.exports){module.exports=Webcam}else{e.Webcam=Webcam}})(window); -------------------------------------------------------------------------------- /templates/app/commit.html: -------------------------------------------------------------------------------- 1 | {% extends 'base/base.html' %} 2 | {% load static %} 3 | 4 | {% block content %} 5 | 6 |
7 |

请填写供需信息

8 |
10 | {% csrf_token %} 11 |
12 | 13 | 14 |
15 |
16 | 17 | 26 |
27 |
28 | 29 | 39 |
40 |
41 | 42 | 43 |
44 |
45 | 46 | 47 |
48 |
49 | 50 | 51 |
52 |
53 | 54 | 55 |
56 | 57 | 58 | {% include "base/form_errors.html" %} 59 | {% include "base/form_messages.html" %} 60 |
61 |
62 | 63 | {% endblock content %} 64 | 65 | {% block javascript %} 66 | 73 | {% endblock javascript %} 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /templates/app/demo.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | WebcamJS Test Page 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 |
19 | 20 | 21 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /templates/app/detail.html: -------------------------------------------------------------------------------- 1 | {% extends 'base/base.html' %} 2 | {% load static %} 3 | {% load app_tag %} 4 | 5 | {% block content %} 6 |
7 |
8 | {% endblock content %} 9 | -------------------------------------------------------------------------------- /templates/app/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base/base.html' %} 2 | {% load static %} 3 | 4 | {% block content %} 5 | 6 |
7 | 8 |
9 | 全部 10 | 求购 11 | 供应 12 |
13 | 14 |
15 | {% for item in product_list %} 16 |
17 |
18 | 查看 19 |
20 | 21 |
22 | {{item.title}} 23 |
24 |
25 | {% empty %} 26 |

暂无数据

27 | {% endfor %} 28 |
29 | {% include "base/page_nav.html" %} 30 |
31 | {% endblock content %} 32 | 33 | -------------------------------------------------------------------------------- /templates/app/search.html: -------------------------------------------------------------------------------- 1 | {% extends 'base/base.html' %} 2 | {% load static %} 3 | 4 | {% block content %} 5 | 6 |
7 |
8 | 首页 9 | 提交链接 10 |
11 |
12 |
13 | 14 | 15 | 17 | 18 |
19 |
20 |
21 | 时间 22 | 热度 23 | 大小 24 |
25 |
26 |
27 |
28 | 大约{{record_count}}条结果,耗时 {{duration}} 秒。 29 |
30 |
31 |
32 | 33 | {% for item in link_list %} 34 |
35 |
36 |

37 | 38 | {{item.title}} 39 | 40 |

41 |
42 |
43 | {{item.desc}} 44 |
45 |
46 | 视频 47 | 创建时间: {{item.timestamp}} 48 | {{item.size}} 49 | 视频热度:{{item.hot}} 50 |
51 |
52 | {% empty %} 53 |

暂无搜索结果

54 | {% endfor %} 55 | 56 | 57 | {% if is_paginated %} 58 |
    59 | {% if page_obj.has_previous %} 60 |
  • « 61 |
  • 62 | {% endif %} 63 | {% for i in page_list %} 64 | {% if page_obj.number == i %} 65 |
  • {{ i }}
  • 66 | {% else %} 67 |
  • {{ i }}
  • 68 | {% endif %} 69 | {% endfor %} 70 | {% if page_obj.has_next %} 71 |
  • » 73 |
  • 74 | {% endif %} 75 |
76 | {% endif %} 77 | 78 |
79 | 80 |
81 |
82 |
83 | 本站主要用于演示软件项目,不以盈利为目的. 本站没有储存任何数据,亦不对结果承担任何责任!本站已经屏蔽了99%的非法链接,如发现非法,侵权的内容请在线举报,谢谢合作!
客服邮箱:net936@163.com 84 |
85 | 88 |
89 |
90 |
91 |
92 |
93 | {% endblock content %} 94 | -------------------------------------------------------------------------------- /templates/base/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | 二手商品交易平台 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {% block css %}{% endblock css %} 16 | 17 | 19 | 20 | 21 | 22 | 23 | {% include "base/header.html" %} 24 |
25 | {% block content %} 26 | {% endblock content %} 27 |
28 | {% include "base/footer.html" %} 29 | 30 | 31 | 32 | 34 | 35 | {% block javascript %} 36 | {% endblock javascript %} 37 | 38 | {% block modal %} 39 | {% endblock modal %} 40 | 41 | 42 | -------------------------------------------------------------------------------- /templates/base/footer.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | -------------------------------------------------------------------------------- /templates/base/form_errors.html: -------------------------------------------------------------------------------- 1 | 2 | {% if form.errors %} 3 |
4 |
    5 | 6 | {% for field in form %} 7 | {% for error in field.errors %} 8 |
  • {{ error|escape }}
  • 9 | {% endfor %} 10 | {% endfor %} 11 | {% for error in form.non_field_errors %} 12 |
  • {{ error|escape }}
  • 13 | {% endfor %} 14 |
15 |
16 | 17 | {% endif %} -------------------------------------------------------------------------------- /templates/base/form_messages.html: -------------------------------------------------------------------------------- 1 | {% if messages %} 2 |
3 | {% for message in messages %} 4 |
{{ message }}
5 | {% endfor %} 6 |
7 | {% endif %} -------------------------------------------------------------------------------- /templates/base/header.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | -------------------------------------------------------------------------------- /templates/base/page_nav.html: -------------------------------------------------------------------------------- 1 | {% if is_paginated %} 2 |
3 |
4 | {% if page_obj.has_previous %} 5 | < 6 | {% endif %} 7 | {% for i in page_list %} 8 | {% if page_obj.number == i %} 9 | {{ i }} 10 | {% else %} 11 | {{ i }} 12 | {% endif %} 13 | {% endfor %} 14 | {% if page_obj.has_next %} 15 | > 16 | {% endif %} 17 |
18 |
19 | {% endif %} -------------------------------------------------------------------------------- /开发过程.md: -------------------------------------------------------------------------------- 1 | ## 项目开发过程 2 | 3 | ### 项目简介 4 | 该项目是基于python的web类库django开发的一套web网站,做为一个公益项目。 5 | 6 | ### 启动项目 7 | ``` 8 | django-admin startproject mask 9 | ``` 10 | ### 创建应用 11 | ``` 12 | python3 manage.py startapp app 13 | ``` 14 | 15 | ### model设计 16 | 主要是对需求表Product进行设计,在此项目中,我们需要标题、联系人、电话等字段。可参考models.py文件。 17 | 18 | 设计字段如下: 19 | ```python 20 | class Product(models.Model): 21 | list_display = ("title", "type", "location") 22 | title = models.CharField(max_length=100,blank=True, null=True) 23 | type = models.IntegerField(default=0) 24 | pv = models.IntegerField(default=0) 25 | contact = models.CharField(max_length=10,blank=True, null=True) 26 | location = models.CharField(max_length=20,blank=True, null=True) 27 | phone = models.CharField(max_length=13, blank=True, null=True) 28 | weixin = models.CharField(max_length=50, blank=True, null=True) 29 | status = models.BooleanField(default=False) 30 | timestamp = models.DateTimeField(auto_now_add=True, null=True) 31 | expire = models.IntegerField(default=1) 32 | ``` 33 | 34 | ### 业务编写 35 | 36 | 本项目一共分为3个页面,分别是列表页、详情页、提交页。 37 | 38 | 我们一一讲解 39 | 40 | #### 首页 41 | 42 | 首先是首页,它的模版位于templates/app/index.html 它主要是用来展示首页内容, 并提交搜索词,到搜索接口,所有的接口都位于app/urls.py里面,如下 43 | ```python 44 | app_name = 'app' 45 | urlpatterns = [ 46 | path('index', views.IndexView.as_view(), name='index'), 47 | path('detail/', views.DetailView.as_view(), name='detail'), 48 | path('commit', views.CommitView.as_view(), name='commit') 49 | ] 50 | ``` 51 | 52 | 我们设置首页的路由为IndexView, 开始编写IndexView的代码。它的代码非常简单: 53 | ```python 54 | 55 | class IndexView(generic.ListView): 56 | model = Product 57 | template_name = 'app/index.html' 58 | context_object_name = 'product_list' 59 | paginate_by = 15 60 | c = None 61 | 62 | def get_context_data(self, *, object_list=None, **kwargs): 63 | context = super(IndexView, self).get_context_data(**kwargs) 64 | paginator = context.get('paginator') 65 | page = context.get('page_obj') 66 | page_list = get_page_list(paginator, page) 67 | context['c'] = self.c 68 | context['page_list'] = page_list 69 | return context 70 | 71 | def get_queryset(self): 72 | self.c = self.request.GET.get("c", None) 73 | if self.c: 74 | return Product.objects.filter(type=self.c).order_by('-timestamp') 75 | else: 76 | return Product.objects.filter(status=0).order_by('-timestamp') 77 | 78 | ``` 79 | 80 | 81 | #### 详情页 82 | 83 | 我们再来开发详情页,从urls.py中看到,详情页是由DetailView来实现的,我们来窥探它的全貌: 84 | ```python 85 | 86 | class DetailView(generic.DetailView): 87 | model = Product 88 | template_name = 'app/detail.html' 89 | 90 | def get_object(self, queryset=None): 91 | obj = super().get_object() 92 | return obj 93 | 94 | def get_context_data(self, **kwargs): 95 | context = super(DetailView, self).get_context_data(**kwargs) 96 | return context 97 | ``` 98 | 它很简单,继承了DetailView通用模板类来显示详情。 99 | 100 | #### 提交页 101 | 102 | 最后再来看一下提交页,它是由CommitView来实现的。同样是观看代码: 103 | ```python 104 | class CommitView(generic.CreateView): 105 | 106 | model = Product 107 | form_class = CommitForm 108 | template_name = 'app/commit.html' 109 | 110 | @ratelimit(key='ip', rate='2/m') 111 | def post(self, request, *args, **kwargs): 112 | was_limited = getattr(request, 'limited', False) 113 | if was_limited: 114 | messages.warning(self.request, "操作太频繁了,请1分钟后再试") 115 | return render(request, 'app/commit.html', {'form': CommitForm()}) 116 | return super().post(request, *args, **kwargs) 117 | 118 | def get_success_url(self): 119 | messages.success(self.request, "发布成功! ") 120 | return reverse('app:commit') 121 | ``` 122 | 它是继承自CreateView,因为是创建操作嘛,在post中,我们通过ratelimit来限制提交次数,防止恶意提交。 123 | 124 | ### 运行项目 125 | ``` 126 | python3 manage.py runserver 127 | ``` 128 | 129 | --------------------------------------------------------------------------------