diff --git a/app/controllers/users/project_packages_controller.rb b/app/controllers/users/project_packages_controller.rb
new file mode 100644
index 000000000..edd6bd29b
--- /dev/null
+++ b/app/controllers/users/project_packages_controller.rb
@@ -0,0 +1,17 @@
+class Users::ProjectPackagesController < Users::BaseController
+
+  def index
+    packages = Users::ProjectPackageService.call(observed_user, query_params)
+
+    @count = packages.count
+    @packages = paginate(packages.includes(:project_package_category))
+
+    bidding_users = BiddingUser.where(project_package_id: @packages.map(&:id), user_id: observed_user.id)
+    bidding_users = bidding_users.group(:project_package_id).select(:project_package_id, :status)
+    @bidding_status_map = bidding_users.each_with_object({}) { |u, h| h[u.project_package_id] = u.status }
+  end
+
+  def query_params
+    params.permit(:category, :status, :sort_by, :sort_direction)
+  end
+end
\ No newline at end of file
diff --git a/app/models/project_package.rb b/app/models/project_package.rb
index fc541097a..219f60ca4 100644
--- a/app/models/project_package.rb
+++ b/app/models/project_package.rb
@@ -13,6 +13,9 @@ class ProjectPackage < ApplicationRecord
 
   has_many :attachments, as: :container, dependent: :destroy
 
+  scope :visible, -> { where(status: %i[published bidding_ended bidding_finished]) }
+  scope :invisible, -> { where(status: %i[pending applying refused]) }
+
   aasm(:status) do
     state :pending, initiali: true
     state :applying
diff --git a/app/models/user.rb b/app/models/user.rb
index 73036c73e..03c97b9f3 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -123,6 +123,11 @@ class User < ApplicationRecord
   has_many :user_interests, dependent: :delete_all
   has_many :interests, through: :user_interests, source: :repertoire
 
+  # 众包
+  has_many :project_packages, foreign_key: :creator_id, dependent: :destroy
+  has_many :bidding_users, dependent: :destroy
+  has_many :bidden_project_packages, through: :bidding_users, source: :project_package
+
   # Groups and active users
   scope :active, lambda { where(status: STATUS_ACTIVE) }
 
@@ -572,6 +577,10 @@ class User < ApplicationRecord
     Attendance.find_by(user_id: id)&.next_gold || 60  # 基础50,连续签到+10
   end
 
+  def admin_or_business?
+    admin? || business?
+  end
+
   protected
   def validate_password_length
     # 管理员的初始密码是5位
diff --git a/app/services/users/project_package_service.rb b/app/services/users/project_package_service.rb
new file mode 100644
index 000000000..870cdc98e
--- /dev/null
+++ b/app/services/users/project_package_service.rb
@@ -0,0 +1,76 @@
+class Users::ProjectPackageService < ApplicationService
+  include CustomSortable
+
+  sort_columns :published_at, default_by: :published_at, default_direction: :desc
+
+  attr_reader :user, :params
+
+  def initialize(user, params)
+    @user   = user
+    @params = params
+  end
+
+  def call
+    packages = category_scope_filter
+
+    packages = user_policy_filter(packages)
+
+    custom_sort(packages, :published_at, params[:sort_direction])
+  end
+
+  private
+
+  def category_scope_filter
+    case params[:category]
+    when 'bidden' then
+      user.bidden_project_packages
+    when 'manage' then
+      user.project_packages
+    else
+      ids = user.bidding_users.pluck(:project_package_id) + user.project_packages.pluck(:id)
+      ProjectPackage.where(id: ids)
+    end
+  end
+
+  def user_policy_filter(relations)
+    if self_or_admin?
+      status_filter(relations)
+    else
+      relations.visible
+    end
+  end
+
+  def status_filter(relations)
+    return relations unless self_or_admin?
+
+    case params[:category]
+    when 'bidden' then bidding_status_filter(relations)
+    when 'manage' then package_status_filter(relations)
+    else relations
+    end
+  end
+
+  def bidding_status_filter(relations)
+    case params[:status]
+    when 'bidding_lost' then
+      relations.where(bidding_users: { status: :bidding_lost })
+    when 'bidding_won' then
+      relations.where(bidding_users: { status: :bidding_won })
+    else
+      relations
+    end
+  end
+
+  def package_status_filter(relations)
+    case params[:status]
+    when 'unpublished' then relations.invisible
+    when 'bidding'     then relations.where(status: :published)
+    when 'finished'    then relations.where(status: %w[bidding_ended bidding_finished])
+    else relations
+    end
+  end
+
+  def self_or_admin?
+    User.current&.id == user.id || User.current&.admin_or_business?
+  end
+end
\ No newline at end of file
diff --git a/app/views/users/project_packages/index.json.jbuilder b/app/views/users/project_packages/index.json.jbuilder
new file mode 100644
index 000000000..a2574d558
--- /dev/null
+++ b/app/views/users/project_packages/index.json.jbuilder
@@ -0,0 +1,20 @@
+user = observed_user
+
+json.count @count
+json.project_packages do
+  json.array! @packages.each do |package|
+    json.extract! package, :id, :title, :status, :min_price, :max_price, :visit_count, :bidding_users_count
+
+    is_creator = user.id == package.creator_id
+    json.type is_creator ? 'manage' : 'bidden'
+    json.category_id package.project_package_category_id
+    json.category_name package.category_name
+
+    unless is_creator
+      json.bidden_status @bidding_status_map[package.id]
+    end
+
+    json.deadline_at package.display_deadline_at
+    json.published_at package.display_published_at
+  end
+end
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 16140e99c..bb5bc49cc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -50,6 +50,7 @@ Rails.application.routes.draw do
         resource :experience_records, only: [:show]
         resource :grade_records, only: [:show]
         resource :watch, only: [:create, :destroy]
+        resources :project_packages, only: [:index]
       end
 
 
diff --git a/db/migrate/20190724013024_modify_final_score_for_games.rb b/db/migrate/20190724013024_modify_final_score_for_games.rb
new file mode 100644
index 000000000..e926cccd6
--- /dev/null
+++ b/db/migrate/20190724013024_modify_final_score_for_games.rb
@@ -0,0 +1,15 @@
+class ModifyFinalScoreForGames < ActiveRecord::Migration[5.2]
+  def change
+    grades = Grade.where(container_type: "Answer")
+    grades.each do |grade|
+      g = Game.find_by_id(grade.container_id)
+      if g.present?
+        if g.status == 2 && g.answer_open > 0 && g.final_score <= 0 && g.end_time < grade.created_at
+          g.update_column(:final_score, g.challenge.score)
+        elsif g.final_score < 0
+          g.update_column(:final_score, 0)
+        end
+      end
+    end
+  end
+end
diff --git a/public/react/config/webpack.config.prod.js b/public/react/config/webpack.config.prod.js
index 7b9795e80..0abd707af 100644
--- a/public/react/config/webpack.config.prod.js
+++ b/public/react/config/webpack.config.prod.js
@@ -301,8 +301,8 @@ module.exports = {
         },
         warnings: false,
         compress: {
-          drop_debugger: true,
-          drop_console: true
+          drop_debugger: false,
+          drop_console: false
         }
       }
     }),
diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js
index 003ef5a9b..02d8c2be5 100644
--- a/public/react/src/AppConfig.js
+++ b/public/react/src/AppConfig.js
@@ -2,7 +2,7 @@ import React from "react";
 
 import axios from 'axios';
 import { requestProxy } from "./indexEduplus2RequestProxy";
-import { broadcastChannelOnmessage ,SetAppModel, isDev, queryString} from 'educoder';
+import { broadcastChannelOnmessage ,SetAppModel} from 'educoder';
 import {  notification } from 'antd';
 import './index.css'
 broadcastChannelOnmessage('refreshPage', () => {
@@ -18,19 +18,10 @@ function locationurl(list){
 }
 
 // TODO 开发期多个身份切换
-let debugType = ""
-if (isDev) {
-  	const _search = window.location.search;
-    let parsed = {};
-    if (_search) {
-      parsed = queryString.parse(_search);
-  	}
-    debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' :
-        window.location.search.indexOf('debug=s') != -1 ? 'student' : 
-        window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || ''
-}
-	
-window._debugType = debugType;
+const debugType =""
+// 	window.location.search.indexOf('debug=t') != -1 ? 'teacher' :
+//         window.location.search.indexOf('debug=s') != -1 ? 'student' : 'admin'
+// window._debugType = debugType;
 export function initAxiosInterceptors(props) {
 
     // TODO 避免重复的请求 https://github.com/axios/axios#cancellation
@@ -121,7 +112,7 @@ export function initAxiosInterceptors(props) {
         // https://github.com/axios/axios/issues/583
             // message.info(response.data.message || '服务端返回status -1,请联系管理员。');
             // props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' )
-            if (window.location.pathname.startsWith('/tasks/')) {    
+            if (window.location.pathname.startsWith('/tasks/')) {
                 props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' )
             } else {
                 notification.open({
@@ -136,7 +127,7 @@ export function initAxiosInterceptors(props) {
                 //   description: response.data.message || '服务器异常,请联系管理员。',
                 // });
             }
-            
+
             throw new axios.Cancel('Operation canceled by the user.');
         }
         // if(response.data.status === 401){
diff --git a/public/react/src/modules/courses/coursesPublic/Addcourses.js b/public/react/src/modules/courses/coursesPublic/Addcourses.js
index e8bd8b9cf..922c68650 100644
--- a/public/react/src/modules/courses/coursesPublic/Addcourses.js
+++ b/public/react/src/modules/courses/coursesPublic/Addcourses.js
@@ -147,6 +147,8 @@ class Addcourses extends Component{
 
 		if(Addcoursestype===true){
 			this.props.hideAddcoursestype();
+		}else{
+			window.location.href = "/";
 		}
 
   }
diff --git a/public/react/src/modules/courses/new/CoursesNew.js b/public/react/src/modules/courses/new/CoursesNew.js
index c5d0009c1..1183b59e9 100644
--- a/public/react/src/modules/courses/new/CoursesNew.js
+++ b/public/react/src/modules/courses/new/CoursesNew.js
@@ -88,11 +88,11 @@ class CoursesNew extends Component {
 
     }
 		componentDidUpdate(prevProps){
-			if(prevProps.current_user!=this.props.current_user){
-				if(this.props.current_user.user_identity==="学生"){
-					window.location.href ="/403"
-				}
-			}
+			// if(prevProps.current_user!=this.props.current_user){
+			// 	if(this.props.current_user.user_identity==="学生"){
+			// 		window.location.href ="/403"
+			// 	}
+			// }
 		}
     onChangeTimepublishs = (date, dateString) => {
         if(dateString===""){
@@ -132,7 +132,7 @@ class CoursesNew extends Component {
 
         e.preventDefault();
         let coursesId = this.props.match.params.coursesId;
-        let {is_public} = this.state
+        let {is_public,datatime} = this.state
         // console.log(is_public)
 
         if (coursesId != undefined) {
@@ -173,7 +173,7 @@ class CoursesNew extends Component {
 
 
                     // console.log('Received values of form: ', values);
-                    let {datatime} = this.state;
+
                     let url = "/courses/" + coursesId + ".json";
                     axios.put(url, {
                             course_list_name: values.course,
@@ -227,7 +227,7 @@ class CoursesNew extends Component {
                     // debugger
                     //新建
                     // console.log('Received values of form: ', values);
-                    let {datatime} = this.state;
+
                     let url = "/courses.json";
                     axios.post(url, {
                             course_list_name: values.course,
diff --git a/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js b/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js
index 5f41cdefb..61ed59d7b 100644
--- a/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js
+++ b/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js
@@ -382,7 +382,7 @@ class ShixunhomeWorkItem extends Component{
               实训详情
 								{this.props.isAdminOrCreator()?this.editname(discussMessage.name,discussMessage.homework_id)} className={"btn colorblue ml20 font-16"}>重命名:""}
               {/*