소스 검색

Merge branch 'dev2.6.4' of http://39.105.157.10:10080/qmx/qfw into dev2.6.4

wcj 5 년 전
부모
커밋
69b198cf1f
36개의 변경된 파일6332개의 추가작업 그리고 69개의 파일을 삭제
  1. 2 0
      common/src/qfw/util/image/imageutil.go
  2. 5 5
      core/src/config.json
  3. 28 0
      core/src/discountPlan.json
  4. 15 0
      core/src/qfw/coreconfig/DiscountPlan.go
  5. 1 0
      core/src/qfw/coreconfig/coreconfig.go
  6. 1 1
      core/src/qfw/filemanage/uploadfile.go
  7. 476 0
      core/src/qfw/manage/course.go
  8. 169 0
      core/src/qfw/manage/entnicheOrder.go
  9. 117 59
      core/src/qfw/manage/vipOrder.go
  10. 1 1
      core/src/timetask.json
  11. 408 0
      core/src/web/staticres/course/css/course_detail.css
  12. 75 0
      core/src/web/staticres/course/css/reset_pc.css
  13. 125 0
      core/src/web/staticres/course/css/wx_base.css
  14. 506 0
      core/src/web/staticres/course/css/wx_course_detail.css
  15. 3 0
      core/src/web/staticres/course/iconfont/iconfont.css
  16. 3 0
      core/src/web/staticres/course/iconfont/wx_iconfont.css
  17. BIN
      core/src/web/staticres/course/image/more.png
  18. 417 0
      core/src/web/staticres/course/js/common.js
  19. 216 0
      core/src/web/staticres/course/js/course_detail.js
  20. 3 0
      core/src/web/staticres/course/js/jquery.js
  21. 18 0
      core/src/web/staticres/course/js/rem.js
  22. 8 1
      core/src/web/staticres/css/unicorn.main.css
  23. BIN
      core/src/web/staticres/images/crouse-icon.png
  24. 1189 0
      core/src/web/staticres/js/bootbox.js
  25. 32 0
      core/src/web/staticres/js/kindeditor/themes/course/iframe_course.css
  26. BIN
      core/src/web/staticres/upload/2019/12/29/20191229172913012213dsp1H.jpg
  27. BIN
      core/src/web/staticres/upload/2019/12/29/201912291729380122852891x.png
  28. 412 0
      core/src/web/templates/manage/course/content.html
  29. 336 0
      core/src/web/templates/manage/course/index.html
  30. 345 0
      core/src/web/templates/manage/course/order_detail.html
  31. 358 0
      core/src/web/templates/manage/course/order_index.html
  32. 382 0
      core/src/web/templates/manage/course/preview/course_detail_mobile.html
  33. 217 0
      core/src/web/templates/manage/course/preview/course_detail_pc.html
  34. 234 0
      core/src/web/templates/manage/entniche_order/entorder.html
  35. 225 0
      core/src/web/templates/manage/entniche_order/entorderdetail.html
  36. 5 2
      core/src/web/templates/manage/slider.html

+ 2 - 0
common/src/qfw/util/image/imageutil.go

@@ -96,6 +96,8 @@ func MakeResize(path string, newX, newY, quality int, t int) (newName string, er
 		switch strings.ToLower(onames[1]) {
 		case "jpg":
 			err = jpeg.Encode(newF, i128, &jpeg.Options{quality})
+		case "jpeg":
+			err = jpeg.Encode(newF, i128, &jpeg.Options{quality})
 		case "png":
 			err = png.Encode(newF, i128)
 		}

+ 5 - 5
core/src/config.json

@@ -1,10 +1,10 @@
 {
     "webServerPort": "8089",
-    "redisServers": "enterprise=192.168.3.18:3379,service=192.168.3.18:3379,other=192.168.3.18:3379,sso=192.168.3.18:3379,credit=192.168.3.18:3379,session=192.168.3.18:3379",
+    "redisServers": "enterprise=192.168.3.128:1712,service=192.168.3.128:1712,other=192.168.3.128:1712,sso=192.168.3.128:1712,credit=192.168.3.128:1712,session=192.168.3.128:1712",
     "useRedis": false,
-    "mongodbServers": "192.168.3.18:27080",	
-    "elasticsearch": "http://192.168.3.18:9800",
-    "jyescsearch": "http://192.168.3.18:9800",
+    "mongodbServers": "192.168.3.128:27080",	
+    "elasticsearch": "http://192.168.3.128:9800",
+    "jyescsearch": "http://192.168.3.128:9800",
     "elasticPoolSize": 30,
     "mongodbPoolSize": 5,
     "mongodbName": "qfw",
@@ -79,7 +79,7 @@
     },
 	"mysql":{
 		"dbName":   "jianyu",
-		"address":  "192.168.3.207:3366",
+		"address":  "192.168.3.11:3366",
 		"userName": "root",
 		"passWord": "Topnet123"
 	},

+ 28 - 0
core/src/discountPlan.json

@@ -0,0 +1,28 @@
+{
+    "招标管理课程": [
+        {
+            "title": "每单立减",
+            "remarks": "限时下单立减100元",
+            "content": "2020年1月16日-2020年5月1日期间购买任意课程,每单立减100元现金。",
+            "price": 100
+        }
+    ],
+    "投标实务课程": [
+        {
+            "title": "每单立减",
+            "remarks": "限时下单立减100元",
+            "content": "2020年1月16日-2020年5月1日期间购买任意课程,每单立减100元现金。",
+            "price": 100
+        },
+        {
+            "title": "多人立减",
+            "remarks": "多人成团最高可打8折优惠",
+            "content": "4人成团,9折现金立减;8人成团,8折现金立减",
+            "price": 100,
+            "discount": {
+                "4": 9,
+                "8": 8
+            }
+        }
+    ]
+}

+ 15 - 0
core/src/qfw/coreconfig/DiscountPlan.go

@@ -0,0 +1,15 @@
+/**
+*初始化课程优惠信息
+**/
+package coreconfig
+
+import (
+	"qfw/util"
+)
+
+//
+var DiscountConfig map[string]interface{}
+
+func readDiscountConfig() {
+	util.ReadConfig("./discountPlan.json", &DiscountConfig)
+}

+ 1 - 0
core/src/qfw/coreconfig/coreconfig.go

@@ -13,4 +13,5 @@ func init() {
 	readredPackage()
 	readluckDraw()
 	readflop()
+	readDiscountConfig()
 }

+ 1 - 1
core/src/qfw/filemanage/uploadfile.go

@@ -28,7 +28,7 @@ func (m *Files) Upload() error {
 	res["msg"] = "上传失败"
 	if m.Method() == "POST" {
 		filetype := m.GetString("type")
-		if filetype == "cauditupload" {
+		if filetype == "cauditupload" || filetype == "courseFile" {
 			fileTypeArray = []string{"gif", "jpg", "jpeg", "png"}
 		}
 		if len(filetype) == 0 {

+ 476 - 0
core/src/qfw/manage/course.go

@@ -0,0 +1,476 @@
+package manage
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"qfw/coreconfig"
+	cutil "qfw/coreutil"
+	qutil "qfw/util"
+	"qfw/util/mongodb"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/go-xweb/log"
+	"github.com/go-xweb/xweb"
+	"github.com/pkg/errors"
+	"gopkg.in/mgo.v2/bson"
+)
+
+//招投标课程相关接口
+type CourseManage struct {
+	*xweb.Action
+	index          xweb.Mapper `xweb:"/manage/course/index"`                 //课程首页
+	list           xweb.Mapper `xweb:"/manage/course/list"`                  //请求课程列表
+	createPage     xweb.Mapper `xweb:"/manage/course/page/(\\w+)/(\\w+)"`    //课程三级页
+	createApi      xweb.Mapper `xweb:"/manage/course/doRequest"`             //课程三级页接口
+	changeStatus   xweb.Mapper `xweb:"/manage/course/changeStatus"`          //上线or下线
+	preview        xweb.Mapper `xweb:"/manage/course/preview/(\\w+)/(\\w+)"` //课程预览
+	previewGetDate xweb.Mapper `xweb:"/manage/course/previewGetDate"`        //课程预览
+	//课程订单
+	orderIndex  xweb.Mapper `xweb:"/manage/courseOrder/index"`         //课程订单列表
+	orderDetail xweb.Mapper `xweb:"/manage/courseOrder/detail/(\\w+)"` //课程订单详情
+	orderList   xweb.Mapper `xweb:"/manage/courseOrder/list"`          //请求课程订单列表
+	getDetail   xweb.Mapper `xweb:"/manage/courseOrder/getDetail"`     //请求课程订单详情
+}
+
+type FuncResult struct {
+	Success bool  //是否成功
+	Err     error //错误
+	Data    map[string]interface{}
+}
+
+func (f *FuncResult) Format() *map[string]interface{} {
+	errStr := ""
+	if f.Err != nil {
+		errStr = f.Err.Error()
+	}
+	return &map[string]interface{}{
+		"success": f.Success,
+		"errMsg":  errStr,
+		"data":    f.Data,
+	}
+}
+func init() {
+	xweb.AddAction(&CourseManage{})
+}
+
+func (this *CourseManage) Preview(flag string, id string) {
+	this.T["id"] = id
+	if flag == "mobile" {
+		this.Render("/manage/course/preview/course_detail_mobile.html")
+	} else {
+		this.Render("/manage/course/preview/course_detail_pc.html")
+	}
+}
+func (this *CourseManage) PreviewGetDate() {
+	_id := this.GetString("_id")             //课程id
+	showAbout := this.GetString("aboutFlag") //是否需要相关课程
+	r := func() *FuncResult {
+		if _id == "" {
+			return &FuncResult{false, errors.New("信息id为空"), nil}
+		}
+		//课程基本信息
+		rData := mongodb.FindById("jy_course", _id, `{"i_type":1,"s_address":1,"i_status":1,"s_name":1,"i_price":1,"l_starttime":1,"l_endtime":1,"s_content":1,"s_discountPlan":1,"_id":1}`)
+		if rData == nil || len(*rData) == 0 {
+			return &FuncResult{false, errors.New("未找到此课程的信息"), nil}
+		}
+		resultMap := map[string]interface{}{}
+		(*rData)["l_starttime"] = time.Unix(qutil.Int64All((*rData)["l_starttime"]), 0).Format("2006-01-02 15:04")
+		(*rData)["l_endtime"] = time.Unix(qutil.Int64All((*rData)["l_endtime"]), 0).Format(qutil.Date_Short_Layout)
+		resultMap["detail"] = rData
+		i_type := qutil.IntAll((*rData)["i_type"])
+
+		if showAbout != "" {
+			//相关课程信息
+			s_name := (*rData)["s_name"]
+			queryAbout := bson.M{"i_type": i_type, "s_name": s_name, "i_status": bson.M{"$in": []int{1, -1}}, "_id": bson.M{"$ne": bson.ObjectIdHex(_id)}} //查询已发布or已结束的课程
+			aboutList := mongodb.Find("jy_course", queryAbout, `{"l_publishtime":-1}`,
+				`{"_id":1,"i_type":1,"s_address":1,"i_status":1,"s_name":1,"i_price":1,"l_starttime":1}`, false, 0, 3)
+			for _, v := range *aboutList {
+				v["l_starttime"] = time.Unix(qutil.Int64All(v["l_starttime"]), 0).Format(qutil.Date_Short_Layout)
+				v["l_endtime"] = time.Unix(qutil.Int64All(v["l_endtime"]), 0).Format(qutil.Date_Short_Layout)
+				v["l_publishtime"] = time.Unix(qutil.Int64All(v["l_publishtime"]), 0).Format(qutil.Date_Short_Layout)
+				v["_id"] = qutil.EncodeArticleId2ByCheck(qutil.BsonIdToSId(v["_id"]))
+			}
+			resultMap["aboutList"] = aboutList
+		}
+		return &FuncResult{true, nil, resultMap}
+	}()
+	if r.Err != nil {
+		log.Printf(" CourseContent err:%v\n", r.Err.Error())
+	}
+	this.ServeJson(r.Format())
+}
+
+//
+func (this *CourseManage) GetDetail() error {
+	orderCode := this.GetString("orderCode")
+	if orderCode != "" {
+		dotype := this.GetString("rt")
+		qMap := map[string]interface{}{}
+		qMap["order_code"] = orderCode
+		res := cutil.Mysql.FindOne("dataexport_order", qMap, "", "create_time desc")
+		log.Println("res:", (*res)["filter"])
+		var filter = qutil.ObjToMap((*res)["filter"])
+		if dotype == "1" { //获取订单信息
+			if len(*res) > 0 {
+				resInv := cutil.Mysql.FindOne("apply_invoice", map[string]interface{}{"order_id": (*res)["id"]}, "", "apply_date desc")
+				filter_id := qutil.ObjToString((*res)["filter_id"])
+				if strings.Contains(filter_id, "ABC") {
+					filter_id = qutil.DecodeArticleId2ByCheck(filter_id)[0]
+				}
+				resCour := mongodb.FindById("jy_course", filter_id, nil)
+				this.ServeJson(map[string]interface{}{
+					"res":     res,
+					"resInv":  resInv,
+					"resCour": resCour,
+				})
+			}
+		} else if dotype == "2" { //确认退款
+			nw := time.Now().Unix()
+			(*filter)["adminRefundTime"] = qutil.FormatDateByInt64(&nw, qutil.Date_Full_Layout)
+			datailMsg, _ := json.Marshal(*filter)
+			id := cutil.Mysql.UpdateOrDeleteBySql("UPDATE dataexport_order SET course_status = 6,filter='" + string(datailMsg) + "' WHERE order_code = " + orderCode)
+			this.ServeJson(map[string]interface{}{
+				"id": id,
+			})
+		} else if dotype == "3" { //审核凭证提交
+			nw := time.Now().Unix()
+			agreeN := this.GetString("agreeN")
+			order_status := "0"
+			course_status := "2"
+			if agreeN == "1" { //不通过
+				course_status = "3"
+			} else {
+				course_status = "4"
+				order_status = "1"
+			}
+			(*filter)["adminTransferVTime"] = qutil.FormatDateByInt64(&nw, qutil.Date_Full_Layout)
+			datailMsg, _ := json.Marshal(*filter)
+			updateSql := "UPDATE dataexport_order SET course_status = " + course_status + ",filter_publishtime=" + strconv.FormatInt(nw, 10) + ",order_status=" + order_status
+			updateSql += ",filter = '" + string(datailMsg) + "'"
+			if agreeN == "2" {
+				updateSql += ",pay_time='" + qutil.FormatDateByInt64(&nw, qutil.Date_Full_Layout) + "'"
+			}
+			updateSql += " WHERE order_code = " + orderCode
+			id := cutil.Mysql.UpdateOrDeleteBySql(updateSql)
+			this.ServeJson(map[string]interface{}{
+				"id":       id,
+				"pay_time": qutil.FormatDateByInt64(&nw, qutil.Date_Full_Layout),
+			})
+		}
+	}
+	return nil
+}
+
+//课程订单详情
+func (this *CourseManage) OrderDetail(orderCode string) error {
+	this.T["orderCode"] = orderCode
+	return this.Render("/manage/course/order_detail.html")
+}
+
+//课程订单列表
+func (this *CourseManage) OrderIndex() error {
+	return this.Render("/manage/course/order_index.html")
+}
+
+//课程首页
+func (this *CourseManage) Index() error {
+	return this.Render("/manage/course/index.html")
+}
+
+//请求课程列表
+func (this *CourseManage) OrderList() {
+	currentPage, _ := this.GetInteger("currentPage")
+	perPage, _ := this.GetInteger("perPage")
+
+	c_status := this.GetString("strSel1") //订单状态 0:未支付 1:已支付 -1:已删除 -2:已取消
+	c_type := this.GetString("strSel2")   //请求类型 0:订单编号 1:课程名称 2:联系人(订单表中 user_nickname 暂存联系人信息) 3:联系人手机号
+	c_content := this.GetString("strCont")
+	var sql = ``
+	var c_sql = `SELECT order_status,order_code,pay_time,filter,applybill_status,pay_money,order_money,course_status,pay_way FROM dataexport_order  WHERE  product_type = '招投标课程' and `
+	var c_sql_c = `SELECT count(*) FROM dataexport_order  WHERE product_type = '招投标课程' and `
+	if c_status != "" {
+		sql += `order_status =` + fmt.Sprint(c_status)
+	} else {
+		c_status = "-1"
+		sql += `order_status !=` + fmt.Sprint(c_status)
+	}
+	if c_type == "1" {
+		query := map[string]interface{}{
+			"s_name": c_content,
+		}
+		res := mongodb.Find("jy_course", query, `{"l_publishtime":-1}`, `{"_id":1}`, false, -1, -1)
+		log.Println("res:", *res)
+		var a_id = ""
+		for _, v := range *res {
+			if a_id != "" {
+				a_id += ","
+			}
+			a_id += "'" + qutil.BsonIdToSId(v["_id"]) + "'"
+		}
+		sql += ` and filter_id in (` + a_id + `)`
+	} else if c_type == "0" {
+		sql += ` and order_code ='` + c_content + `'`
+	} else if c_type == "2" {
+		sql += ` and filter like '%"name":"` + c_content + `"%'`
+	} else if c_type == "3" {
+		sql += ` and user_phone ='` + c_content + `'`
+	}
+	c_sql = c_sql + sql
+	c_sql += ` order by create_time desc limit ` + fmt.Sprint((currentPage-1)*perPage) + `,` + fmt.Sprint(perPage)
+	log.Println("sql:", c_sql)
+	rData := cutil.Mysql.SelectBySql(c_sql)
+	if len(*rData) > 0 {
+		for _, v := range *rData {
+			filter := qutil.ObjToMap(v["filter"])
+			v["courseType"] = (*filter)["courseType"]
+		}
+	}
+	c_sql_c = c_sql_c + sql
+	count := cutil.Mysql.CountBySql(c_sql_c)
+	this.ServeJson(map[string]interface{}{
+		"currentPage": currentPage,
+		"data":        rData,
+		"totalRows":   count,
+	})
+}
+
+//请求课程列表
+func (this *CourseManage) List() {
+	currentPage, _ := this.GetInteger("currentPage")
+	perPage, _ := this.GetInteger("perPage")
+
+	c_status := this.GetString("strSel1") //报名状态 1 报名中 2 结束 0未发布
+	c_type := this.GetString("strSel2")   //课程类型 1 招标 2 投标
+	queryStr := this.GetString("query")
+
+	query := map[string]interface{}{}
+	if c_status != "" {
+		query["i_status"] = qutil.IntAll(c_status)
+	}
+	if c_type != "" {
+		query["i_type"] = qutil.IntAll(c_type)
+	}
+	if queryStr != "" {
+		query["s_name"] = bson.M{"$regex": queryStr}
+	}
+	rData := mongodb.Find("jy_course", query, `{"l_publishtime":-1}`, `{"_id":1,"i_type":1,"s_address":1,"i_status":1,"s_name":1,"l_publishtime":1}`, false, (currentPage-1)*perPage, perPage)
+	count := mongodb.Count("jy_course", query)
+	this.ServeJson(map[string]interface{}{
+		"currentPage": currentPage,
+		"data":        rData,
+		"totalRows":   count,
+	})
+
+}
+
+//课程三级页
+func (this *CourseManage) CreatePage(flag, id string) error {
+	if flag == "edit" || flag == "copy" {
+		//获取文章详情
+		if id == "" {
+			return errors.New("请求参数有误")
+		}
+		rData := mongodb.FindById("jy_course", id, "")
+		this.T["type"] = (*rData)["i_type"]
+		this.T["name"] = (*rData)["s_name"]
+		this.T["address"] = (*rData)["s_address"]
+		this.T["price"] = (*rData)["i_price"]
+
+		this.T["publishtime"] = time.Unix(qutil.Int64All((*rData)["l_publishtime"]), 0).Format(qutil.Date_Full_Layout)
+		this.T["starttime"] = time.Unix(qutil.Int64All((*rData)["l_starttime"]), 0).Format(qutil.Date_Full_Layout)
+		this.T["endtime"] = time.Unix(qutil.Int64All((*rData)["l_endtime"]), 0).Format(qutil.Date_Full_Layout)
+		this.T["content"] = (*rData)["s_content"]
+		this.T["status"] = (*rData)["i_status"]
+		this.T["id"] = id
+	}
+	this.T["doType"] = flag
+	this.Render("/manage/course/content.html")
+	return nil
+}
+
+func (this *CourseManage) CreateApi() {
+	c_type, _ := this.GetInteger("c_type") //课程类型
+	name := this.GetString("name")
+	address := this.GetString("address")
+	price, _ := this.GetInt("price")
+	s_starttime := this.GetString("starttime")
+	s_endtime := this.GetString("endtime")
+	s_publishtime := this.GetString("publishtime")
+	d_content := this.GetString("content")
+	Dotype := this.GetString("dotype") //克隆 or 新增 or 修改
+	courseName := "招标管理课程"
+	if c_type == 2 {
+		courseName = "投标实务课程"
+	}
+	log.Println(coreconfig.DiscountConfig)
+	dplan := coreconfig.DiscountConfig
+	var pmap []map[string]interface{}
+	if dplan != nil {
+		pmap = qutil.ObjArrToMapArr(dplan[courseName].([]interface{}))
+	} else {
+		log.Println("添加优惠信息有误")
+	}
+	//	discountPlan := this.GetString("discountPlan")
+	//	err := json.Unmarshal([]byte(discountPlan), &pmap)
+	//	if err != nil {
+	//		log.Println("err:", err)
+	//	}
+	r := func() *FuncResult {
+		//数据校验
+		if name == "" || address == "" || d_content == "" || Dotype == "" || c_type == 0 ||
+			price == 0 || s_publishtime == "" || s_starttime == "" || s_endtime == "" {
+			return &FuncResult{false, errors.New("参数不完整"), nil}
+		}
+		publishtime, err := time.ParseInLocation(qutil.Date_Full_Layout, s_publishtime, time.Local)
+		if err != nil {
+			return &FuncResult{false, errors.New("发布时间异常"), nil}
+		}
+		log.Println("start:", s_starttime)
+		starttime, err := time.ParseInLocation(qutil.Date_Full_Layout, s_starttime, time.Local)
+		if err != nil {
+			return &FuncResult{false, errors.New("课程时间异常"), nil}
+		}
+		log.Println("s_endtime:", s_endtime)
+		endtime, err := time.ParseInLocation(qutil.Date_Full_Layout, s_endtime, time.Local)
+		if err != nil {
+			return &FuncResult{false, errors.New("课程时间异常"), nil}
+		}
+		if endtime.Before(starttime) {
+			return &FuncResult{false, errors.New("时间异常"), nil}
+		}
+		//
+		d1_content, err := url.QueryUnescape(d_content)
+		if err != nil {
+			return &FuncResult{false, errors.New("课程内容解析异常"), nil}
+		}
+		content, err := url.QueryUnescape(d1_content)
+		if err != nil {
+			return &FuncResult{false, errors.New("课程内容解析异常"), nil}
+		}
+		if !(price > 0) {
+			return &FuncResult{false, errors.New("课程金额异常"), nil}
+		}
+		//数据校验
+		mData := map[string]interface{}{
+			"s_name":         name,
+			"i_type":         c_type,
+			"s_address":      address,
+			"i_price":        price,
+			"l_publishtime":  publishtime.Unix(),
+			"l_starttime":    starttime.Unix(),
+			"l_endtime":      endtime.Unix(),
+			"s_content":      content,
+			"s_discountPlan": pmap, //课程优惠内容
+		}
+		if Dotype == "add" || Dotype == "copy" {
+			flag := this.GetString("flag") //保存 or 立即发布
+			if flag == "publish" {
+				mData["i_status"] = 1 //立即发布
+				if time.Now().After(starttime) {
+					return &FuncResult{false, errors.New("开课时间已到,禁止发布"), nil}
+				}
+			} else {
+				mData["i_status"] = 0 //暂时保存
+			}
+			if mongodb.Save("jy_course", mData) == "" {
+				return &FuncResult{false, errors.New("增加课程失败"), nil}
+			} else {
+				return &FuncResult{true, nil, nil}
+			}
+		} else if Dotype == "edit" {
+			id := this.GetString("_id")
+			if id == "" {
+				return &FuncResult{false, errors.New("操作信息id为空"), nil}
+			}
+			updateFlag := mongodb.Update("jy_course", &map[string]interface{}{
+				"_id": qutil.StringTOBsonId(id),
+			}, &map[string]interface{}{
+				"$set": mData,
+			}, false, false)
+			if !updateFlag {
+				return &FuncResult{false, errors.New("修改课程失败"), nil}
+			} else {
+				return &FuncResult{true, nil, nil}
+			}
+		}
+		return &FuncResult{false, errors.New("未知操作"), nil}
+	}()
+	if r.Err != nil {
+		log.Printf("CreateApi err:%v\n", r.Err.Error())
+	}
+	this.ServeJson(r.Format())
+}
+
+func (this *CourseManage) ChangeStatus() {
+	flag := this.GetString("flag")
+	_id := this.GetString("id")
+	r := func() *FuncResult {
+		if !(flag == "off" || flag == "on" || flag == "del") {
+			return &FuncResult{false, errors.New("未知操作"), nil}
+		}
+		if _id == "" {
+			return &FuncResult{false, errors.New("未获取到信息_id"), nil}
+		}
+		rData := mongodb.FindById("jy_course", _id, `"i_status":1,"l_starttime":1`)
+		if rData == nil || len(*rData) == 0 {
+			return &FuncResult{false, errors.New("未知信息_id"), nil}
+		}
+		if (*rData)["i_status"] == -2 {
+			return &FuncResult{false, errors.New("当前信息状态不能更改"), nil}
+		}
+		if flag == "off" { //下线
+			if (*rData)["i_status"] == 1 {
+				ok := mongodb.Update("jy_course", &map[string]interface{}{
+					"_id": qutil.StringTOBsonId(_id),
+				}, &map[string]interface{}{
+					"$set": bson.M{"i_status": -1},
+				}, false, false)
+				//通过课程id查询该课程相关的订单
+				var updateSql = `UPDATE dataexport_order  SET order_status = -2 WHERE order_status = 0 AND product_type = '招投标课程' AND filter_id = '` + _id + `'`
+				go cutil.Mysql.UpdateOrDeleteBySql(updateSql)
+				if ok {
+					return &FuncResult{true, nil, nil}
+				}
+			}
+		} else if flag == "on" { //发布
+			//校验开课时间是否已到
+			if time.Unix(qutil.Int64All((*rData)["l_starttime"]), 0).Before(time.Now()) {
+				return &FuncResult{false, errors.New("开课时间已到,禁止发布"), nil}
+			}
+			if (*rData)["i_status"] == 0 {
+				ok := mongodb.Update("jy_course", &map[string]interface{}{
+					"_id": qutil.StringTOBsonId(_id),
+				}, &map[string]interface{}{
+					"$set": bson.M{"i_status": 1},
+				}, false, false)
+
+				if ok {
+					return &FuncResult{true, nil, nil}
+				}
+			}
+		} else if flag == "del" {
+			status := []int{0, -1} //只能删除已下线或者未发布的
+			ok := mongodb.Update("jy_course", &map[string]interface{}{
+				"_id":      qutil.StringTOBsonId(_id),
+				"i_status": bson.M{"$in": status},
+			}, &map[string]interface{}{
+				"$set": bson.M{"i_status": -2},
+			}, false, false)
+			//通过课程id查询该课程相关的订单
+			var updateSql = `UPDATE dataexport_order  SET order_status = -2 WHERE order_status = 0 AND product_type = '招投标课程' AND filter_id = '` + _id + `'`
+			go cutil.Mysql.UpdateOrDeleteBySql(updateSql)
+			if ok {
+				return &FuncResult{true, nil, nil}
+			}
+		}
+		return &FuncResult{false, errors.New("信息状态修改非法"), nil}
+	}()
+	if r.Err != nil {
+		log.Printf("CreateApi err:%v\n", r.Err.Error())
+	}
+	this.ServeJson(r.Format())
+}

+ 169 - 0
core/src/qfw/manage/entnicheOrder.go

@@ -0,0 +1,169 @@
+package manage
+
+import (
+	"encoding/json"
+	cutil "qfw/coreutil"
+	"qfw/util"
+	"strings"
+
+	"github.com/go-xweb/xweb"
+)
+
+//企业商机管理
+type EntnicheOrder struct {
+	*xweb.Action
+	entOrder             xweb.Mapper `xweb:"/manage/entnicheOrder/list"`
+	entnicheOrderPageing xweb.Mapper `xweb:"/manage/entnicheOrder/p"`
+	entnicheOrderDetail  xweb.Mapper `xweb:"/manage/entnicheOrder/entnicheOrderDetail/(\\w+)"`
+}
+
+func init() {
+	xweb.AddAction(&EntnicheOrder{})
+}
+
+func (e *EntnicheOrder) EntOrder() error {
+	return e.Render("/manage/entniche_order/entorder.html")
+}
+
+func (e *EntnicheOrder) EntnicheOrderPageing() {
+	order_status := e.GetString("strSel1")
+	code := e.GetString("query")
+	currentPage, _ := e.GetInteger("currentPage")
+	perPage, _ := e.GetInteger("perPage")
+
+	qMap := map[string]interface{}{}
+	if code != "" {
+		qMap["order_code"] = code
+	}
+
+	if order_status != "" {
+		if order_status == "0" {
+			qMap["pay_time"] = "$isNull"
+			qMap["order_status"] = "0"
+		} else if order_status == "1" {
+			qMap["pay_time"] = "$isNotNull"
+		} else if order_status == "-2" {
+			qMap["order_status"] = "-2"
+		}
+	}
+
+	qMap["product_type"] = "企业商机管理"
+	res := cutil.Mysql.Find("dataexport_order", qMap, "order_code,pay_time,product_type,order_money,order_status,applybill_status,pay_money,pay_way,user_mail,applybill_company,applybill_type,user_id,vip_type,original_price", "create_time desc", (currentPage-1)*perPage, perPage)
+
+	count := cutil.Mysql.Count("dataexport_order", qMap)
+	for k, v := range *res {
+		v["index"] = k + 1
+		var y, n int64 = 1, 0
+		//申请发票
+		if v["applybill_status"] == y {
+			v["applybill_status"] = "已申请"
+			if v["applybill_type"] == n {
+				v["applybill_company"] = "个人"
+			}
+		} else if v["applybill_status"] == n || v["applybill_status"] == nil {
+			v["applybill_status"] = "未申请"
+			if v["applybill_company"] == nil {
+				v["applybill_company"] = "-"
+			}
+		}
+		//是否支付
+		if v["pay_time"] == nil {
+			if util.IntAll(v["order_status"]) == -2 {
+				v["order_status"] = "已取消"
+			} else {
+				v["order_status"] = "未支付"
+			}
+
+			v["service_status"] = "-"
+			v["applybill_status"] = "-"
+			v["pay_time"] = "-"
+		} else {
+			//删除用户 -1 根据支付金额判断
+			v["order_status"] = "已支付"
+		}
+		if v["vip_type"] == 1 {
+			v["product_type"] = "企业商机管理(续费)"
+		} else {
+			v["product_type"] = "企业商机管理"
+		}
+	}
+	data := map[string]interface{}{
+		"currentPage": currentPage,
+		"data":        res,
+		"totalRows":   count,
+	}
+	e.ServeJson(data)
+}
+
+func (v *EntnicheOrder) EntnicheOrderDetail(order_code string) error {
+	qMap := map[string]interface{}{}
+	var filterMap map[string]interface{}
+	qMap["order_code"] = order_code
+	table := ""
+	res := cutil.Mysql.FindOne("dataexport_order", qMap, "", "create_time desc")
+	if len(*res) > 0 {
+		pay_time := util.ObjToString((*res)["pay_time"])
+		orderMoney := util.Float64All((*res)["order_money"]) / 100
+		order_status := util.IntAll((*res)["order_status"])
+		payway := util.ObjToString((*res)["pay_way"])
+		prepay_id := util.ObjToString((*res)["prepay_id"])
+		//
+		pay_money := util.Float64All((*res)["pay_money"])
+		if pay_money != 0 && prepay_id != "" && pay_time != "" {
+			(*res)["order_status"] = "已支付"
+		} else {
+			if order_status == -2 {
+				(*res)["order_status"] = "已取消"
+			} else if order_status == 0 {
+				(*res)["order_status"] = "未支付"
+			} else if order_status == 1 {
+				(*res)["order_status"] = "已支付"
+			}
+		}
+		(*res)["order_money"] = orderMoney
+		if strings.Contains(payway, "wx") {
+			(*res)["pay_way"] = "微信"
+			table = "weixin_pay"
+		} else if strings.Contains(payway, "ali") {
+			(*res)["pay_way"] = "支付宝"
+			table = "ali_pay"
+		}
+		if prepay_id != "" {
+			wxPayMap := map[string]interface{}{}
+			wxPayMap["out_trade_no"] = (*res)["out_trade_no"]
+			wxpay := cutil.Mysql.FindOne(table, wxPayMap, "", "create_time desc")
+			if wxpay != nil {
+				v.T["transaction_id"] = util.ObjToString((*wxpay)["transaction_id"])
+			}
+		} else {
+			v.T["transaction_id"] = "-"
+			(*res)["pay_time"] = "-"
+		}
+		//申请发票
+		applybill_status := util.IntAll((*res)["applybill_status"])
+		if applybill_status == 1 {
+			(*res)["applybill_status"] = "已申请"
+		} else if applybill_status == 0 {
+			(*res)["applybill_status"] = "未申请"
+		}
+		//0个人 1单位
+		applybill_type := util.IntAll((*res)["applybill_type"])
+		if applybill_type == 1 {
+			(*res)["applybill_type"] = "单位"
+		} else {
+			if order_status == -2 {
+				(*res)["applybill_type"] = "-"
+			} else {
+				(*res)["applybill_type"] = "个人"
+			}
+		}
+		filterData := (*res)["filter"]
+		if err := json.Unmarshal([]byte(filterData.(string)), &filterMap); err == nil {
+
+		}
+	}
+
+	v.T["res"] = *res
+	v.T["filterData"] = filterMap
+	return v.Render("/manage/entniche_order/entorderdetail.html")
+}

+ 117 - 59
core/src/qfw/manage/vipOrder.go

@@ -227,81 +227,93 @@ func (v *VipOrder) VipOrderDetail(order_code string) error {
 			(*res)["product_type"] = "VIP订阅(试用)"
 		}
 
-		//条件 升级订单用户另算
+		//条件 升级/续费订单用户另算		有newbuyset的 都是升级续费逻辑重写后的订单 没有的是老订单
 		subscription_area, industry_str, subscription_cycle, effective_date := "", "", "", ""
 		province_count, city_count := 0, 0
 		filterData := (*res)["filter"]
 		if err := json.Unmarshal([]byte(filterData.(string)), &filterMap); err == nil {
+			newBuyset := *util.ObjToMap((filterMap)["newBuyset"])
 			if util.Int64All((*res)["vip_type"]) != 2 {
-				area := util.ObjToMap(filterMap["area"])
-				subscription_area = SubscriptionArea(*area)
-
-				//行业数量 []string
-				industry := filterMap["industry"].([]interface{})
-				BuyerclassCount := util.If(len(industry) > 0, len(industry), -1).(int)
-				if BuyerclassCount != -1 {
-					industry_str = fmt.Sprintf("%d个行业", BuyerclassCount)
+				if newBuyset != nil {
+					subscription_area, industry_str = newbuysetConversion(newBuyset)
 				} else {
-					industry_str = "全行业"
+					area := util.ObjToMap(filterMap["area"])
+					subscription_area = SubscriptionArea(*area)
+					//行业数量 []string
+					industry := filterMap["industry"].([]interface{})
+					BuyerclassCount := util.If(len(industry) > 0, len(industry), -1).(int)
+					if BuyerclassCount != -1 {
+						industry_str = fmt.Sprintf("%d个行业", BuyerclassCount)
+					} else {
+						industry_str = "全行业"
+					}
 				}
 			} else {
 				//升级
-				addareacount := *util.ObjToMap(filterMap["addareacount"])
-				if len(addareacount) != 0 {
-					province_count = util.IntAll((addareacount)["province"])
-					city_count = util.IntAll((addareacount)["city"])
-					//升级区域显示
-					if city_count != 0 && province_count == 0 {
-						subscription_area = fmt.Sprintf("%d个地市", city_count)
-					} else if city_count == 0 && province_count != 0 {
-						subscription_area = fmt.Sprintf("%d个省级区域", province_count)
-					} else if city_count != 0 && province_count != 0 {
-						subscription_area = fmt.Sprintf("%d个省级区域、%d个地市", province_count, city_count)
-					} else if city_count == 0 && province_count == 0 {
-						subscription_area = "全国"
-					}
+				if newBuyset != nil {
+					subscription_area, industry_str = newbuysetConversion(newBuyset)
 				} else {
-					subscription_area = "无"
-				}
-				//
-				addbuyerclasscount := util.IntAll(filterMap["addbuyerclasscount"])
-				industry_str = fmt.Sprintf("%d个行业", addbuyerclasscount)
-				if addbuyerclasscount == 0 {
-					industry_str = "无"
-				}
-				if addbuyerclasscount == -1 {
-					industry_str = "全行业"
-				}
-			}
-			if util.Int64All((*res)["vip_type"]) == 1 {
-				buyset := util.ObjToMap(filterMap["buyset"])
-				if len(*buyset) != 0 {
-					province_count = util.IntAll((*buyset)["areacount"])
-					citys := util.ObjToMap((*buyset)["citys"])
-					if len(*citys) != 0 {
-						for _, v := range *citys {
-							city_count += util.IntAll(v)
-						}
-					}
-					if city_count == -1 {
-						subscription_area = "全国"
-					} else {
-						if city_count != 0 && province_count != 0 {
-							subscription_area = fmt.Sprintf("%d个省级区域、%d个地市", province_count, city_count)
+					addareacount := *util.ObjToMap(filterMap["addareacount"])
+					if len(addareacount) != 0 {
+						province_count = util.IntAll((addareacount)["province"])
+						city_count = util.IntAll((addareacount)["city"])
+						//升级区域显示
+						if city_count != 0 && province_count == 0 {
+							subscription_area = fmt.Sprintf("%d个地市", city_count)
 						} else if city_count == 0 && province_count != 0 {
 							subscription_area = fmt.Sprintf("%d个省级区域", province_count)
-						} else if city_count != 0 && province_count == 0 {
-							subscription_area = fmt.Sprintf("%d个地市", city_count)
+						} else if city_count != 0 && province_count != 0 {
+							subscription_area = fmt.Sprintf("%d个省级区域、%d个地市", province_count, city_count)
+						} else if city_count == 0 && province_count == 0 {
+							subscription_area = "全国"
 						}
+					} else {
+						subscription_area = "无"
 					}
-					if province_count == -1 {
-						subscription_area = "全国"
+					//
+					addbuyerclasscount := util.IntAll(filterMap["addbuyerclasscount"])
+					industry_str = fmt.Sprintf("%d个行业", addbuyerclasscount)
+					if addbuyerclasscount == 0 {
+						industry_str = "无"
 					}
-					buyerclasscount := util.IntAll((*buyset)["buyerclasscount"])
-					if buyerclasscount == -1 {
+					if addbuyerclasscount == -1 {
 						industry_str = "全行业"
-					} else {
-						industry_str = fmt.Sprintf("%d个行业", buyerclasscount)
+					}
+				}
+			}
+			if util.Int64All((*res)["vip_type"]) == 1 { //续费
+				if newBuyset != nil {
+					subscription_area, industry_str = newbuysetConversion(newBuyset)
+				} else {
+					buyset := util.ObjToMap(filterMap["buyset"])
+					if len(*buyset) != 0 {
+						province_count = util.IntAll((*buyset)["areacount"])
+						citys := util.ObjToMap((*buyset)["citys"])
+						if len(*citys) != 0 {
+							for _, v := range *citys {
+								city_count += util.IntAll(v)
+							}
+						}
+						if city_count == -1 {
+							subscription_area = "全国"
+						} else {
+							if city_count != 0 && province_count != 0 {
+								subscription_area = fmt.Sprintf("%d个省级区域、%d个地市", province_count, city_count)
+							} else if city_count == 0 && province_count != 0 {
+								subscription_area = fmt.Sprintf("%d个省级区域", province_count)
+							} else if city_count != 0 && province_count == 0 {
+								subscription_area = fmt.Sprintf("%d个地市", city_count)
+							}
+						}
+						if province_count == -1 {
+							subscription_area = "全国"
+						}
+						buyerclasscount := util.IntAll((*buyset)["buyerclasscount"])
+						if buyerclasscount == -1 {
+							industry_str = "全行业"
+						} else {
+							industry_str = fmt.Sprintf("%d个行业", buyerclasscount)
+						}
 					}
 				}
 			}
@@ -357,6 +369,10 @@ func (v *VipOrder) VipOrderDetail(order_code string) error {
 					} else if util.IntAll(filterMap["cycleunit"]) == -1 {
 						subscription_cycle = "不延期"
 					}
+					//升级续费后的根据 不延期 cycleunit,cyclecount=0,0
+					if util.IntAll(filterMap["cycleunit"]) == 0 && util.IntAll(filterMap["cyclecount"]) == 0 {
+						subscription_cycle = "不延期"
+					}
 				}
 				if util.ObjToString((*res)["pay_way"]) == "trial" {
 					(filterMap)["subscription_cycle"] = "7天"
@@ -364,6 +380,8 @@ func (v *VipOrder) VipOrderDetail(order_code string) error {
 					(filterMap)["subscription_cycle"] = subscription_cycle
 				}
 				(filterMap)["effective_date"] = effective_date
+			} else {
+
 			}
 		}
 	}
@@ -600,3 +618,43 @@ func isOrderCode(value string) bool {
 	bl, _ := regexp.MatchString(`^(\d+)$`, value)
 	return bl
 }
+
+//
+//升级续费逻辑升级后的 转换
+func newbuysetConversion(newbuyset map[string]interface{}) (subscription_area, industry string) {
+	areacount := util.Int64All(newbuyset["areacount"])
+	newcityscount := len(newbuyset["newcitys"].([]interface{})) //分布
+	if areacount == -1 {
+		subscription_area = "全国"
+	} else {
+		if newcityscount > 0 {
+			cityCount := 0
+			for _, v := range newbuyset["newcitys"].([]interface{}) {
+				cityCount += int(v.(float64))
+			}
+			if newcityscount > 1 { //显示(分布在x个省内)
+				if areacount != 0 {
+					subscription_area = fmt.Sprintf("%d个省、%d个地市(分布在%d个省内)", areacount, cityCount, newcityscount)
+				} else {
+					subscription_area = fmt.Sprintf("%d个地市(分布在%d个省内)", cityCount, newcityscount)
+				}
+			} else {
+				if areacount != 0 {
+					subscription_area = fmt.Sprintf("%d个省、%d个地市", areacount, cityCount)
+				} else {
+					subscription_area = fmt.Sprintf("%d个地市", cityCount)
+				}
+			}
+		} else {
+			subscription_area = fmt.Sprintf("%d个省", areacount)
+		}
+	}
+	//行业
+	buyerclasscount := util.Int64All(newbuyset["buyerclasscount"])
+	if buyerclasscount == -1 {
+		industry = "全行业"
+	} else {
+		industry = fmt.Sprintf("%d个行业", int(newbuyset["buyerclasscount"].(float64)))
+	}
+	return subscription_area, industry
+}

+ 1 - 1
core/src/timetask.json

@@ -1 +1 @@
-{"comment":{"c_rate":720,"commentrate":900},"market":{"demand":{"attr":["i_hits","i_bids","i_status"],"timepoint":"2019-05-14 15:23:49"},"service":{"attr":["i_hits","i_sales","i_comments","i_score","i_appcounts"],"timepoint":"2019-05-14 15:23:49"}},"marketisstart":true,"marketrate":300}
+{"comment":{"c_rate":720,"commentrate":900},"market":{"demand":{"attr":["i_hits","i_bids","i_status"],"timepoint":"2020-01-16 16:17:23"},"service":{"attr":["i_hits","i_sales","i_comments","i_score","i_appcounts"],"timepoint":"2020-01-16 16:17:23"}},"marketisstart":true,"marketrate":300}

+ 408 - 0
core/src/web/staticres/course/css/course_detail.css

@@ -0,0 +1,408 @@
+.buyBthHandle, #course_detail .c_top .handle .buy_btn, #course_detail .c_middle .tabbar .handle .buy_btn {
+  display: inline-block;
+  width: 180px;
+  height: 46px;
+  line-height: 46px;
+  text-align: center;
+  background-color: #2CB7CA;
+  color: #fff;
+  text-decoration: none;
+  border-radius: 6px;
+  margin-right: 16px;
+  border: 1px solid #2CB7CA;
+  font-size: 16px;
+}
+
+.helpBtnHandle, #course_detail .c_top .handle .help_btn, #course_detail .c_middle .tabbar .handle .help_btn {
+  display: inline-block;
+  width: 132px;
+  height: 46px;
+  line-height: 46px;
+  text-align: center;
+  color: #2CB7CA;
+  background-color: #F5FEFF;
+  border: 1px solid #2CB7CA;
+  text-decoration: none;
+  border-radius: 6px;
+  font-size: 16px;
+}
+
+.helpBtnHandle i, #course_detail .c_top .handle .help_btn i, #course_detail .c_middle .tabbar .handle .help_btn i {
+  display: inline-block;
+  margin-right: 4px;
+  font-size: 22px;
+  color: #2CB7CA;
+  vertical-align: middle;
+}
+
+#course_detail {
+/*  line-height: 1;
+  padding-top: 76px;*/
+  padding-bottom: 60px;
+  background-color: #F6F5FB;
+border-top: 1px solid #e0e0e0;
+    margin-top: 1px;
+	padding-top: 32px;
+}
+
+#course_detail .w {
+  position: relative;
+}
+
+#course_detail .c_wrap {
+  width: 980px;
+}
+
+#course_detail .over_btn {
+  display: inline-block;
+  width: 180px;
+  height: 46px;
+  line-height: 46px;
+  margin-right: 16px;
+  text-align: center;
+  color: #888888;
+  background-color: #ebebeb;
+  border-radius: 6px;
+  font-size: 16px;
+}
+
+#course_detail .advertising {
+  position: absolute;
+  right: 0;
+  top: 0;
+  width: 200px;
+  height: 200px;
+}
+
+#course_detail .advertising img {
+  display: block;
+  width: 100%;
+  height: 100%;
+}
+
+#course_detail .c_top {
+  padding: 36px 40px;
+  border-radius: 8px;
+  background-color: #fff;
+}
+
+#course_detail .c_top .t_name {
+  float: left;
+  color: #252627;
+  font-size: 24px;
+line-height: 32px;
+}
+
+#course_detail .c_top .t_status {
+  float: right;
+  display: inline-block;
+  width: 64px;
+  height: 22px;
+  line-height: 22px;
+  font-size: 14px;
+  color: #fff;
+  text-align: center;
+  border-radius: 0 11px 11px 0;
+  background-color: #2CB7CA;
+}
+
+#course_detail .c_top .price_info {
+  margin-top: 20px;
+  padding: 19px 10px 16px;
+  background: #F7F7F7;
+}
+
+#course_detail .c_top .price_info .p_label {
+  display: inline-block;
+  width: 54px;
+  margin-right: 23px;
+  color: #999999;
+  font-size: 14px;
+}
+
+#course_detail .c_top .price_info .p_price {
+  margin-bottom: 16px;
+}
+
+#course_detail .c_top .price_info .p_price .p_value {
+  color: #FF3A20;
+  font-size: 14px;
+}
+
+#course_detail .c_top .price_info .p_price .p_value strong {
+  font-size: 18px;
+}
+
+#course_detail .c_top .price_info .p_sale .p_item {
+  margin-bottom: 8px;
+}
+
+#course_detail .c_top .price_info .p_sale .sale {
+  display: inline-block;
+  width: 68px;
+  height: 20px;
+  text-align: center;
+  line-height: 20px;
+  border-radius: 4px;
+  color: #FF3A20;
+  border: 1px solid #FF3A20;
+  margin-right: 8px;
+  font-size: 13px;
+}
+
+#course_detail .c_top .price_info .p_sale .sale_info {
+  color: #686868;
+  font-size: 13px;
+}
+
+#course_detail .c_top .price_info .p_sale .arrow {
+  display: inline-block;
+  width: 10px;
+  height: 6px;
+  cursor: pointer;
+}
+
+#course_detail .c_top .price_info .p_sale .arrow_down {
+  background: url(../image/more.png) no-repeat center center;
+  background-size: 100% 100%;
+  vertical-align: middle;
+}
+
+#course_detail .c_top .price_info .p_sale .arrow_up {
+  background: url(../image/moreup.png) no-repeat center center;
+  background-size: 100% 100%;
+  vertical-align: middle;
+}
+
+#course_detail .c_top .price_info .p_sale .more {
+  display: none;
+  font-size: 13px;
+  line-height: 20px;
+  padding: 8px 0 0 86px;
+}
+
+#course_detail .c_top .type_info {
+  margin-top: 12px;
+  padding-left: 10px;
+  font-size: 14px;
+}
+
+#course_detail .c_top .type_info .type {
+  float: left;
+  margin-right: 336px;
+}
+
+#course_detail .c_top .type_info .area {
+  float: left;
+}
+
+#course_detail .c_top .type_info .type_label, #course_detail .c_top .type_info .area_label {
+  color: #999999;
+  margin-right: 20px;
+}
+
+#course_detail .c_top .type_info .type_value, #course_detail .c_top .type_info .area_value {
+  color: #686868;
+}
+
+#course_detail .c_top .time_info {
+  margin-top: 12px;
+  font-size: 14px;
+  padding-left: 10px;
+}
+
+#course_detail .c_top .time_info .time_label {
+  color: #999999;
+  margin-right: 20px;
+}
+
+#course_detail .c_top .time_info .time_value {
+  color: #686868;
+}
+
+#course_detail .c_top .handle {
+  margin-top: 18px;
+}
+
+#course_detail .c_middle {
+  margin-top: 10px;
+  border-radius: 8px;
+  background-color: #fff;
+}
+
+#course_detail .c_middle .tabbar {
+  height: 50px;
+  line-height: 50px;
+  border-bottom: 1px solid #EBEBEB;
+}
+
+#course_detail .c_middle .tabbar .tabbar_item {
+  display: inline-block;
+  width: 64px;
+  height: 100%;
+  margin: 0 20px;
+  cursor: pointer;
+  text-align: center;
+  text-decoration: none;
+  color: #686868;
+  font-size: 16px;
+}
+
+#course_detail .c_middle .tabbar:hover {
+  color: #686868;
+}
+
+#course_detail .c_middle .tabbar .active {
+  color: #2CB7CA;
+  border-bottom: 2px solid #2CB7CA;
+}
+
+#course_detail .c_middle .tabbar .handle {
+  display: none;
+  float: right;
+}
+
+#course_detail .c_middle .box {
+  padding: 10px 30px 0;
+  background-color: #fff;
+}
+
+#course_detail .c_middle .box h2.c-title {
+  height: 48px;
+  line-height: 48px;
+  background-color: #F6F6F6;
+  font-size: 16px;
+  padding-left: 20px;
+  margin: 20px 0;
+  color: #686868;
+  position: relative;
+}
+
+#course_detail .c_middle .box h2.c-title:after {
+  content: '';
+  position: absolute;
+  top: 50%;
+  left: 0;
+  height: 20px;
+  width: 2px;
+  margin-top: -10px;
+  background-color: #2CB7CA;
+}
+
+#course_detail .c_middle .box p {
+  line-height: 24px;
+  text-align: justify;
+  font-size: 14px;
+  margin: 5px 0;
+}
+
+#course_detail .c_middle .tips {
+  padding: 30px 40px 36px;
+  color: #1D1D1D;
+  font-size: 14px;
+}
+
+#course_detail .c_middle .tips em {
+  color: #2CB7CA;
+}
+
+#course_detail .c_bottom {
+  margin-top: 19px;
+  margin-bottom: 60px;
+  background-color: #fff;
+}
+
+#course_detail .c_bottom .recommend_header {
+  padding-left: 30px;
+  height: 50px;
+  line-height: 50px;
+  border-bottom: 1px solid #EBEBEB;
+  font-size: 16px;
+  color: #2CB7CA;
+}
+
+#course_detail .c_bottom .recommend_con {
+  padding: 0 30px;
+}
+
+#course_detail .c_bottom .recommend_con .c_body {
+  display: block;
+  width: 100%;
+  height: 60px;
+  line-height: 60px;
+  border-bottom: 1px solid #EBEBEB;
+  box-sizing: border-box;
+}
+
+#course_detail .c_bottom .recommend_con a:hover {
+  background: none;
+}
+
+#course_detail .c_bottom .recommend_con .list_left {
+  float: left;
+  width: 550px;
+  height: 100%;
+}
+
+#course_detail .c_bottom .recommend_con .list_left .c_status {
+  display: inline-block;
+  width: 54px;
+  height: 22px;
+  line-height: 22px;
+  font-size: 14px;
+  color: #fff;
+  text-align: center;
+  border-radius: 0 11px 11px 0;
+  background-color: #CFCFCF;
+}
+
+#course_detail .c_bottom .recommend_con .list_left .status_past {
+  background-color: #CFCFCF;
+}
+
+#course_detail .c_bottom .recommend_con .list_left .status_go {
+  background-color: #2CB7CA;
+}
+
+#course_detail .c_bottom .recommend_con .list_left .c_title {
+  padding-left: 8px;
+  color: #2F2F2F;
+  font-size: 16px;
+}
+
+#course_detail .c_bottom .recommend_con .list_right {
+  float: right;
+  height: 100%;
+}
+
+#course_detail .c_bottom .recommend_con .list_right .c_area, #course_detail .c_bottom .recommend_con .list_right .c_time {
+  display: inline-block;
+  height: 22px;
+  line-height: 22px;
+  margin-right: 4px;
+  padding: 0 8px;
+  background: #F7F9FA;
+  border: 1px solid #EBEDED;
+  box-sizing: border-box;
+  border-radius: 4px;
+  font-size: 13px;
+  text-align: center;
+  color: #686868;
+}
+
+#course_detail .c_bottom .recommend_con .list_right .c_price {
+  margin-left: 12px;
+  font-size: 13px;
+}
+
+#course_detail .c_bottom .recommend_con .list_right .c_price strong {
+  font-size: 18px;
+}
+
+#course_detail .c_bottom .recommend_con .list_right .c_price_go {
+  color: #FF3A20;
+}
+
+#course_detail .c_bottom .recommend_con .list_right .c_price_past {
+  color: #686868;
+}

+ 75 - 0
core/src/web/staticres/course/css/reset_pc.css

@@ -0,0 +1,75 @@
+html, body, div, span, applet, object, iframe, 
+h1, h2, h3, h4, h5, h6, p, blockquote, pre, 
+a, abbr, acronym, address, big, cite, code, 
+del, dfn, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var, 
+dl, dt, dd, li, 
+fieldset, form, label, legend, 
+table, caption, tbody, tfoot, thead, tr, th{
+margin: 0; 
+padding: 0; 
+border: 0; 
+outline: 0; 
+font-weight: inherit; 
+font-style: inherit; 
+font-family: inherit;
+-webkit-tap-highlight-color: transparent;
+} 
+:focus { 
+outline: 0; 
+} 
+body { 
+/*line-height: 1; */
+/*color: black; 
+background: white; */
+font-family: "Microsoft YaHei",sans-serif;
+font-size: 16px;
+-webkit-font-smoothing: antialiased;
+} 
+input{
+	font-family: "Microsoft YaHei",sans-serif;
+	-webkit-appearance: none;
+}
+button{ 
+	outline: none;border: none;
+	}
+table { 
+border-collapse: separate; 
+border-spacing: 0; 
+} 
+caption, th, td { 
+text-align: left; 
+font-weight: normal; 
+} 
+textarea { resize:none;-webkit-appearance: none; }
+img{border:0;}
+a{
+	text-decoration:none;
+	color: #000;
+	font-size: 14px;
+}
+/*selet 下拉三角改变*/
+/*select {border: none;border-radius: 0;appearance:none;-moz-appearance:none;-webkit-appearance:none;background:#ffffff url(../images/public-img/pub-Xsj.png) no-repeat 95% center;}*/
+/*清除ie的默认选择框样式清除,隐藏下拉箭头*/
+/*select::-ms-expand { display: none;}
+html{-webkit-text-size-adjust: none;}	*/	
+	
+/*a:link {color:#606060;} 
+a:visited {color:#606060;} 
+a:hover{color:#8cb91e;	text-decoration: underline;}
+a:active {color:#606060;}*/
+
+.clearfix:after {visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; }
+.clearfix {*zoom:1; }
+.fl {float:left; }
+.fr {float: right; }
+.w {width: 1200px; margin: 0 auto;}
+.ellipsis {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+/*去除下拉框*/
+/*input[type="search"]::-webkit-search-cancel-button{
+  display: none;
+}*/

+ 125 - 0
core/src/web/staticres/course/css/wx_base.css

@@ -0,0 +1,125 @@
+* {
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+    -webkit-overflow-scrolling: touch;
+    -webkit-tap-highlight-color:rgba(0,0,0,0);
+    -webkit-tap-highlight-color:transparent;
+}
+body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, hr, button, article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, sumary {
+    margin: 0;
+    padding: 0;
+}
+html,body {
+    /* max-width: 750px; */
+    -webkit-text-size-adjust: 100%;
+    margin: 0 auto;
+    height: 100%;
+    overflow-x: hidden;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+    font-size: .24rem;
+    background:rgba(245,244,249,1);;
+    color: #3d3d3d;
+    font-family:  "Microsoft YaHei","Helvetica Neue", "Roboto", "Segoe UI", "PingFang SC", "Hiragino Sans GB", sans-serif;
+}
+
+ul,ol {
+    list-style: none;
+}
+/*清除输入框内阴影*/
+input,textarea,select,button{
+    outline: none;
+    border: 0;
+    -webkit-appearance: none;
+    appearance:none;
+}
+button,span,div{
+    -webkit-tap-highlight-color:rgba(0,0,0,0);
+	/* -webkit-user-modify:read-only; */
+}
+img {
+    border: 0;
+    vertical-align: middle;
+    max-width: 100%;
+    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+a {
+    text-decoration: none;
+    color: #3d3d3d;
+	-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
+	-webkit-user-select: none;
+	-moz-user-focus: none;
+	-moz-user-select: none;
+}
+/*禁用长按页面时的弹出菜单(iOS下有效) ,img和a标签都要加*/
+img,a{
+    -webkit-touch-callout:none;
+}
+em,i{
+	font-style: normal;
+}
+/*兼容ios调取h5页面的头部*/
+.ios-head {
+    display: none;
+    position: fixed;
+    top: 0;
+    padding-top: 15px;
+    background: #18974b;
+    width: 100%;
+    z-index: 100;
+}
+/*base*/
+.clearfix{
+    zoom: 1;
+}
+.clearfix:after{
+    clear: both;
+    height: 0;
+    overflow: hidden;
+    display: block;
+    visibility: hidden;
+    content: "";
+}
+
+.left {
+    float: left;
+}
+
+.right {
+    float: right;
+}
+
+.ellipsis {
+    overflow:hidden;
+    text-overflow:ellipsis;
+    white-space:nowrap;
+    text-align: justify
+}
+/* 超过2行省略号显示 */
+.ellipsis-2 {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-line-clamp: 2;
+    -webkit-box-orient: vertical;
+    text-align: justify
+}
+
+/* 超过3行省略号显示 */
+.ellipsis-3 {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-line-clamp: 3;
+    -webkit-box-orient: vertical;
+}
+
+/* 超过一行换行显示 */
+.text-wrap {
+    white-space: pre-wrap;
+}
+
+input, textarea {
+    caret-color: #2ABED1;
+}

+ 506 - 0
core/src/web/staticres/course/css/wx_course_detail.css

@@ -0,0 +1,506 @@
+.course-detail {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+}
+
+.course-detail .sticky {
+  position: -webkit-sticky;
+  position: sticky;
+  left: 0;
+  top: -1px;
+  background-color: #fff;
+  z-index: 9;
+}
+
+.course-detail .absolute {
+  position: absolute;
+  width: 100%;
+  left: 0;
+  top: -1px;
+  background-color: #fff;
+  z-index: 9;
+}
+
+.course-detail .wp {
+  padding: 0 0.32rem;
+  background-color: #fff;
+}
+
+.course-detail .detail-content {
+  flex: 1;
+  overflow-y: scroll;
+  height: 100%;
+
+}
+.course-detail .detail-content::-webkit-scrollbar {display:none}
+
+.course-detail .course-info-detail .header-container {
+  padding: 0.4rem 0.32rem;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+.course-detail .course-info-detail .header-container .header-title {
+  margin-bottom: 0.32rem;
+  font-size: 0.4rem;
+  line-height: 0.6rem;
+  color: #171826;
+}
+
+.course-detail .course-info-detail .header-container .header-info {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 0.24rem;
+  color: #5F5E64;
+}
+
+.course-detail .course-info-detail .header-container .header-info .info-l {
+  display: flex;
+}
+
+.course-detail .course-info-detail .header-container .header-info .course-state,
+.course-detail .course-info-detail .header-container .header-info .course-city,
+.course-detail .course-info-detail .header-container .header-info .course-date {
+  display: flex;
+  align-items: center;
+  margin-right: 0.1rem;
+  padding: 0 0.1rem;
+  background-color: #F7F9FA;
+  border: 1px solid rgba(0, 0, 0, 0.05);
+  border-radius: 0.08rem;
+}
+
+.course-detail .course-info-detail .header-container .header-info .in-progress {
+  color: #fff;
+  background-color: #FF9F40;
+  border: 1px solid #FF9F40;
+}
+
+.course-detail .course-info-detail .header-container .header-info.ended .item-title {
+  color: #9B9CA3;
+}
+
+.course-detail .course-info-detail .header-container .header-info.ended .course-state,
+.course-detail .course-info-detail .header-container .header-info.ended .course-city,
+.course-detail .course-info-detail .header-container .header-info.ended .course-date {
+  color: #9B9CA3;
+}
+
+.course-detail .course-info-detail .header-container .header-info.ended .course-price {
+  color: #9B9CA3;
+}
+
+.course-detail .course-info-detail .header-container .header-info.ended .in-progress {
+  color: #9B9CA3;
+  background-color: #F7F9FA;
+  border: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+.course-detail .course-info-detail .course-time-quantum {
+  display: flex;
+  margin-bottom: 0.2rem;
+  align-items: center;
+  height: 0.88rem;
+}
+
+.course-detail .course-info-detail .course-time-quantum .time-label {
+  margin-right: 0.32rem;
+  font-size: 0.28rem;
+  color: #5F5E64;
+}
+
+.course-detail .course-info-detail .course-time-quantum .time-content {
+  font-size: 0.26rem;
+  color: #171826;
+}
+
+.course-detail .course-info-detail .course-discount {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 0.2rem;
+  padding-top: 0.32rem;
+  padding-bottom: 0.32rem;
+  font-size: 0.28rem;
+  color: #5F5E64;
+}
+
+.course-detail .course-info-detail .course-discount .icon-arrow {
+  color: #C0C4CC;
+}
+
+.course-detail .course-info-detail .course-discount .discount-content {
+  display: flex;
+  flex-direction: column;
+  min-width: 4.2rem;
+  max-width: 5.2rem;
+}
+
+.course-detail .course-info-detail .course-discount .discount-content .discount-item {
+  display: flex;
+  align-items: center;
+  margin-top: 0.08rem;
+}
+
+.course-detail .course-info-detail .course-discount .discount-content .discount-item:first-of-type {
+  margin-top: 0;
+}
+
+.course-detail .course-info-detail .course-discount .discount-content .item-l {
+  margin-right: 0.12rem;
+  padding: 0.02rem 0.12rem;
+  color: #FB483D;
+  font-size: 0.2rem;
+  white-space: nowrap;
+  border: 1px solid rgba(251, 72, 61, 0.5);
+  border-radius: 0.08rem;
+}
+
+.course-detail .course-info-detail .course-discount .discount-content .item-r {
+  font-size: 0.28rem;
+}
+
+.course-detail .course-info-detail .info-detail-content .tabs-wrap {
+  display: flex;
+  height: 0.96rem;
+  font-size: 0.28rem;
+  color: #5F5E64;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+  box-shadow: 0px 2px 8px rgba(54, 147, 179, 0.051);
+}
+
+.course-detail .course-info-detail .info-detail-content .tabs-wrap .tab {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  flex: 1;
+  height: 100%;
+}
+
+.course-detail .course-info-detail .info-detail-content .tabs-wrap .tab.active {
+  color: #2ABED1;
+}
+
+.course-detail .course-info-detail .info-detail-content .tabs-wrap .tab.active:after {
+  content: '';
+  position: absolute;
+  left: 50%;
+  bottom: 0;
+  width: 0.48rem;
+  height: 0.04rem;
+  background-color: #2ABED1;
+  transform: translateX(-50%);
+}
+
+.course-detail .course-info-detail .info-detail-content .box {
+  padding-top: 0.2rem;
+  padding-bottom: 0.32rem;
+  border: 1px solid transparent;
+  overflow-x: scroll;
+}
+
+.course-detail .course-info-detail .info-detail-content .box h2.c-title {
+  position: relative;
+  display: flex;
+  align-items: center;
+  margin-top: 0.32rem;
+  margin-bottom: 0.12rem;
+  padding-left: 0.22rem;
+  font-size: 0.36rem;
+  color: #171826;
+}
+
+.course-detail .course-info-detail .info-detail-content .box h2.c-title:before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 50%;
+  transform: translateY(-45%);
+  width: 0.06rem;
+  height: 0.32rem;
+  background-color: #2ABED1;
+}
+
+.course-detail .course-info-detail .info-detail-content .box p {
+  line-height: 0.52rem;
+  font-size: 0.3rem;
+}
+
+.course-detail .course-info-detail .copyright-container {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0.32rem 0.32rem;
+  height: 1rem;
+  color: #9B9CA3;
+}
+
+.course-detail .course-info-detail .copyright-container .line {
+  width: 0.48rem;
+  height: 1px;
+  background-color: #9B9CA3;
+}
+
+.course-detail .course-info-detail .copyright-container .copyright-info {
+  margin: 0 0.1rem;
+  text-align: center;
+}
+
+.course-detail .bottom-container {
+  padding: 0 0.32rem;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  height: 1.12rem;
+  background-color: #fff;
+}
+
+.course-detail .bottom-container .course-price {
+  font-size: 0.4rem;
+  white-space: nowrap;
+  color: #FB483D;
+}
+
+.course-detail .bottom-container .course-price .yen,
+.course-detail .bottom-container .course-price .unit {
+  font-size: 0.32rem;
+}
+
+.course-detail .bottom-container .button-container {
+  display: flex;
+  justify-content: space-between;
+  flex: 1;
+  margin-left: 0.2rem;
+}
+
+.course-detail .bottom-container .button-container .icon-box {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-around;
+  height: 0.76rem;
+  color: #9B9CA3;
+}
+
+.course-detail .bottom-container .button-container .icon-box .iconfont {
+  font-size: 0.4rem;
+}
+
+.course-detail .bottom-container .button-container .reserve-now {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex: 1;
+  margin-left: 0.2rem;
+  height: 0.8rem;
+  font-size: 0.32rem;
+  color: #fff;
+  background-color: #2ABED1;
+  border-radius: 0.4rem;
+  white-space: nowrap;
+}
+
+.course-detail .bottom-container.ended {
+  color: #9B9CA3;
+}
+
+.course-detail .bottom-container.ended .course-price {
+  color: #9B9CA3;
+}
+
+.course-detail .bottom-container.ended button[disabled] {
+  color: #C0C4CC;
+  background-color: #EDEFF2;
+}
+
+.weui-mask {
+  position: fixed;
+  z-index: 99;
+  top: 0;
+  right: 0;
+  left: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.6);
+}
+
+.weui-dialog {
+  position: fixed;
+  z-index: 5000;
+  top: 50%;
+  left: 16px;
+  right: 16px;
+  -webkit-transform: translateY(-50%);
+  transform: translateY(-50%);
+  background-color: #fff;
+  text-align: center;
+  border-radius: 3px;
+  overflow: hidden;
+}
+
+.weui-dialog__bd:first-child {
+  color: rgba(0, 0, 0, 0.9);
+}
+
+.weui-dialog__bd {
+  min-height: 40px;
+  font-size: 17px;
+  word-wrap: break-word;
+  word-break: break-all;
+  color: rgba(0, 0, 0, 0.5);
+}
+
+.weui-dialog__ft {
+  position: relative;
+  font-size: 17px;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: flex;
+}
+
+.weui-dialog__ft:after {
+  content: " ";
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  height: 1px;
+  border-top: 1px solid rgba(0, 0, 0, 0.1);
+  color: rgba(0, 0, 0, 0.1);
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+}
+
+.weui-dialog__btn {
+  display: block;
+  -webkit-box-flex: 1;
+  -webkit-flex: 1;
+  flex: 1;
+  color: #576b95;
+  font-weight: 700;
+  text-decoration: none;
+  -webkit-tap-highlight-color: transparent;
+  position: relative;
+}
+
+.discount-picker {
+  display: none;
+}
+
+.discount-picker .weui-mask {
+  bottom: 1.12rem;
+}
+
+.discount-picker .weui-picker {
+  box-sizing: border-box;
+  padding: 0 0.32rem;
+  position: fixed;
+  width: 100%;
+  left: 0;
+  right: 0;
+  max-height: 75%;
+  bottom: 1.12rem;
+  z-index: 100;
+  border-top-left-radius: 12px;
+  border-top-right-radius: 12px;
+  overflow: hidden;
+  background-color: #fff;
+  transition: transform .3s;
+}
+
+.discount-picker .weui-dialog__hd {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  height: 1.1rem;
+}
+
+.discount-picker .weui-dialog__hd .weui-dialog__hd__left {
+  font-weight: 700;
+  font-size: 0.36rem;
+}
+
+.discount-picker .weui-dialog__hd .weui-dialog__hd__right {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  height: 100%;
+  width: 0.4rem;
+}
+
+.discount-picker .weui-dialog__hd .weui-picker__btn {
+  background-color: #fff;
+}
+
+.discount-picker .weui-dialog__hd .weui-picker__btn.icon-close {
+  color: #C0C4CC;
+}
+
+.discount-picker .weui-dialog__bd {
+  margin-bottom: 0.5rem;
+  word-wrap: break-word;
+  overflow-y: auto;
+}
+
+.discount-picker .weui-dialog__bd .discount-item {
+  margin-bottom: 0.32rem;
+}
+
+.discount-picker .weui-dialog__bd .discount-item .item-tip {
+  display: flex;
+  align-items: center;
+  height: 0.64rem;
+}
+
+.discount-picker .weui-dialog__bd .discount-item .item-tip .tip-l {
+  margin-right: 0.12rem;
+  padding: 0.02rem 0.12rem;
+  color: #FB483D;
+  font-size: 0.2rem;
+  white-space: nowrap;
+  border: 1px solid rgba(251, 72, 61, 0.5);
+  border-radius: 0.08rem;
+}
+
+.discount-picker .weui-dialog__bd .discount-item .item-tip .tip-r {
+  font-size: 0.24rem;
+}
+
+.discount-picker .weui-dialog__bd .discount-item .item-content {
+  font-size: 0.28rem;
+  color: #171826;
+  line-height: 0.44rem;
+}
+
+.jy-alert .weui-dialog {
+  margin-left: -2.8rem;
+  width: 5.6rem;
+  height: 2.49rem;
+  left: 50%;
+  border-radius: .08rem;
+}
+
+.jy-alert .weui-dialog__bd {
+  padding: 0;
+  height: 1.49rem;
+  line-height: 1.49rem;
+}
+
+.jy-alert .weui-dialog__ft {
+  height: 1rem;
+  line-height: 1rem;
+}
+
+.jy-alert .weui-dialog__ft .weui-dialog__btn {
+  color: #2CB7CA;
+  font-weight: 400;
+}
+
+.c_state {
+    color: #fff !important;
+    background-color: #C0C4CC !important;
+    border: 1px solid rgba(0, 0, 0, 0.05) !important;
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 3 - 0
core/src/web/staticres/course/iconfont/iconfont.css


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 3 - 0
core/src/web/staticres/course/iconfont/wx_iconfont.css


BIN
core/src/web/staticres/course/image/more.png


+ 417 - 0
core/src/web/staticres/course/js/common.js

@@ -0,0 +1,417 @@
+var priceshow = false;
+var timeshow = false;
+function priceTime(){
+	$(".pricefat").mouseover(function(){
+		if(!$(".pricefat").hasClass("active")){
+			$("#minprice").css({"border-color":"#2cb7ca"});
+			$("#maxprice").css({"border-color":"#2cb7ca"});
+			$(".pricebut").show();
+			$(".pricefat").addClass("customtime-active");
+		}
+	}).mouseout(function(){
+		if(!$(".pricefat").hasClass("active")){
+			if(!priceshow){
+				$("#minprice").css({"border-color":""});
+				$("#maxprice").css({"border-color":""});
+				$(".pricebut").hide();
+				$(".pricefat").removeClass("customtime-active");
+			}
+		}
+	})
+	$("#minprice,#maxprice").blur(function(){
+		if(!priceshow&&!$(".pricefat").hasClass("active")){
+			$("#minprice").css({"border-color":""});
+			$("#maxprice").css({"border-color":""});
+			$(".pricebut").hide();
+			$(".pricefat").removeClass("customtime-active");
+		}
+	})
+	$("#minprice").click(function(){
+		priceshow=true;
+		$(".pricebut").show();
+		$(".pricefat").addClass("customtime-active");
+	})
+	$("#maxprice").click(function(){
+		priceshow=true;
+		$(".pricebut").show();
+		$(".pricefat").addClass("customtime-active");
+	})
+	//
+	$(".timerInput").mouseover(function(){
+		if(!$(".timerInput").hasClass("active")){
+			$("#starttime").css({"border-color":"#2cb7ca"});
+			$("#endtime").css({"border-color":"#2cb7ca"});
+			$("#timebut").show();
+			$(".timerInput").addClass("customtime-active");
+		}
+	}).mouseout(function(){
+		if(!$(".timerInput").hasClass("active")){
+			if(!timeshow){
+				$("#starttime").css({"border-color":""});
+				$("#endtime").css({"border-color":""});
+				$("#timebut").hide();
+				$(".timerInput").removeClass("customtime-active");
+			}
+		}
+	})
+	//
+	$("#starttime").click(function(){
+		timeshow = true;
+		$("#timebut").show();
+		$(".timerInput").addClass("customtime-active");
+	})
+	$("#endtime").click(function(){
+		timeshow = true;
+		$("#timebut").show();
+		$(".timerInput").addClass("customtime-active");
+	})
+}
+//
+var EasyAlert = {
+	timeout: null,
+	waitTime: 1000,
+	show: function(text,css,waitTime){
+		if(this.timeout != null){
+			clearTimeout(this.timeout);
+			this.hide();
+			this.timeout = null;
+		}
+		var thisClass = this;
+		this.timeout = setTimeout(function(){
+			thisClass.hide();
+			thisClass.timeout = null;
+		},waitTime?waitTime:this.waitTime);
+		$("body").append('<div class="easyalert" id="easyAlert">'+text+'</div>');
+		if(typeof(css) != "undefined"&&css!=""){
+			$("#easyAlert").css(css);
+		}
+		$("#easyAlert").css({"left":"50%","margin-top":-($("#easyAlert").outerHeight()/2),"margin-left":-($("#easyAlert").outerWidth()/2)}).show();
+	},
+	hide: function(){
+		$("#easyAlert").remove();
+	}
+}
+var EasyPopup = function(id){
+	this.id = id;
+	var thisClass = this;
+	document.getElementById(id).ontap = function(e){
+		if(e.target.id == id){
+			thisClass.hide();
+		}
+	}
+	this.show = function(){
+		$("#"+this.id).fadeIn();
+		var mainObj = $("#"+id+">div:first");
+		mainObj.css({"margin-top":-(mainObj.outerHeight()/2 + 35)});
+	},
+	this.hide = function(){
+		$("#"+this.id).fadeOut();
+	}
+}
+//计算时差
+function timeDiff(date){
+	var date1 = date;//开始时间
+	var date2 = new Date();//结束时间
+	var date3 = date2.getTime()-date1.getTime();//时间差的毫秒数
+	//计算出相差天数
+	var days = Math.floor(date3/(24*3600*1000));
+	//计算出小时数
+	var leave1 = date3%(24*3600*1000);//计算天数后剩余的毫秒数
+	var hours = Math.floor(leave1/(3600*1000));
+	//计算相差分钟数
+	var leave2 = leave1%(3600*1000);//计算小时数后剩余的毫秒数
+	var minutes = Math.floor(leave2/(60*1000));
+	//计算相差秒数
+	var td = "30秒前";
+	if(days > 0){
+		if (days > 10) {
+			var date1year = date1.getFullYear();
+			var date2year = date2.getFullYear();
+			var date1month = date1.getMonth()+1;
+			var date1day = date1.getDate();
+			if(date1month < 10){
+				date1month ="0"+date1month;
+			}
+			if(date1day < 10){
+				date1day ="0"+date1day;
+			}
+			if (date1year<date2year){
+				td = date1.getFullYear()+"-"+date1month+"-"+date1day;
+			}else{
+				td = date1month+"-"+date1day;
+			}
+		} else {
+			td = days+"天前"
+		}
+	}else if(hours > 0){
+		td = hours+"小时前";
+	}else if(minutes > 0){
+		td = minutes+"分钟前";
+	}
+	return td;
+}
+function redirect(zbadd,link,sid,sds){
+	if(link != null && typeof(link) != "undefined"){
+		link = link.replace(/\n/g,"");
+		if(!/^http/.test(link)){
+			link="http://"+link
+		}
+	}
+	if(sds){
+		window.location.href=zbadd+"/article/content/"+sid+".html?keywords="+encodeURIComponent(sds);
+	}else{
+		window.location.href=zbadd+"/article/content/"+sid+".html";
+	}
+}
+function newredirect(zbadd,link,sid,sds,index){
+	if(link != null && typeof(link) != "undefined"){
+		link = link.replace(/\n/g,"");
+		if(!/^http/.test(link)){
+			link="http://"+link
+		}
+	}
+	var pt = ""
+	if (index==1){
+		pt="projectMatch=项目匹配"
+	}
+	if(sds){
+		pt = "&"+pt
+		window.location.href=zbadd+"/article/content/"+sid+".html?keywords="+encodeURIComponent(sds)+pt;
+	}else{
+		window.location.href=zbadd+"/article/content/"+sid+".html"+pt;
+	}
+}
+function pcredirect(link,sid){
+	window.open("/pcdetail/"+sid+".html");
+}
+function keyWordHighlight(value,oldChars,newChar){
+	if(typeof(oldChars) == "undefined" || oldChars == null || typeof(newChar) == "undefined" || newChar == null || newChar == ""){
+		return value;
+	}
+	var array = [];
+	if(oldChars instanceof Array){
+		array = oldChars.concat();
+	}else{
+		array.push(oldChars);
+	}
+	try{
+		var map = {};
+		for(var i=0;i<array.length;i++){
+			var oldChar = array[i];
+			if(oldChar.replace(/\s+/g,"") == "" || map[oldChar]){
+				continue;
+			}
+			map[oldChar] = true;
+			oldChar = oldChar.replace(/\$/g,"\\$");
+			oldChar = oldChar.replace(/\(/g,"\\(");
+			oldChar = oldChar.replace(/\)/g,"\\)");
+			oldChar = oldChar.replace(/\*/g,"\\*");
+			oldChar = oldChar.replace(/\+/g,"\\+");
+			oldChar = oldChar.replace(/\./g,"\\.");
+			oldChar = oldChar.replace(/\[/g,"\\[");
+			oldChar = oldChar.replace(/\]/g,"\\]");
+			oldChar = oldChar.replace(/\?/g,"\\?");
+			oldChar = oldChar.replace(/\\/g,"\\");
+			oldChar = oldChar.replace(/\//g,"\\/");
+			oldChar = oldChar.replace(/\^/g,"\\^");
+			oldChar = oldChar.replace(/\{/g,"\\{");
+			oldChar = oldChar.replace(/\}/g,"\\}");
+			oldChar = oldChar.replace(/\|/g,"\\|");
+			value = value.replace(new RegExp("("+oldChar+")",'gmi'),newChar);
+		}
+	}catch(e){}
+	return value;
+}
+function getWxVersion(){
+	var wechatInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
+	if(!wechatInfo) {
+	  	return null;
+	}
+	return wechatInfo[1];
+}
+/**
+ * 设置光标在短连接输入框中的位置
+ * @param inpObj 输入框
+ * @param pos
+ */
+function setCursorPos(inpObj, pos){
+    if(navigator.userAgent.indexOf("MSIE") > -1){
+        var range = document.selection.createRange();
+        var textRange = inpObj.createTextRange();
+        textRange.moveStart('character',pos);
+        textRange.collapse();
+        textRange.select();
+    }else{
+        inpObj.setSelectionRange(pos,pos);
+    }
+}
+/**
+ * 获取光标在短连接输入框中的位置
+ * @param inpObj 输入框
+ */
+function getCursorPos(inpObj){
+     if(navigator.userAgent.indexOf("MSIE") > -1) { // IE
+        var range = document.selection.createRange();
+        range.text = '';
+        range.setEndPoint('StartToStart',inpObj.createTextRange());
+        return range.text.length;
+    } else {
+        return inpObj.selectionStart;
+    }
+}
+//获取url中参数
+function getUrlParam(name){
+    var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
+    var r = window.location.search.substr(1).match(reg);
+    if(r != null)
+		return unescape(r[2]); 
+	return null;
+}
+
+/******* 获取url参数(正则)********/
+function getParam(name) {
+    var search = document.location.search;
+    // alert(search);
+    var pattern = new RegExp("[?&]" + name + "\=([^&]+)", "g");
+    var matcher = pattern.exec(search);
+    var items = null;
+    if (null != matcher) {
+        try {
+            items = decodeURIComponent(decodeURIComponent(matcher[1]));
+        } catch (e) {
+            try {
+                items = decodeURIComponent(matcher[1]);
+            } catch (e) {
+                items = matcher[1];
+            }
+        }
+    }
+    return items;
+};
+//获取滚动条宽度
+function getScrollWidth() {
+	var noScroll, scroll, oDiv = document.createElement("DIV");
+    oDiv.style.cssText = "position:absolute; top:-1000px; width:100px; height:100px; overflow:hidden;";
+  	noScroll = document.body.appendChild(oDiv).clientWidth;
+  	oDiv.style.overflowY = "scroll";
+  	scroll = oDiv.clientWidth;
+  	document.body.removeChild(oDiv);
+  	return noScroll-scroll;
+}
+//表头固定
+var TableHeadFixed = function(className,isminus,flag,pageName){
+	if(typeof(className) == "undefined"){
+		className = "tabContainer-2";
+	}
+	if(typeof(isminus) == "undefined"){
+		isminus = true;
+	}
+	if(typeof(flag) == "undefined"){
+		flag = true;
+	}
+	var cHeight = document.body.clientHeight;
+	if(cHeight <= 0){
+		cHeight = 500;
+	}
+	var thisFlag = false;
+	var prevSelectType = null;
+	$(window).scroll(function(event){
+		if(!$("#right-table").hasClass("active") && flag){
+			return;
+		}
+		//超级搜索页面增加处理逻辑
+		if(pageName == "supsearch"){
+			if(prevSelectType != selectType){
+				thisFlag = false;
+			}
+			prevSelectType = selectType;
+			if(selectType == "all"){
+				className = "tabContainer"
+			}else{
+				className = "tabContainer-2";
+			}
+		}
+		var tableHeight = $("."+className).outerHeight();
+		if(tableHeight <= cHeight){
+				$("."+className+" .lucene-table").removeClass("tabfixed tababsolute");
+				$("."+className+" .lucene-table>table:first").css("top",0);
+				thisFlag = false;
+			return;
+		}
+		var offsetTop = $("."+className).offset().top;
+		var scrollTop = $(this).scrollTop();
+		var oTop = offsetTop;
+		var ooTop = offsetTop;
+		if(isminus){
+			oTop+=20;
+			ooTop-=20;
+		}
+		if(scrollTop >= oTop){
+			if(ooTop + tableHeight - scrollTop -20 <= cHeight){
+				if(!thisFlag){
+					$("."+className+" .lucene-table").addClass("tababsolute");
+					$("."+className+" .lucene-table>table:first").css("top",scrollTop);
+				}
+				thisFlag = true;
+			}else{
+				if(thisFlag){
+					$("."+className+" .lucene-table").removeClass("tababsolute");
+					$("."+className+" .lucene-table>table:first").css("top",0);
+				}
+				thisFlag = false;
+			}
+			$("."+className+" .lucene-table").addClass("tabfixed");
+		}else{
+			$("."+className+" .lucene-table").removeClass("tabfixed tababsolute");
+			$("."+className+" .lucene-table>table:first").css("top",0);
+			thisFlag = false;
+		}
+	});
+}
+//页面跳转输入框光标位置
+function moveEnd(obj) {
+	obj.focus();
+	var len = obj.value.length;
+	if (document.selection) {
+		var sel = obj.createTextRange();
+		sel.moveStart('character', len);
+		sel.collapse();
+		sel.select();
+	} else if (typeof obj.selectionStart == 'number'
+			&& typeof obj.selectionEnd == 'number') {
+		obj.selectionStart = obj.selectionEnd = len;
+	}
+}
+function mySysIsIos(){
+	return !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
+}
+$(function(){
+	//自定义tap
+	if("ontouchend" in document){
+		$(document).on("touchstart", function(e) {
+	        var $target = $(e.target);
+	        $target.data("isMoved", 0);
+			$target.data("startTime", Date.now());
+	    });
+	    $(document).on("touchmove", function(e) {
+	        var $target = $(e.target);
+	        $target.data("isMoved", 1);
+	    });
+	    $(document).on("touchend", function(e) {
+	        var $target = $(e.target);
+			var startTime = $target.data("startTime");
+			if(Date.now()-startTime>200){
+				return;
+			}
+	        if($target.data("isMoved") == 1){
+				return;
+			}
+			$target.trigger("tap");
+	    });
+	}else{
+		$(document).on("click", function(e) {
+			var $target = $(e.target);
+			$target.trigger("tap");
+	    });
+	}
+});

+ 216 - 0
core/src/web/staticres/course/js/course_detail.js

@@ -0,0 +1,216 @@
+$(function () {
+    var boxTop = $(".tabbar").offset().top;
+    var scrollTop = 0;
+    //页面滚动
+    $(window).scroll(function () {
+        scrollTop = $(window).scrollTop();
+        if (scrollTop >= boxTop) {
+            $(".tabbar").css({
+                "position": "fixed",
+                "top": 0,
+                "background-color": "#fff",
+                "width": "980px",
+                "height": "72px",
+                "line-height": "72px",
+                "z-index": "999"
+            });
+            $('.tabbar .handle').show();
+        } else {
+            $(".tabbar").css({
+                "position": "static",
+                "width": "980px",
+                "height": "50px",
+                "line-height": "50px",
+            });
+            $('.tabbar .handle').hide();
+        }
+    });
+
+    function bSort(arr) {
+        var len = arr.length;
+        for (var i = 0; i < len - 1; i++) {
+            for (var j = 0; j < len - 1 - i; j++) {
+                // 相邻元素两两对比,元素交换,大的元素交换到后面
+                if (arr[j].oTop > arr[j + 1].oTop) {
+                    var temp = arr[j];
+                    arr[j] = arr[j + 1];
+                    arr[j + 1] = temp;
+                }
+            }
+        }
+        return arr;
+    }
+
+    // 滚动距离
+    initTabChange();
+
+    function initTabChange() {
+        var h2Ids = [];
+        // 获取所有带有id属性的h2标签的位置
+        $('.box h2[id]').each(function (i, dom) {
+            // var y = dom.getBoundingClientRect().top + scrollTop;
+            var y = dom.offsetTop;
+            h2Ids.push({
+                id: dom.id,
+                oTop: y - 48
+            });
+        });
+        if (h2Ids.length > 0) {
+            h2Ids = bSort(h2Ids);
+        }
+        // 监听滚动,控制tab高亮
+        var cannotTriggerScroll = false;
+        $(window).on('scroll', function () {
+            if (cannotTriggerScroll) return;
+            cannotTriggerScroll = true;
+            var current = null;
+            scrollTop = parseInt($(window).scrollTop());
+            h2Ids.some(function (item, i) {
+                if (scrollTop < h2Ids[0].oTop) {
+                    current = h2Ids[0];
+                    return true;
+                }
+
+                if (scrollTop > h2Ids[h2Ids.length - 1].oTop) {
+                    current = h2Ids[h2Ids.length - 1];
+                    return true;
+                }
+
+                if (scrollTop > item.oTop && scrollTop < h2Ids[i + 1].oTop) {
+                    current = item;
+                    return true;
+                }
+            });
+            if (current) {
+                $('.tabbar .tabbar_item[data-id=' + current.id + ']').addClass('active').siblings().removeClass('active');
+            }
+            cannotTriggerScroll = false;
+        });
+
+        // tab点击事件
+        $('.course_detail').on('click', '.tabbar_item', function () {
+            cannotTriggerScroll = true
+            var $this = $(this);
+            var id = $this.attr('data-id');
+            scrollTop = $(window).scrollTop();
+            // // 控制active样式
+            $this.addClass('active').siblings().removeClass('active');
+            // // 计算滚动距离并滚动
+            // // e距离文档顶部的距离 = e相对的与视口的距离 + 滚动距离
+            $(window).stop()
+            var y = $('#' + id)[0].getBoundingClientRect().top + scrollTop;
+            $('html').animate({
+                "scrollTop": y - 55 - 72 + 'px'
+            }, 300, function () {
+                setTimeout(function () {
+                    cannotTriggerScroll = false
+                }, 100)
+            });
+        });
+    }
+    getCourseContent(msgId);
+    // 展开收起
+    $(".arrow").click(function () {
+        if ($(this).hasClass('arrow_down')) {
+            $(this).removeClass('arrow_down').addClass('arrow_up');
+        } else {
+            $(this).removeClass('arrow_up').addClass('arrow_down');
+        }
+        $(this).next('.more').slideToggle(500);
+    })
+})
+
+function getCourseContent(id) {
+    $.ajax({
+        type: "GET",
+        async: false,
+        url: "/manage/course/previewGetDate",
+        data: {"_id": id, "aboutFlag": "true"},
+        datatype: "json",
+        success: function (d) {
+            var r = d.data;
+            var html = "";
+            if (typeof (r) != "undefined" && r["detail"] !== undefined) {
+                $(".t_name").text(r["detail"].s_name);
+                $(".p_value strong").text(parseInt(r["detail"].i_price) / 100);
+                s_discountPlan = r["detail"].s_discountPlan
+                var t = ""
+                var yh = "优&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;惠"
+                try {
+                    if (typeof (s_discountPlan) != "undefined" && s_discountPlan.length > 0) {
+                        for (var m = 0; m < s_discountPlan.length; m++) {
+                            if (m > 0) {
+                                yh = ""
+                            }
+                            try {
+                                t += '<div class="p_item">\n' +
+                                    '                            <span class="p_label">' + yh + '</span>\n' +
+                                    '                            <span class="sale">' + s_discountPlan[m].title + '</span>\n' +
+                                    '                            <span class="sale_info">' + s_discountPlan[m].remarks + '</span>\n' +
+                                    '                            <i class="arrow arrow_down"></i>\n' +
+                                    '                            <div class="more">' + s_discountPlan[m].content + '</div>\n' +
+                                    '                        </div>\n' +
+                                    '                    </div>';
+                            } catch (e) {
+                            }
+                        }
+                        $(".p_sale").html(t)
+                    }
+                } catch (e) {
+                    console.log(e)
+                }
+                if (r["detail"].i_type != 1) {
+                    $(".type_value").text("投标实务课程")
+                } else {
+                    $(".type_value").text("招标管理课程")
+                }
+                $(".area_value").text(r["detail"].s_address);
+                $(".time_value").text(formatTime(r["detail"].l_starttime.split(" ")[0]) + "-" + formatTime(r["detail"].l_endtime));
+                $(".box").html(r["detail"].s_content);
+                //
+                var nowTime = new Date().getTime();
+                // var startTimes = new Date(r["detail"].l_starttime.split(" ")[0] + " 23:59:59").getTime() - 86400000;
+                var startTimes = new Date(r["detail"].l_starttime).getTime();
+                if (nowTime >= startTimes) {
+                    var status = "已结束";
+                    $(".t_status").css("background-color", "#E0E0E0");
+                    $(".buy_btn").css("background-color", "#E0E0E0");
+                    $(".buy_btn").attr("disabled", true)
+                    $(".t_status").text(status);
+                } else {
+                    var status = "报名中";
+                    if (r["detail"].i_status !== 1) {
+                        status = "已结束";
+                        $(".t_status").css("background-color", "#E0E0E0");
+                        $(".buy_btn").css("background-color", "#E0E0E0");
+                        $(".buy_btn").attr("disabled", true)
+                    }
+                    $(".t_status").text(status);
+                }
+                if (typeof (r["aboutList"]) != "undefined" && r["aboutList"].length > 0) {
+                    tj = '<div class="recommend_header">相关课程推荐</div>';
+                    for (var i = 0; i < r["aboutList"].length; i++) {
+                        var t = ""
+                        t = '<div class="recommend_con"><ul><li><a href="/front/course/detail?aboutFlag=true&_id=' + r["aboutList"][i]._id + '" class="clearfix c_body"><div class="ellipsis list_left"><span class="c_status status_go">'
+                        if (r["aboutList"][i].i_status === 1) {
+                            t += "报名中"
+                        } else {
+                            t += "已结束"
+                        }
+                        t += '</span><span class="c_title">' + r["aboutList"][i].s_name + '</span></div><div class="list_right"><span class="c_area">' + r["aboutList"][i].s_address + '</span><span class="c_time">' + r["aboutList"][i].l_starttime + '</span><span class="c_price c_price_go">¥<strong>' + r["aboutList"][i].i_price / 100 + '</strong>元/人</span></div></a></li></ul></div>'
+                        html += t;
+                    }
+                    $(".c_bottom").html(tj + html)
+                }
+
+            }
+
+        }
+    })
+}
+
+//时间格式化
+function formatTime(t) {
+    var formattime = t.split("-", 3);
+    return formattime[0] + "/" + formattime[1] + "/" + formattime[2]
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 3 - 0
core/src/web/staticres/course/js/jquery.js


+ 18 - 0
core/src/web/staticres/course/js/rem.js

@@ -0,0 +1,18 @@
+(function(){
+    function w() {
+        var r = document.documentElement;
+        var a = r.getBoundingClientRect().width;
+        if (a > 750 ){
+            a = 750;
+        } 
+        //750/w = 100/font-size
+        rem = a / 7.5;
+        r.style.fontSize = rem + "px"
+    }
+    var t;
+    w();
+    window.addEventListener("resize", function() {
+        clearTimeout(t);
+        t = setTimeout(w, 300);
+    }, false);
+})();

+ 8 - 1
core/src/web/staticres/css/unicorn.main.css

@@ -92,7 +92,7 @@
     margin-right: 0;
     margin-bottom: 25px;
     position: relative;
-    min-height: 660px;
+	min-height: 713px;
     width: auto;
     border-top-left-radius: 8px;
 }
@@ -1318,3 +1318,10 @@ div.dataTables_wrapper .ui-widget-header {
 		margin-left: 43px;
 	}
 }
+
+.glyphicon.course-icon{
+	width: 15px;
+	height: 15px;
+	background-size: 15px 15px;
+	background-image: url("/images/crouse-icon.png");
+}

BIN
core/src/web/staticres/images/crouse-icon.png


+ 1189 - 0
core/src/web/staticres/js/bootbox.js

@@ -0,0 +1,1189 @@
+/*! @preserve
+ * bootbox.js
+ * version: 5.3.4
+ * author: Nick Payne <nick@kurai.co.uk>
+ * license: MIT
+ * http://bootboxjs.com/
+ */
+(function (root, factory) {
+  'use strict';
+  if (typeof define === 'function' && define.amd) {
+    // AMD
+    define(['jquery'], factory);
+  } else if (typeof exports === 'object') {
+    // Node, CommonJS-like
+    module.exports = factory(require('jquery'));
+  } else {
+    // Browser globals (root is window)
+    root.bootbox = factory(root.jQuery);
+  }
+}(this, function init($, undefined) {
+  'use strict';
+
+  //  Polyfills Object.keys, if necessary.
+  //  @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
+  if (!Object.keys) {
+    Object.keys = (function () {
+      var hasOwnProperty = Object.prototype.hasOwnProperty,
+        hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
+        dontEnums = [
+          'toString',
+          'toLocaleString',
+          'valueOf',
+          'hasOwnProperty',
+          'isPrototypeOf',
+          'propertyIsEnumerable',
+          'constructor'
+        ],
+        dontEnumsLength = dontEnums.length;
+
+      return function (obj) {
+        if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) {
+          throw new TypeError('Object.keys called on non-object');
+        }
+
+        var result = [], prop, i;
+
+        for (prop in obj) {
+          if (hasOwnProperty.call(obj, prop)) {
+            result.push(prop);
+          }
+        }
+
+        if (hasDontEnumBug) {
+          for (i = 0; i < dontEnumsLength; i++) {
+            if (hasOwnProperty.call(obj, dontEnums[i])) {
+              result.push(dontEnums[i]);
+            }
+          }
+        }
+
+        return result;
+      };
+    }());
+  }
+
+  var exports = {};
+
+  var VERSION = '5.0.0';
+  exports.VERSION = VERSION;
+
+  var locales = {};
+
+  var templates = {
+    dialog:
+    '<div class="bootbox modal" tabindex="-1" role="dialog" aria-hidden="true">' +
+    '<div class="modal-dialog">' +
+    '<div class="modal-content">' +
+    '<div class="modal-body"><div class="bootbox-body"></div></div>' +
+    '</div>' +
+    '</div>' +
+    '</div>',
+    header:
+    '<div class="modal-header">' +
+    '<h5 class="modal-title"></h5>' +
+    '</div>',
+    footer:
+    '<div class="modal-footer"></div>',
+    closeButton:
+    '<button type="button" class="bootbox-close-button close" aria-hidden="true">&times;</button>',
+    form:
+    '<form class="bootbox-form"></form>',
+    button:
+    '<button type="button" class="btn"></button>',
+    option:
+    '<option></option>',
+    promptMessage:
+    '<div class="bootbox-prompt-message"></div>',
+    inputs: {
+      text:
+      '<input class="bootbox-input bootbox-input-text form-control" autocomplete="off" type="text" />',
+      textarea:
+      '<textarea class="bootbox-input bootbox-input-textarea form-control"></textarea>',
+      email:
+      '<input class="bootbox-input bootbox-input-email form-control" autocomplete="off" type="email" />',
+      select:
+      '<select class="bootbox-input bootbox-input-select form-control"></select>',
+      checkbox:
+      '<div class="form-check checkbox"><label class="form-check-label"><input class="form-check-input bootbox-input bootbox-input-checkbox" type="checkbox" /></label></div>',
+      radio:
+      '<div class="form-check radio"><label class="form-check-label"><input class="form-check-input bootbox-input bootbox-input-radio" type="radio" name="bootbox-radio" /></label></div>',
+      date:
+      '<input class="bootbox-input bootbox-input-date form-control" autocomplete="off" type="date" />',
+      time:
+      '<input class="bootbox-input bootbox-input-time form-control" autocomplete="off" type="time" />',
+      number:
+      '<input class="bootbox-input bootbox-input-number form-control" autocomplete="off" type="number" />',
+      password:
+      '<input class="bootbox-input bootbox-input-password form-control" autocomplete="off" type="password" />',
+      range:
+      '<input class="bootbox-input bootbox-input-range form-control-range" autocomplete="off" type="range" />'
+    }
+  };
+
+
+  var defaults = {
+    // default language
+    locale: 'en',
+    // show backdrop or not. Default to static so user has to interact with dialog
+    backdrop: 'static',
+    // animate the modal in/out
+    animate: true,
+    // additional class string applied to the top level dialog
+    className: null,
+    // whether or not to include a close button
+    closeButton: true,
+    // show the dialog immediately by default
+    show: true,
+    // dialog container
+    container: 'body',
+    // default value (used by the prompt helper)
+    value: '',
+    // default input type (used by the prompt helper)
+    inputType: 'text',
+    // switch button order from cancel/confirm (default) to confirm/cancel
+    swapButtonOrder: false,
+    // center modal vertically in page
+    centerVertical: false,
+    // Append "multiple" property to the select when using the "prompt" helper
+    multiple: false,
+    // Automatically scroll modal content when height exceeds viewport height
+    scrollable: false
+  };
+
+
+  // PUBLIC FUNCTIONS
+  // *************************************************************************************************************
+
+  // Return all currently registered locales, or a specific locale if "name" is defined
+  exports.locales = function (name) {
+    return name ? locales[name] : locales;
+  };
+
+
+  // Register localized strings for the OK, Confirm, and Cancel buttons
+  exports.addLocale = function (name, values) {
+    $.each(['OK', 'CANCEL', 'CONFIRM'], function (_, v) {
+      if (!values[v]) {
+        throw new Error('Please supply a translation for "' + v + '"');
+      }
+    });
+
+    locales[name] = {
+      OK: values.OK,
+      CANCEL: values.CANCEL,
+      CONFIRM: values.CONFIRM
+    };
+
+    return exports;
+  };
+
+
+  // Remove a previously-registered locale
+  exports.removeLocale = function (name) {
+    if (name !== 'en') {
+      delete locales[name];
+    }
+    else {
+      throw new Error('"en" is used as the default and fallback locale and cannot be removed.');
+    }
+
+    return exports;
+  };
+
+
+  // Set the default locale
+  exports.setLocale = function (name) {
+    return exports.setDefaults('locale', name);
+  };
+
+
+  // Override default value(s) of Bootbox.
+  exports.setDefaults = function () {
+    var values = {};
+
+    if (arguments.length === 2) {
+      // allow passing of single key/value...
+      values[arguments[0]] = arguments[1];
+    } else {
+      // ... and as an object too
+      values = arguments[0];
+    }
+
+    $.extend(defaults, values);
+
+    return exports;
+  };
+
+
+  // Hides all currently active Bootbox modals
+  exports.hideAll = function () {
+    $('.bootbox').modal('hide');
+
+    return exports;
+  };
+
+
+  // Allows the base init() function to be overridden
+  exports.init = function (_$) {
+    return init(_$ || $);
+  };
+
+
+  // CORE HELPER FUNCTIONS
+  // *************************************************************************************************************
+
+  // Core dialog function
+  exports.dialog = function (options) {
+    if ($.fn.modal === undefined) {
+      throw new Error(
+        '"$.fn.modal" is not defined; please double check you have included ' +
+        'the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ ' +
+        'for more details.'
+      );
+    }
+
+    options = sanitize(options);
+
+    if ($.fn.modal.Constructor.VERSION) {
+      options.fullBootstrapVersion = $.fn.modal.Constructor.VERSION;
+      var i = options.fullBootstrapVersion.indexOf('.');
+      options.bootstrap = options.fullBootstrapVersion.substring(0, i);
+    }
+    else {
+      // Assuming version 2.3.2, as that was the last "supported" 2.x version
+      options.bootstrap = '2';
+      options.fullBootstrapVersion = '2.3.2';
+      console.warn('Bootbox will *mostly* work with Bootstrap 2, but we do not officially support it. Please upgrade, if possible.');
+    }
+
+    var dialog = $(templates.dialog);
+    var innerDialog = dialog.find('.modal-dialog');
+    var body = dialog.find('.modal-body');
+    var header = $(templates.header);
+    var footer = $(templates.footer);
+    var buttons = options.buttons;
+
+    var callbacks = {
+      onEscape: options.onEscape
+    };
+
+    body.find('.bootbox-body').html(options.message);
+
+    // Only attempt to create buttons if at least one has 
+    // been defined in the options object
+    if (getKeyLength(options.buttons) > 0) {
+      each(buttons, function (key, b) {
+        var button = $(templates.button);
+        button.data('bb-handler', key);
+        button.addClass(b.className);
+
+        switch(key)
+        {
+          case 'ok':
+          case 'confirm':
+            button.addClass('bootbox-accept');
+            break;
+
+          case 'cancel':
+            button.addClass('bootbox-cancel');
+            break;
+        }
+
+        button.html(b.label);
+        footer.append(button);
+
+        callbacks[key] = b.callback;
+      });
+
+      body.after(footer);
+    }
+
+    if (options.animate === true) {
+      dialog.addClass('fade');
+    }
+
+    if (options.className) {
+      dialog.addClass(options.className);
+    }
+
+    if (options.size) {
+      // Requires Bootstrap 3.1.0 or higher
+      if (options.fullBootstrapVersion.substring(0, 3) < '3.1') {
+        console.warn('"size" requires Bootstrap 3.1.0 or higher. You appear to be using ' + options.fullBootstrapVersion + '. Please upgrade to use this option.');
+      }
+
+      switch(options.size)
+      {
+        case 'small':
+        case 'sm':
+          innerDialog.addClass('modal-sm');
+          break;
+
+        case 'large':
+        case 'lg':
+          innerDialog.addClass('modal-lg');
+          break;
+
+        case 'xl':
+        case 'extra-large':
+          // Requires Bootstrap 4.2.0 or higher
+          if (options.fullBootstrapVersion.substring(0, 3) < '4.2') {
+            console.warn('Using size "xl"/"extra-large" requires Bootstrap 4.2.0 or higher. You appear to be using ' + options.fullBootstrapVersion + '. Please upgrade to use this option.');
+          }
+          innerDialog.addClass('modal-xl');
+          break;
+      }
+    }
+
+    if(options.scrollable){
+      // Requires Bootstrap 4.3.0 or higher
+      if (options.fullBootstrapVersion.substring(0, 3) < '4.3') {
+        console.warn('Using "scrollable" requires Bootstrap 4.3.0 or higher. You appear to be using ' + options.fullBootstrapVersion + '. Please upgrade to use this option.');
+      }
+
+      innerDialog.addClass('modal-dialog-scrollable');
+    }
+
+    if (options.title) {
+      body.before(header);
+      dialog.find('.modal-title').html(options.title);
+    }
+
+    if (options.closeButton) {
+      var closeButton = $(templates.closeButton);
+
+      if (options.title) {
+        if (options.bootstrap > 3) {
+          dialog.find('.modal-header').append(closeButton);
+        }
+        else {
+          dialog.find('.modal-header').prepend(closeButton);
+        }
+      } else {
+        closeButton.prependTo(body);
+      }
+    }
+
+    if(options.centerVertical){
+      // Requires Bootstrap 4.0.0-beta.3 or higher
+      if (options.fullBootstrapVersion < '4.0.0') {
+        console.warn('"centerVertical" requires Bootstrap 4.0.0-beta.3 or higher. You appear to be using ' + options.fullBootstrapVersion + '. Please upgrade to use this option.');
+      }
+
+      innerDialog.addClass('modal-dialog-centered');
+    }
+
+    // Bootstrap event listeners; these handle extra
+    // setup & teardown required after the underlying
+    // modal has performed certain actions.
+
+    // make sure we unbind any listeners once the dialog has definitively been dismissed
+      dialog.one('hide.bs.modal', function (e) {
+        if (e.target === this) {
+          dialog.off('escape.close.bb');
+          dialog.off('click');
+        }
+    });
+
+    dialog.one('hidden.bs.modal', function (e) {
+      // ensure we don't accidentally intercept hidden events triggered
+      // by children of the current dialog. We shouldn't need to handle this anymore, 
+      // now that Bootstrap namespaces its events, but still worth doing.
+      if (e.target === this) {
+        dialog.remove();
+      }
+    });
+
+    dialog.one('shown.bs.modal', function () {
+      dialog.find('.bootbox-accept').first().trigger('focus');
+    });
+
+    // Bootbox event listeners; used to decouple some
+    // behaviours from their respective triggers
+
+    if (options.backdrop !== 'static') {
+      // A boolean true/false according to the Bootstrap docs
+      // should show a dialog the user can dismiss by clicking on
+      // the background.
+      // We always only ever pass static/false to the actual
+      // $.modal function because with "true" we can't trap
+      // this event (the .modal-backdrop swallows it)
+      // However, we still want to sort of respect true
+      // and invoke the escape mechanism instead
+      dialog.on('click.dismiss.bs.modal', function (e) {
+        // @NOTE: the target varies in >= 3.3.x releases since the modal backdrop
+        // moved *inside* the outer dialog rather than *alongside* it
+        if (dialog.children('.modal-backdrop').length) {
+          e.currentTarget = dialog.children('.modal-backdrop').get(0);
+        }
+
+        if (e.target !== e.currentTarget) {
+          return;
+        }
+
+        dialog.trigger('escape.close.bb');
+      });
+    }
+
+    dialog.on('escape.close.bb', function (e) {
+      // the if statement looks redundant but it isn't; without it
+      // if we *didn't* have an onEscape handler then processCallback
+      // would automatically dismiss the dialog
+      if (callbacks.onEscape) {
+        processCallback(e, dialog, callbacks.onEscape);
+      }
+    });
+
+
+    dialog.on('click', '.modal-footer button:not(.disabled)', function (e) {
+      var callbackKey = $(this).data('bb-handler');
+
+      if (callbackKey !== undefined) {
+        // Only process callbacks for buttons we recognize:
+        processCallback(e, dialog, callbacks[callbackKey]);
+     }
+    });
+
+    dialog.on('click', '.bootbox-close-button', function (e) {
+      // onEscape might be falsy but that's fine; the fact is
+      // if the user has managed to click the close button we
+      // have to close the dialog, callback or not
+      processCallback(e, dialog, callbacks.onEscape);
+    });
+
+    dialog.on('keyup', function (e) {
+      if (e.which === 27) {
+        dialog.trigger('escape.close.bb');
+      }
+    });
+
+    // the remainder of this method simply deals with adding our
+    // dialogent to the DOM, augmenting it with Bootstrap's modal
+    // functionality and then giving the resulting object back
+    // to our caller
+
+    $(options.container).append(dialog);
+
+    dialog.modal({
+      backdrop: options.backdrop ? 'static' : false,
+      keyboard: false,
+      show: false
+    });
+
+    if (options.show) {
+      dialog.modal('show');
+    }
+
+    return dialog;
+  };
+
+
+  // Helper function to simulate the native alert() behavior. **NOTE**: This is non-blocking, so any
+  // code that must happen after the alert is dismissed should be placed within the callback function 
+  // for this alert.
+  exports.alert = function () {
+    var options;
+
+    options = mergeDialogOptions('alert', ['ok'], ['message', 'callback'], arguments);
+
+    // @TODO: can this move inside exports.dialog when we're iterating over each
+    // button and checking its button.callback value instead?
+    if (options.callback && !$.isFunction(options.callback)) {
+      throw new Error('alert requires the "callback" property to be a function when provided');
+    }
+
+    // override the ok and escape callback to make sure they just invoke
+    // the single user-supplied one (if provided)
+    options.buttons.ok.callback = options.onEscape = function () {
+      if ($.isFunction(options.callback)) {
+        return options.callback.call(this);
+      }
+
+      return true;
+    };
+
+    return exports.dialog(options);
+  };
+
+
+  // Helper function to simulate the native confirm() behavior. **NOTE**: This is non-blocking, so any
+  // code that must happen after the confirm is dismissed should be placed within the callback function 
+  // for this confirm.
+  exports.confirm = function () {
+    var options;
+
+    options = mergeDialogOptions('confirm', ['cancel', 'confirm'], ['message', 'callback'], arguments);
+
+    // confirm specific validation; they don't make sense without a callback so make
+    // sure it's present
+    if (!$.isFunction(options.callback)) {
+      throw new Error('confirm requires a callback');
+    }
+
+    // overrides; undo anything the user tried to set they shouldn't have
+    options.buttons.cancel.callback = options.onEscape = function () {
+      return options.callback.call(this, false);
+    };
+
+    options.buttons.confirm.callback = function () {
+      return options.callback.call(this, true);
+    };
+
+    return exports.dialog(options);
+  };
+
+
+  // Helper function to simulate the native prompt() behavior. **NOTE**: This is non-blocking, so any
+  // code that must happen after the prompt is dismissed should be placed within the callback function 
+  // for this prompt.
+  exports.prompt = function () {
+    var options;
+    var promptDialog;
+    var form;
+    var input;
+    var shouldShow;
+    var inputOptions;
+
+    // we have to create our form first otherwise
+    // its value is undefined when gearing up our options
+    // @TODO this could be solved by allowing message to
+    // be a function instead...
+    form = $(templates.form);
+
+    // prompt defaults are more complex than others in that
+    // users can override more defaults
+    options = mergeDialogOptions('prompt', ['cancel', 'confirm'], ['title', 'callback'], arguments);
+
+    if (!options.value) {
+      options.value = defaults.value;
+    }
+
+    if (!options.inputType) {
+      options.inputType = defaults.inputType;
+    }
+
+    // capture the user's show value; we always set this to false before
+    // spawning the dialog to give us a chance to attach some handlers to
+    // it, but we need to make sure we respect a preference not to show it
+    shouldShow = (options.show === undefined) ? defaults.show : options.show;
+    // This is required prior to calling the dialog builder below - we need to 
+    // add an event handler just before the prompt is shown
+    options.show = false;
+
+    // Handles the 'cancel' action
+    options.buttons.cancel.callback = options.onEscape = function () {
+      return options.callback.call(this, null);
+    };
+
+    // Prompt submitted - extract the prompt value. This requires a bit of work, 
+    // given the different input types available.
+    options.buttons.confirm.callback = function () {
+      var value;
+
+      if (options.inputType === 'checkbox') {
+        value = input.find('input:checked').map(function () {
+          return $(this).val();
+        }).get();
+      } else if (options.inputType === 'radio') {
+        value = input.find('input:checked').val();
+      }
+      else {
+        if (input[0].checkValidity && !input[0].checkValidity()) {
+          // prevents button callback from being called
+          return false;
+        } else {
+          if (options.inputType === 'select' && options.multiple === true) {
+            value = input.find('option:selected').map(function () {
+              return $(this).val();
+            }).get();
+          }
+          else{
+            value = input.val();
+          }
+        }
+      }
+
+      return options.callback.call(this, value);
+    };
+
+    // prompt-specific validation
+    if (!options.title) {
+      throw new Error('prompt requires a title');
+    }
+
+    if (!$.isFunction(options.callback)) {
+      throw new Error('prompt requires a callback');
+    }
+
+    if (!templates.inputs[options.inputType]) {
+      throw new Error('Invalid prompt type');
+    }
+
+    // create the input based on the supplied type
+    input = $(templates.inputs[options.inputType]);
+
+    switch (options.inputType) {
+      case 'text':
+      case 'textarea':
+      case 'email':
+      case 'password':
+        input.val(options.value);
+        
+        if (options.placeholder) {
+          input.attr('placeholder', options.placeholder);
+        }
+    
+        if (options.pattern) {
+          input.attr('pattern', options.pattern);
+        }
+    
+        if (options.maxlength) {
+          input.attr('maxlength', options.maxlength);
+        }
+
+        if (options.required) {
+          input.prop({ 'required': true });
+        }
+        
+        if (options.rows && !isNaN(parseInt(options.rows))) {
+          if(options.inputType === 'textarea'){
+            input.attr({ 'rows': options.rows });
+          }
+        }
+
+        break;
+
+
+      case 'date':
+      case 'time':
+      case 'number':
+      case 'range':
+        input.val(options.value);
+        
+        if (options.placeholder) {
+          input.attr('placeholder', options.placeholder);
+        }
+    
+        if (options.pattern) {
+          input.attr('pattern', options.pattern);
+        }
+
+        if (options.required) {
+          input.prop({ 'required': true });
+        }
+        
+        // These input types have extra attributes which affect their input validation.
+        // Warning: For most browsers, date inputs are buggy in their implementation of 'step', so 
+        // this attribute will have no effect. Therefore, we don't set the attribute for date inputs.
+        // @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#Setting_maximum_and_minimum_dates
+        if (options.inputType !== 'date') {
+          if (options.step) {
+            if (options.step === 'any' || (!isNaN(options.step) && parseFloat(options.step) > 0)) {
+              input.attr('step', options.step);
+            }
+            else {
+              throw new Error('"step" must be a valid positive number or the value "any". See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-step for more information.');
+            }
+          }
+        }
+
+        if(minAndMaxAreValid(options.inputType, options.min, options.max)){
+          if(options.min !== undefined){
+            input.attr('min', options.min);
+          }
+          if(options.max !== undefined){
+            input.attr('max', options.max);
+          }
+        }
+
+        break;
+
+
+      case 'select':
+        var groups = {};
+        inputOptions = options.inputOptions || [];
+
+        if (!$.isArray(inputOptions)) {
+          throw new Error('Please pass an array of input options');
+        }
+
+        if (!inputOptions.length) {
+          throw new Error('prompt with "inputType" set to "select" requires at least one option');
+        }
+
+        // placeholder is not actually a valid attribute for select,
+        // but we'll allow it, assuming it might be used for a plugin
+        if (options.placeholder) {
+          input.attr('placeholder', options.placeholder);
+        }
+        
+        if (options.required) {
+          input.prop({ 'required': true });
+        }
+        
+        if (options.multiple) {
+          input.prop({ 'multiple': true });
+        }
+        
+        each(inputOptions, function (_, option) {
+          // assume the element to attach to is the input...
+          var elem = input;
+
+          if (option.value === undefined || option.text === undefined) {
+            throw new Error('each option needs a "value" property and a "text" property');
+          }
+
+          // ... but override that element if this option sits in a group
+
+          if (option.group) {
+            // initialise group if necessary
+            if (!groups[option.group]) {
+              groups[option.group] = $('<optgroup />').attr('label', option.group);
+            }
+
+            elem = groups[option.group];
+          }
+
+          var o = $(templates.option);
+          o.attr('value', option.value).text(option.text);
+          elem.append(o);
+        });
+
+        each(groups, function (_, group) {
+          input.append(group);
+        });
+
+        // safe to set a select's value as per a normal input
+        input.val(options.value);
+
+        break;
+
+
+      case 'checkbox':
+        var checkboxValues = $.isArray(options.value) ? options.value : [options.value];
+        inputOptions = options.inputOptions || [];
+
+        if (!inputOptions.length) {
+          throw new Error('prompt with "inputType" set to "checkbox" requires at least one option');
+        }
+
+        // checkboxes have to nest within a containing element, so
+        // they break the rules a bit and we end up re-assigning
+        // our 'input' element to this container instead
+        input = $('<div class="bootbox-checkbox-list"></div>');
+
+        each(inputOptions, function (_, option) {
+          if (option.value === undefined || option.text === undefined) {
+            throw new Error('each option needs a "value" property and a "text" property');
+          }
+
+          var checkbox = $(templates.inputs[options.inputType]);
+
+          checkbox.find('input').attr('value', option.value);
+          checkbox.find('label').append('\n' + option.text);
+
+          // we've ensured values is an array so we can always iterate over it
+          each(checkboxValues, function (_, value) {
+            if (value === option.value) {
+              checkbox.find('input').prop('checked', true);
+            }
+          });
+
+          input.append(checkbox);
+        });
+        break;
+
+
+      case 'radio':
+        // Make sure that value is not an array (only a single radio can ever be checked)
+        if (options.value !== undefined && $.isArray(options.value)) {
+          throw new Error('prompt with "inputType" set to "radio" requires a single, non-array value for "value"');
+        }
+
+        inputOptions = options.inputOptions || [];
+
+        if (!inputOptions.length) {
+          throw new Error('prompt with "inputType" set to "radio" requires at least one option');
+        }
+
+        // Radiobuttons have to nest within a containing element, so
+        // they break the rules a bit and we end up re-assigning
+        // our 'input' element to this container instead
+        input = $('<div class="bootbox-radiobutton-list"></div>');
+
+        // Radiobuttons should always have an initial checked input checked in a "group".
+        // If value is undefined or doesn't match an input option, select the first radiobutton
+        var checkFirstRadio = true;
+
+        each(inputOptions, function (_, option) {
+          if (option.value === undefined || option.text === undefined) {
+            throw new Error('each option needs a "value" property and a "text" property');
+          }
+
+          var radio = $(templates.inputs[options.inputType]);
+
+          radio.find('input').attr('value', option.value);
+          radio.find('label').append('\n' + option.text);
+
+          if (options.value !== undefined) {
+            if (option.value === options.value) {
+              radio.find('input').prop('checked', true);
+              checkFirstRadio = false;
+            }
+          }
+
+          input.append(radio);
+        });
+
+        if (checkFirstRadio) {
+          input.find('input[type="radio"]').first().prop('checked', true);
+        }
+        break;
+    }
+
+    // now place it in our form
+    form.append(input);
+
+    form.on('submit', function (e) {
+      e.preventDefault();
+      // Fix for SammyJS (or similar JS routing library) hijacking the form post.
+      e.stopPropagation();
+
+      // @TODO can we actually click *the* button object instead?
+      // e.g. buttons.confirm.click() or similar
+      promptDialog.find('.bootbox-accept').trigger('click');
+    });
+
+    if ($.trim(options.message) !== '') {
+      // Add the form to whatever content the user may have added.
+      var message = $(templates.promptMessage).html(options.message);
+      form.prepend(message);
+      options.message = form;
+    }
+    else {
+      options.message = form;
+    }
+
+    // Generate the dialog
+    promptDialog = exports.dialog(options);
+
+    // clear the existing handler focusing the submit button...
+    promptDialog.off('shown.bs.modal');
+
+    // ...and replace it with one focusing our input, if possible
+    promptDialog.on('shown.bs.modal', function () {
+      // need the closure here since input isn't
+      // an object otherwise
+      input.focus();
+    });
+
+    if (shouldShow === true) {
+      promptDialog.modal('show');
+    }
+
+    return promptDialog;
+  };
+
+
+  // INTERNAL FUNCTIONS
+  // *************************************************************************************************************
+
+  // Map a flexible set of arguments into a single returned object
+  // If args.length is already one just return it, otherwise
+  // use the properties argument to map the unnamed args to
+  // object properties.
+  // So in the latter case:
+  //  mapArguments(["foo", $.noop], ["message", "callback"])
+  //  -> { message: "foo", callback: $.noop }
+  function mapArguments(args, properties) {
+    var argn = args.length;
+    var options = {};
+
+    if (argn < 1 || argn > 2) {
+      throw new Error('Invalid argument length');
+    }
+
+    if (argn === 2 || typeof args[0] === 'string') {
+      options[properties[0]] = args[0];
+      options[properties[1]] = args[1];
+    } else {
+      options = args[0];
+    }
+
+    return options;
+  }
+
+
+  //  Merge a set of default dialog options with user supplied arguments
+  function mergeArguments(defaults, args, properties) {
+    return $.extend(
+      // deep merge
+      true,
+      // ensure the target is an empty, unreferenced object
+      {},
+      // the base options object for this type of dialog (often just buttons)
+      defaults,
+      // args could be an object or array; if it's an array properties will
+      // map it to a proper options object
+      mapArguments(
+        args,
+        properties
+      )
+    );
+  }
+
+
+  //  This entry-level method makes heavy use of composition to take a simple
+  //  range of inputs and return valid options suitable for passing to bootbox.dialog
+  function mergeDialogOptions(className, labels, properties, args) {
+    var locale;
+    if(args && args[0]){
+      locale = args[0].locale || defaults.locale;
+      var swapButtons = args[0].swapButtonOrder || defaults.swapButtonOrder;
+
+      if(swapButtons){
+        labels = labels.reverse();
+      }
+    }
+
+    //  build up a base set of dialog properties
+    var baseOptions = {
+      className: 'bootbox-' + className,
+      buttons: createLabels(labels, locale)
+    };
+
+    // Ensure the buttons properties generated, *after* merging
+    // with user args are still valid against the supplied labels
+    return validateButtons(
+      // merge the generated base properties with user supplied arguments
+      mergeArguments(
+        baseOptions,
+        args,
+        // if args.length > 1, properties specify how each arg maps to an object key
+        properties
+      ),
+      labels
+    );
+  }
+
+
+  //  Checks each button object to see if key is valid. 
+  //  This function will only be called by the alert, confirm, and prompt helpers. 
+  function validateButtons(options, buttons) {
+    var allowedButtons = {};
+    each(buttons, function (key, value) {
+      allowedButtons[value] = true;
+    });
+
+    each(options.buttons, function (key) {
+      if (allowedButtons[key] === undefined) {
+        throw new Error('button key "' + key + '" is not allowed (options are ' + buttons.join(' ') + ')');
+      }
+    });
+
+    return options;
+  }
+
+
+
+  //  From a given list of arguments, return a suitable object of button labels.
+  //  All this does is normalise the given labels and translate them where possible.
+  //  e.g. "ok", "confirm" -> { ok: "OK", cancel: "Annuleren" }
+  function createLabels(labels, locale) {
+    var buttons = {};
+
+    for (var i = 0, j = labels.length; i < j; i++) {
+      var argument = labels[i];
+      var key = argument.toLowerCase();
+      var value = argument.toUpperCase();
+
+      buttons[key] = {
+        label: getText(value, locale)
+      };
+    }
+
+    return buttons;
+  }
+
+
+
+  //  Get localized text from a locale. Defaults to 'en' locale if no locale 
+  //  provided or a non-registered locale is requested
+  function getText(key, locale) {
+    var labels = locales[locale];
+
+    return labels ? labels[key] : locales.en[key];
+  }
+
+
+
+  //  Filter and tidy up any user supplied parameters to this dialog.
+  //  Also looks for any shorthands used and ensures that the options
+  //  which are returned are all normalized properly
+  function sanitize(options) {
+    var buttons;
+    var total;
+
+    if (typeof options !== 'object') {
+      throw new Error('Please supply an object of options');
+    }
+
+    if (!options.message) {
+      throw new Error('"message" option must not be null or an empty string.');
+    }
+
+    // make sure any supplied options take precedence over defaults
+    options = $.extend({}, defaults, options);
+
+    // no buttons is still a valid dialog but it's cleaner to always have
+    // a buttons object to iterate over, even if it's empty
+    if (!options.buttons) {
+      options.buttons = {};
+    }
+
+    buttons = options.buttons;
+
+    total = getKeyLength(buttons);
+
+    each(buttons, function (key, button, index) {
+      if ($.isFunction(button)) {
+        // short form, assume value is our callback. Since button
+        // isn't an object it isn't a reference either so re-assign it
+        button = buttons[key] = {
+          callback: button
+        };
+      }
+
+      // before any further checks make sure by now button is the correct type
+      if ($.type(button) !== 'object') {
+        throw new Error('button with key "' + key + '" must be an object');
+      }
+
+      if (!button.label) {
+        // the lack of an explicit label means we'll assume the key is good enough
+        button.label = key;
+      }
+
+      if (!button.className) {     
+        var isPrimary = false;
+        if(options.swapButtonOrder){
+          isPrimary = index === 0;
+        }
+        else{
+          isPrimary = index === total-1;
+        }
+
+        if (total <= 2 && isPrimary) {
+          // always add a primary to the main option in a one or two-button dialog
+          button.className = 'btn-primary';
+        } else {
+          // adding both classes allows us to target both BS3 and BS4 without needing to check the version
+          button.className = 'btn-secondary btn-default';
+        }
+      }
+    });
+
+    return options;
+  }
+
+
+  //  Returns a count of the properties defined on the object
+  function getKeyLength(obj) {
+    return Object.keys(obj).length;
+  }
+
+
+  //  Tiny wrapper function around jQuery.each; just adds index as the third parameter
+  function each(collection, iterator) {
+    var index = 0;
+    $.each(collection, function (key, value) {
+      iterator(key, value, index++);
+    });
+  }
+
+
+  //  Handle the invoked dialog callback
+  function processCallback(e, dialog, callback) {
+    e.stopPropagation();
+    e.preventDefault();
+
+    // by default we assume a callback will get rid of the dialog,
+    // although it is given the opportunity to override this
+
+    // so, if the callback can be invoked and it *explicitly returns false*
+    // then we'll set a flag to keep the dialog active...
+    var preserveDialog = $.isFunction(callback) && callback.call(dialog, e) === false;
+
+    // ... otherwise we'll bin it
+    if (!preserveDialog) {
+      dialog.modal('hide');
+    }
+  }
+  
+  // Validate `min` and `max` values based on the current `inputType` value
+  function minAndMaxAreValid(type, min, max){
+    var result = false;
+    var minValid = true;
+    var maxValid = true;
+
+    if (type === 'date') {
+      if (min !== undefined && !(minValid = dateIsValid(min))) {
+        console.warn('Browsers which natively support the "date" input type expect date values to be of the form "YYYY-MM-DD" (see ISO-8601 https://www.iso.org/iso-8601-date-and-time-format.html). Bootbox does not enforce this rule, but your min value may not be enforced by this browser.');
+      }
+      else if (max !== undefined && !(maxValid = dateIsValid(max))) {
+        console.warn('Browsers which natively support the "date" input type expect date values to be of the form "YYYY-MM-DD" (see ISO-8601 https://www.iso.org/iso-8601-date-and-time-format.html). Bootbox does not enforce this rule, but your max value may not be enforced by this browser.');
+      }
+    }
+    else if (type === 'time') {
+      if (min !== undefined && !(minValid = timeIsValid(min))) {
+        throw new Error('"min" is not a valid time. See https://www.w3.org/TR/2012/WD-html-markup-20120315/datatypes.html#form.data.time for more information.');
+      }
+      else if (max !== undefined && !(maxValid = timeIsValid(max))) {
+        throw new Error('"max" is not a valid time. See https://www.w3.org/TR/2012/WD-html-markup-20120315/datatypes.html#form.data.time for more information.');
+      }
+    }
+    else {
+      if (min !== undefined && isNaN(min)) {
+        minValid = false;
+        throw new Error('"min" must be a valid number. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-min for more information.');
+      }
+
+      if (max !== undefined && isNaN(max)) {
+        maxValid = false;
+        throw new Error('"max" must be a valid number. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-max for more information.');
+      }
+    }
+    
+    if(minValid && maxValid){
+      if(max <= min){
+        throw new Error('"max" must be greater than "min". See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-max for more information.');
+      }
+      else{
+        result = true;
+      }
+    }
+
+    return result;
+  }
+
+  function timeIsValid(value){
+    return /([01][0-9]|2[0-3]):[0-5][0-9]?:[0-5][0-9]/.test(value);
+  }
+
+  function dateIsValid(value){
+    return /(\d{4})-(\d{2})-(\d{2})/.test(value);
+  }
+
+
+  //  Register the default locale
+  exports.addLocale('en', {
+    OK: 'OK',
+    CANCEL: 'Cancel',
+    CONFIRM: 'OK'
+  });
+
+
+  //  The Bootbox object
+  return exports;
+}));

+ 32 - 0
core/src/web/staticres/js/kindeditor/themes/course/iframe_course.css

@@ -0,0 +1,32 @@
+@charset "UTF-8";
+.c-title {
+  height: 48px;
+  line-height: 48px;
+  background-color: #F6F6F6;
+  font-size: 16px;
+  padding-left: 20px;
+  margin: 20px 0;
+  color: #686868;
+  position: relative;
+}
+
+.c-title:first-of-type {
+  margin-top: 0;
+}
+
+.c-title:after {
+  content: '';
+  position: absolute;
+  top: 50%;
+  left: 0;
+  height: 20px;
+  width: 2px;
+  margin-top: -10px;
+  background-color: #2CB7CA;
+}
+
+p {
+  line-height: 24px;
+  text-align: justify;
+  font-size: 14px;
+}

BIN
core/src/web/staticres/upload/2019/12/29/20191229172913012213dsp1H.jpg


BIN
core/src/web/staticres/upload/2019/12/29/201912291729380122852891x.png


+ 412 - 0
core/src/web/templates/manage/course/content.html

@@ -0,0 +1,412 @@
+<html>
+<head>
+    <title>课程详情</title>
+    {{include "/common/inc.html"}}
+    <link href="{{Msg "seo" "cdn"}}/css/message.css" rel="stylesheet">
+    <link rel="stylesheet" href="{{Msg "seo" "cdn"}}/js/kindeditor/themes/default/default.css"/>
+    <script charset="utf-8" src="{{Msg "seo" "cdn"}}/js/kindeditor/kindeditor-all.js"></script>
+    <script charset="utf-8" src="{{Msg "seo" "cdn"}}/js/kindeditor/kinditem.js"></script>
+    <script src="/js/validform-min.js"></script>
+    <script type="text/javascript" src="/js/zDrag.js"></script>
+    <script type="text/javascript" src="/js/zDialog.js"></script>
+    <script src="{{Msg "seo" "cdn"}}/js/jquery.cityselect.js"></script>
+    <script type="text/javascript" src="{{Msg "seo" "cdn"}}/js/My97DatePicker/WdatePicker.js"></script>
+    <style type="text/css">
+        .widget-content {
+            table-layout: fixed;
+            font-size: 14px;
+        }
+
+        #course {
+            background-color: #f5f5f5;
+        }
+
+        #tr1 td img {
+            border: 1px solid #999999;
+            width: 78px;
+            height: 78px;
+            margin: 0;
+            padding: 0;
+            margin-bottom: 20px;
+        }
+
+        .delbtn {
+            position: absolute;
+            margin: 0 0 0 -10px;
+            padding: 0 0 0 0;
+            background-color: #00ffff;
+            cursor: pointer;
+        }
+
+        .delbtn img {
+            height: 15px !important;
+            width: 15px !important;
+            margin-right: -20px !important;
+            margin-top: -8px !important;
+        }
+
+        /*修改弹框样式*/
+        .modal {
+            top: 33%;
+        }
+
+        .modal-dialog {
+            width: 400px;
+            text-align: center;
+        }
+
+        .modal-dialog .bootbox-close-button.close {
+            display: none;
+        }
+
+        .modal-dialog .modal-header .modal-title {
+            color: #4E5051;
+            font-size: 18px;
+        }
+
+        .modal-dialog .bootbox-body {
+            color: #4E5051;
+            font-size: 14px;
+        }
+
+        .modal-dialog .modal-header,
+        .modal-dialog .modal-footer {
+            border: none;
+
+        }
+
+        .modal-dialog .modal-footer {
+            display: flex;
+            justify-content: space-between;
+        }
+
+        .modal-dialog .modal-footer .bootbox-cancel {
+            width: 110px;
+            height: 38px;
+            left: 24px;
+            top: 112px;
+
+            background: #C2C2C2;
+            border-radius: 4px;
+            border-color: #C2C2C2;
+            color: #ffff;
+        }
+
+        .modal-dialog .modal-footer .bootbox-accept {
+            width: 110px;
+            height: 38px;
+            left: 226px;
+            top: 112px;
+
+            background: #4DB443;
+            border-radius: 4px;
+            border-color: #4DB443;
+            color: #ffff;
+        }
+    </style>
+</head>
+<body>
+
+{{include "/manage/audithead.html"}}
+<!-- 中间 -->
+<div class="row" style="width:96%; margin:0 auto; margin-top:10px;">
+    <div>
+        {{include "/manage/slider.html"}}
+
+        <div id="content" class="send">
+            <div class="widget-box">
+                <div class="widget-content nopadding">
+                    <div class="head">
+                        <div class="title">课程信息</div>
+                        <div style="clear:both;"></div>
+                    </div>
+                    <div class="sendform">
+                        <form class="registerform form-horizontal" role="form" method="post">
+                            <div class="form-group">
+                                <label class="col-sm-2 control-label" for="name">课程类型:</label>
+                                <div class="col-sm-10">
+                                    <div class="dropdown col-sm-5">
+                                        <div class="dropdown col-sm-12">
+                                            <div class="form-group" style="margin-left: 0">
+                                                <select class="form-control" id="courseType">
+                                                    <option>招标管理课程</option>
+                                                    <option>投标实务课程</option>
+                                                </select>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="form-group">
+                                <label class="col-sm-2 control-label" for="name">课程名称:</label>
+                                <div class="col-sm-10" id="fbt">
+                                    <input class="form-control" id="courseName" value="{{.T.name}}"/>
+                                </div>
+                            </div>
+
+                            <div class="form-group">
+                                <label class="col-sm-2 control-label" for="name">课程地点:</label>
+                                <div class="col-sm-5" id="fbt">
+                                    <input class="form-control" id="courseAddress" value="{{.T.address}}"/>
+                                </div>
+                            </div>
+
+                            <div class="form-group">
+                                <label class="col-sm-2 control-label" for="name">课程金额:</label>
+                                <div class="col-sm-5" id="fbt">
+                                    <input class="form-control" id="coursePrice" value=""/>
+                                </div>
+                            </div>
+
+
+                            <div class="form-group">
+                                <label class="col-sm-2 control-label" for="name">课程时间:</label>
+                                <div class="col-sm-5" id="fbt">
+                                    <input style="background:#fff url({{Msg "seo" "cdn"}}/images/datePicker.gif) no-repeat right;"
+                                           id="courseStart" datatype="*"
+                                           onFocus="WdatePicker({lang:'zh-cn',dateFmt:'yyyy-MM-dd HH:mm:ss'})"
+                                           type="text" class="form-control" placeholder="请选择课程开始时间"
+                                           onClick="WdatePicker({dateFmt:'yyyy-MM-dd HH:mm:ss'})" readonly="ture"
+                                           value="{{.T.starttime}}"/>
+
+                                </div>
+                                <div class="col-sm-5" id="fbt">
+                                    <input style="background:#fff url({{Msg "seo" "cdn"}}/images/datePicker.gif) no-repeat right;"
+                                           id="courseEnd" datatype="*"
+                                           onFocus="WdatePicker({lang:'zh-cn',dateFmt:'yyyy-MM-dd HH:mm:ss'})"
+                                           type="text" class="form-control" placeholder="请选择课程结束时间"
+                                           onClick="WdatePicker({dateFmt:'yyyy-MM-dd HH:mm:ss'})" readonly="ture"
+                                           value="{{.T.endtime}}"/>
+
+                                </div>
+                            </div>
+
+                            <div class="form-group">
+                                <label class="col-sm-2 control-label" for="name">发布时间:</label>
+                                <div class="col-sm-5" id="fbt">
+                                    <input style="background:#fff url({{Msg "seo" "cdn"}}/images/datePicker.gif) no-repeat right;"
+                                           id="coursePushtime" datatype="*"
+                                           onFocus="WdatePicker({lang:'zh-cn',dateFmt:'yyyy-MM-dd HH:mm:ss'})"
+                                           type="text" class="form-control" placeholder="请输入发布时间"
+                                           onClick="WdatePicker({dateFmt:'yyyy-MM-dd HH:mm:ss'})" readonly="ture"
+                                           value="{{.T.publishtime}}"/>
+                                </div>
+                            </div>
+
+                        </form>
+                    </div>
+
+                    <div class="head">
+                        <div class="title">课程内容</div>
+                        <div style="clear:both;"></div>
+                    </div>
+
+                    <div style="width: 800px;margin: 0 auto;padding-top: 20px">
+                        <textarea name="s_content" id="s_content"></textarea>
+                    </div>
+
+
+                    <div class="form-group" style="margin: 10px 0px 60px 0px">
+                        <label class="col-sm-2 control-label" for="name"></label>
+                        <div class="col-sm-10" id="submit">
+                            {{ if  ne .T.doType "edit"}}
+                                <button class="btn btn-success" onclick="submit(this, 'publish')" type="button">立即发布
+                                </button>
+                            {{end}}
+                            <button class="btn " type="button" onclick="submit(this, 'save')"
+                                    style="margin-left: 60px;color: #4DB443;border-color: #4DB443;background-color: #fff">
+                                保存
+                            </button>
+                            {{ if  eq .T.doType "edit"}}
+                                <button class="btn btn-info" type="button" onclick="preview(0)"
+                                        style="margin-left: 30px;">
+                                    pc预览
+                                </button>
+                                <button class="btn btn-info" type="button" onclick="preview(1)">
+                                    微信预览
+                                </button>
+                                <span style="font-size: 12px;color: #ff00008a;">保存后预览生效</span>
+                            {{end}}
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+
+        </div>
+
+    </div>
+</div>
+{{include "/common/bottom.html"}}
+<script type="text/javascript" src="/js/bootbox.js"></script>
+<script>
+    var c_type = "";
+    var name = "";
+    var address = "";
+    var price = {{.T.price}};
+    var starttime = "";
+    var endtime = "";
+    var publishtime = "";
+    var content = {{.T.content}};
+    var id = {{.T.id}};
+    var Dotype ={{.T.doType}};
+    var editor;
+    var defaultHtml = "<h2 class=\"c-title\" id=\"a1\">课程介绍</h2>"
+        + "<p></p>"
+        + "<p></p>"
+
+        + "<h2 class=\"c-title\" id=\"a2\">课程大纲</h2>"
+        + "<p></p>"
+        + "<p></p>"
+
+        + "<h2 class=\"c-title\" id=\"a3\">购买须知</h2>"
+        + "<p></p>"
+        + "<p></p>"
+
+        + "<h2 class=\"c-title\" id=\"a4\">客户服务</h2>"
+        + "<p></p>"
+        + "<p></p>";
+
+    $(function () {
+        editor = KindEditor.create('textarea[name="s_content"]', {
+            id: "ke_editor",
+            items: ["source", "|", "undo", "redo", "|", "preview"],
+            allowFileManager: false,
+            filterMode: true,
+            cssPath: '/js/kindeditor/themes/course/iframe_course.css',
+            width: '800px',
+            height: '500px',
+            filterMode: false,
+            items: items_simp,
+            allowImageRemoteImageRemote: false,
+            uploadJson: '/filemanage/upload',
+            afterCreate: function () {
+                this.sync()
+            },
+            beforesubmit: function () {
+                this.sync()
+            },
+            afterBlur: function () {
+                this.sync()
+            }
+        });
+
+
+        //数据回显
+        var t_type ={{.T.type}}
+        if (t_type === 1) {
+            $("#courseType").val("招标管理课程")
+        } else if (t_type === 2) {
+            $("#courseType").val("投标实务课程")
+        }
+        if (price !== "") {
+            $("#coursePrice").val(parseInt(price) / 100)
+        }
+
+        if (!content) {
+            content = defaultHtml;
+        }
+        editor.html(content);
+        //数据回显end
+    });
+
+    //提交
+    function submit($Obj, flag) {
+        $($Obj).attr("disabled", "disabled");
+        c_type = $("#courseType").val();
+        name = $("#courseName").val();
+        address = $("#courseAddress").val();
+        price = parseInt(($("#coursePrice").val() * 100).toFixed(2));
+        starttime = $("#courseStart").val();
+        endtime = $("#courseEnd").val();
+        publishtime = $("#coursePushtime").val();
+        content = editor.html();
+
+        //数据校验
+        if (!(c_type && name && address && price && starttime && endtime && publishtime && content)) {
+            bootbox.alert("请输入完整信息");
+            $($Obj).removeAttr("disabled");
+            return
+        }
+        if (Date.parse(endtime) < Date.parse(starttime)) {
+            bootbox.alert("课程开始时间必须小于结束时间");
+            $($Obj).removeAttr("disabled");
+            return
+        }
+
+
+        var param = {
+            c_type: c_type == "招标管理课程" ? 1 : 2,
+            name: name,
+            address: address,
+            price: price,
+            starttime: starttime,
+            endtime: endtime,
+            publishtime: publishtime,
+            content: encodeURI(encodeURI(content)),
+            dotype: Dotype, //克隆 or 新增 or 修改
+            flag: flag//保存 or 立即发布
+        }
+
+        if (Dotype == "edit" && id != "") {
+            param["_id"] = id
+        }
+        $.post("/manage/course/doRequest", param, function (r) {
+            if (r.success) {
+                window.location.href = "/manage/course/index";
+            } else {
+                bootbox.alert(r.errMsg)
+            }
+        });
+        $($Obj).removeAttr("disabled");
+    }
+
+    //预览
+    function preview(flag) {
+        if (flag === 0) {
+            window.open("/manage/course/preview/pc/" + id)
+        } else (flag === 1)
+        {
+            window.open("/manage/course/preview/mobile/" + id)
+        }
+    }
+
+    var dateFormat = function (timestamp, formats) {
+        // formats格式包括
+        // 1. Y-m-d
+        // 2. Y-m-d H:i:s
+        // 3. Y年m月d日
+        // 4. Y年m月d日 H时i分
+        formats = formats || 'Y-m-d';
+
+        var zero = function (value) {
+            if (value < 10) {
+                return '0' + value;
+            }
+            return value;
+        };
+
+        var myDate = timestamp ? new Date(timestamp) : new Date();
+
+        var year = myDate.getFullYear();
+        var month = zero(myDate.getMonth() + 1);
+        var day = zero(myDate.getDate());
+
+        var hour = zero(myDate.getHours());
+        var minite = zero(myDate.getMinutes());
+        var second = zero(myDate.getSeconds());
+
+        return formats.replace(/Y|m|d|H|i|s/ig, function (matches) {
+            return ({
+                Y: year,
+                m: month,
+                d: day,
+                H: hour,
+                i: minite,
+                s: second
+            })[matches];
+        });
+    };
+</script>
+</body>
+</html>

+ 336 - 0
core/src/web/templates/manage/course/index.html

@@ -0,0 +1,336 @@
+<html>
+<head>
+    <title>课程列表</title>
+    {{include "/common/inc.html"}}
+    <script src="{{Msg "seo" "cdn"}}/js/jquery.cookie.js"></script>
+    <script src="/js/qfwtable.js"></script>
+    <style type="text/css">
+        #course {
+            background-color: #f5f5f5;
+        }
+
+        #content table {
+            table-layout: fixed;
+            border: 0px;
+            font-size: 14px;
+        }
+
+        #sidebar {
+            margin-left: 0px;
+        }
+
+        .table > thead > tr > th:nth-child(1) {
+            width: 10%;
+        }
+
+        .table > thead > tr > th:nth-child(2) {
+            width: 30%;
+        }
+
+        .table > thead > tr > th:nth-child(3) {
+            width: 15%;
+        }
+
+        .table > thead > tr > th:nth-child(4) {
+            width: 10%;
+        }
+
+        .table > thead > tr > th:nth-child(5) {
+            width: 15%;
+        }
+
+        .table > thead > tr > th:nth-child(6), .table > tbody > tr > td:nth-child(6) {
+            width: 20%;
+            /*text-align: center;*/
+        }
+
+
+        .table > thead > tr > th {
+            border: 0px;
+            font-size: 14px;
+        }
+
+        .table > tbody > tr > td {
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            border: 0px;
+            border-bottom: 1px dashed #999999;
+        }
+
+        .table > tbody > tr {
+            cursor: pointer;
+        }
+
+        .addCourse {
+            float: right;
+            margin-right: 20px;
+            color: #fff;
+            background-color: #38b44a;
+            border-color: #38b44a;
+            border-radius: 4px;
+            padding: 8px 12px;
+            margin: 5px;
+        }
+
+        .pagination > .active > a:hover, .pagination > .active > a:focus {
+            background-color: #18CC7D;
+        }
+
+        .editBtn {
+            display: flex;
+        }
+
+        .editBtn span {
+            padding: 3px 7px;
+            border: 1px solid;
+            border-radius: 4px;
+            margin: 0 3px;
+        }
+
+        .yellowStyle {
+            color: #EAB62F;
+            border-color: #EAB62F;
+        }
+
+        .greenStyle {
+            color: #4DB443;
+            border-color: #4DB443;
+        }
+
+        .redStyle {
+            color: #F5585C;
+            border-color: #F5585C;
+        }
+
+        /*修改弹框样式*/
+        .modal {
+            top: 33%;
+        }
+
+        .modal-dialog {
+            width: 400px;
+            text-align: center;
+        }
+
+        .modal-dialog .bootbox-close-button.close {
+            display: none;
+        }
+
+        .modal-dialog .modal-header .modal-title {
+            color: #4E5051;
+            font-size: 18px;
+        }
+
+        .modal-dialog .bootbox-body {
+            color: #4E5051;
+            font-size: 14px;
+        }
+
+        .modal-dialog .modal-header,
+        .modal-dialog .modal-footer {
+            border: none;
+
+        }
+
+        .modal-dialog .modal-footer{
+            display: flex;
+            justify-content: space-between;
+        }
+
+        .modal-dialog .modal-footer .bootbox-cancel{
+            width: 110px;
+            height: 38px;
+            left: 24px;
+            top: 112px;
+
+            background: #C2C2C2;
+            border-radius: 4px;
+            border-color: #C2C2C2;
+            color: #ffff;
+        }
+
+        .modal-dialog .modal-footer .bootbox-accept{
+            width: 110px;
+            height: 38px;
+            left: 226px;
+            top: 112px;
+
+            background: #4DB443;
+            border-radius: 4px;
+            border-color: #4DB443;
+            color: #ffff;
+        }
+
+
+    </style>
+</head>
+<body>
+{{include "/manage/audithead.html"}}
+<div class="row" style="width:96%; margin:0 auto;">
+    {{include "/manage/slider.html"}}
+    <div id="content">
+        <div id="audit"></div>
+    </div>
+</div>
+{{include "/common/bottom.html"}}
+</body>
+<script type="text/javascript" src="/js/bootbox.js"></script>
+<script>
+    $(function () {
+        $("#audit").datatable({
+            perPage: 10
+            ,
+            showPagination: true
+            ,
+            checkbox: "" //check radio
+            ,
+            checkboxHeader: false
+            ,
+            idField: "_id"
+            ,
+            classname: "table-hover"
+            ,
+            css: {"height": "550px"}
+            //,post:{"name":"ee"}
+            ,
+            buttons: ['<div class="addCourse">添加课程</div><div style="width:50%;margin:5px" class="input-group pull-right" id="search"><input type="text" id="searchtext" value=""  data-original-title="Search" class="form-control" placeholder="请输入检索条件"><span class="input-group-btn"><button class="btn btn-success" onclick="SearchContent()" data-original-title="Search" id="searchtip" type="button" style="height:38px;">检索</button></span></div><div style="margin:5px;" class="controls pull-right"><select class="form-control" id="select2" ><option value="">  选择课程类型  </option><option  value="1">  招标管理课程</option><option value="2">  投标实务课程 </option></select></div><div style="margin:5px;" class="controls pull-right"><select class="form-control" id="select1"><option value="">  选择报名状态  </option><option value="1">  报名中 </option><option value="-1">  已结束 </option><option value="0">  未发布 </option></select></div>']
+            ,
+            url: '/manage/course/list'
+            ,
+            columns: [
+                {
+                    title: "报名状态", field: "index", callback: function (data) {
+                        if (data.i_status == -1) {
+                            return "已结束"
+                        } else if (data.i_status === 1) {
+                            return "报名中"
+                        //} else if (data.i_status === -2) {
+                        //   return "已删除"
+                        } else {
+                            return "未发布"
+                        }
+                    }
+                },
+                {
+                    title: "课程名称", field: "s_name"
+                },
+                {
+                    title: "类型", field: "order_status", callback: function (data) {
+                        if (data.i_type === 1) {
+                            return "招标管理课程"
+                        } else if (data.i_type === 2) {
+                            return "投标实务课程"
+                        }
+                    }
+                },
+                {
+                    title: "地点", field: "s_address"
+                },
+                {
+                    title: "上线时间", field: "l_publishtime", callback: function (data) {
+                        var d = new Date(data.l_publishtime * 1000);
+                        return (d.getFullYear()) + "-" +
+                            (d.getMonth() + 1) + "-" +
+                            (d.getDate()) + " " +
+                            (d.getHours()) + ":" +
+                            (d.getMinutes()) + ":" +
+                            (d.getSeconds());
+                    }
+                },
+                {
+                    title: "操作", field: "applybill_company", callback: function (data) {
+                        //修改 克隆
+                        if (data._id != "") {
+                            var returnHtml = "<div class='editBtn'><span class='yellowStyle' onclick='window.location.href=\"" + "/manage/course/page/edit/" + data._id + "\"'>修改</span>" +
+                                "<span class='greenStyle' onclick='window.location.href=\"" + "/manage/course/page/copy/" + data._id + "\"'>克隆</span>"
+                            if (data.i_status == 1) {
+                                returnHtml += "<span class='redStyle' onclick='doCheck(\"off\",\"" + data._id + "\")'>下线</span>"
+                            } else if (data.i_status == 0) {
+                                returnHtml += "<span class='greenStyle' onclick='doCheck(\"on\",\"" + data._id + "\")'>上线</span>"
+                            }
+							//if (data.i_status == -2){
+							//	returnHtml += "<span class='greenStyle'>已删除</span>"
+							//}
+							
+							//if (data.i_status == 0||data.i_status == -1){
+							//	returnHtml += "<span class='greenStyle' onclick='doCheck(\"del\",\"" + data._id + "\")'>删除</span>"
+							//}
+                            return returnHtml + "</div>"
+                        }
+                    }
+                }
+            ]
+        });
+
+        $("select").change(function () {
+            var find = $("#audit").data("datatable");
+            if (!find.options.opost) find.options.opost = find.options.post || {};
+            find.options.post = $.extend(find.options.opost, {
+                strSel1: $("#select1").val(),
+                strSel2: $("#select2").val(),
+                strSel3: $("#select3").val()
+            });
+            find.options.currentPage = 1;
+            find.render();
+        });
+
+        $(".addCourse").on("click", function () {
+            window.location.href = "/manage/course/page/add/new"
+        })
+    });
+
+    //点击跳转新页面
+    function redirect(code) {
+        //sessionStorage.setItem("contentHtml",$("#content").prop("outerHTML"));
+        window.open("/manage/dataExport/dataDetail/" + code);
+    }
+
+    //
+    function SearchContent() {
+        var find = $("#audit").data("datatable");
+        if (!find.options.opost) find.options.opost = find.options.post || {};
+        find.options.post = $.extend(find.options.opost, {query: $("#searchtext").val()});
+        find.options.currentPage = 1;
+        find.render();
+    }
+
+    function doCheck(flag, id) {
+        var tipMsg = "";
+        if (flag === "on") {
+            tipMsg = "确定发布课程?";
+        } else if (flag === "off") {
+            tipMsg = "课程下线后将无法购买,确定是否下线?";
+        //} else if (flag === "del") {
+         //   tipMsg = "课程删除后用户将无法查看购买,请确保没有用户已预订此课程,确定删除?";
+        } else {
+            return
+        }
+
+        bootbox.confirm({
+            title: "提示",
+            message: tipMsg,
+            buttons: {
+                cancel: {
+                    label: '取消'
+                },
+                confirm: {
+                    label: '确定'
+                }
+            },
+            callback: function (result) {
+                if (!result) {
+                    return
+                }
+                $.post("/manage/course/changeStatus", {id: id, flag: flag}, function (r) {
+                    if (r.success) {
+                        $("#audit").data("datatable").render();
+                    } else {
+                        bootbox.alert(r.errMsg)
+                    }
+                })
+            }
+        });
+    }
+</script>
+</html>

+ 345 - 0
core/src/web/templates/manage/course/order_detail.html

@@ -0,0 +1,345 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width, initial-scale=1">
+		<title>课程订单详情</title>
+		{{include "/common/inc.html"}}
+	<link rel="stylesheet" type="text/css" href="{{Msg "seo" "cdn"}}/dataexport/base.css"/>
+    <link rel="stylesheet" type="text/css" href="{{Msg "seo" "cdn"}}/dataexport/dataExport.css"/>
+	</head>
+	<style>
+	.nofloat{float:none}
+	body {
+	    padding-top: 0px;
+	    font-family: tahoma, arial, 'Hiragino Sans GB', 'Microsoft YaHei', 宋体, sans-serif;
+	    color: #4e5051;
+	    background: #f5f5fb;
+	}
+        #courseOrder {
+            background-color: #f5f5f5;
+        }
+	#dataReportOrder {
+	    background-color: #f5f5f5;
+	}
+	.cont-one, .row {
+   	 margin-top: 20px  !important;
+	}
+	.pbtn{
+		margin: 20px;
+	    background: #00bcd4;
+		user-select: none;
+	    float: right;
+	    width: 100px;
+	    height: 35px;
+	    line-height: 35px;
+	    text-align: center;
+	    color: #fff;
+      text-decoration:none;
+	}
+  .pbtn:hover{
+      text-decoration:none;
+      color:#fff;
+  }
+  .pbtn:visited {   
+      text-decoration: none;  
+  }
+  .pbtn:link {
+    text-decoration: none;  
+  }
+  .imgdiv{
+    padding: 27px 120px;
+    background: #fff;
+  }
+  .imgdiv img{
+    height: 200px;
+    width:30%;
+    max-width: 300px;
+  }  
+	.right .order_info .bd .first, .right .download_link .bd .first, .right .filter .bd .first {
+	    padding-left: 14px;
+	    width: 48% !important;
+	}
+	.right .order_info .bd .second, .right .download_link .bd .second, .right .filter .bd .second {
+	    width: 48% !important;
+	}
+	.status{
+		position: absolute;
+	    left: 250px;
+	    top: 0px;
+	}
+	input[type=radio]{-webkit-appearance:radio;}
+	</style>
+	<body>
+		{{include "/manage/audithead.html"}}
+		<div class="main">
+			<div class="left">
+			{{include "/manage/slider.html"}}</div>
+			<div class="right" style="background: #fff;color:#4e5051;min-height: 610px;">
+				<div class="title" style="position:relative;">
+					<span></span>订单详情 <span></span>
+					<div class="status"></div>
+				</div>
+				<!-- 退款审核 -->
+				<div class="order_info" id="tuikuan" style="display:none;" >
+					<div class="hd">退款审核</div>
+					<div class="bd clearfix" style="padding-right: 65px;padding-bottom: 10px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">申请退款时间:<span class="sqtksj"></span></li>
+							<li class="row-list nofloat">申请退款原因:<span class="sqtkyy"></span></li>
+							<li class="row-list nofloat">退款金额:<span class="sqtkje"></span></li>
+							<li class="row-list nofloat"><button style="margin-top: 10px;" class="btn btn-success" onclick="tuikuan(this)" data-original-title="Search" id="searchtip" type="button">确认已退款</button></li>
+						</ul>
+					</div>
+				</div>
+				<!-- 订单信息 -->
+				<div class="order_info" id="info">
+					<div class="hd">订单信息</div>
+					<div class="bd clearfix" style="padding-right: 65px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">课程名称:<span class="kcmc"></span></li>
+							<li class="row-list nofloat">课程类型:<span class="kclx"></span></li>
+							<li class="row-list nofloat">课程地点:<span class="kcdd"></span></li>
+							<li class="row-list nofloat">参会人数:<span class="chrs"></span></li>
+						</ul>
+						<div class="line" style="height: 110px;"></div>
+						<ul class="row second"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">联系人单位:<span class="lxrdw"></span></li>
+							<li class="row-list nofloat">联系人姓名:<span class="lxrxm"></span></li>
+							<li class="row-list nofloat">联系人邮箱:<span class="lxryx"></span></li>
+							<li class="row-list nofloat">联系人电话:<span class="lxrdh"></span></li>
+						</ul>
+					</div>
+				</div>
+				<!-- 支付信息 -->
+				<div class="order_info" id="info">
+					<div class="hd">支付信息</div>
+					<div class="bd clearfix" style="padding-right: 65px;padding-bottom: 10px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">订单编号:<span class="ddbh"></span></li>
+							<li class="row-list nofloat">下单时间:<span class="xdsj"></span></li>
+							<li class="row-list nofloat">支付时间:<span class="zfsj"></span></li>
+						</ul>
+						<div class="line" style="height: 110px;"></div>
+						<ul class="row second"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">支付方式:<span class="zffs"></span></li>
+							<li class="row-list nofloat" style="display:none;">支付单号:<span class="zfdh"></span></li>
+							<li class="row-list nofloat" style="display:none;padding-top: 10px;">
+								<div>
+									转账凭证:<button style="padding: 3px;font-size: 12px;margin-top: -2px;" class="btn btn-success" id="chakanpz" type="button">查看凭证</button>
+								</div>
+								<div style="    margin-left: 100px;margin-top: 10px;">
+									<label class="checkbox-inline"><input type="radio" name="agree" id="agree" value="1"  checked="">不通过</label>
+									<label class="checkbox-inline"><input type="radio" name="agree" id="disagree" value="2"  checked="">通过</label>
+									<button style="padding: 3px 10px;font-size: 12px;margin-left: 14px;" class="btn btn-success" onclick="queren(this)" id="queren" type="button">确认</button>
+								</div>
+							</li>
+						</ul>
+					</div>
+					<div class="bd clearfix" style="padding-right: 65px;padding-bottom: 10px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">单价:<span class="dj"></span></li>
+							<li class="row-list nofloat">参会人数:<span class="chrs"></span></li>
+							<li class="row-list nofloat">订单总价:<span class="ddzj"></span></li>
+						</ul>
+						<div class="line" style="height: 110px;"></div>
+						<ul class="row second"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">每单立减:<span class="mdlj"></span></li>
+							<li class="row-list nofloat">多人立减:<span class="drlj"></span></li>
+							<li class="row-list nofloat">实付金额:<span class="sfje"></span></li>
+						</ul>
+					</div>
+				</div>
+				<!-- 发票信息 -->
+				<div class="order_info" id="fapiao" style="display:none;" >
+					<div class="hd">发票信息</div>
+					<div class="bd clearfix" style="padding-right: 65px;padding-bottom: 10px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">发票类型:<span class="fplx"></span></li>
+							<li class="row-list nofloat">发票抬头:<span class="fptt"></span></li>
+						</ul>
+						<div class="line" style="height: 110px;"></div>
+						<ul class="row second"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">发票明细:<span class="fpmx"></span></li>
+						</ul>
+					</div>
+					<div class="bd clearfix" style="padding-right: 65px;padding-bottom: 10px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">开票单位名称:<span class="kpdwmc"></span></li>
+							<li class="row-list nofloat">纳税人识别号:<span class="nsrsbh"></span></li>
+							<li class="row-list nofloat">注册地址:<span class="zcdz"></span></li>
+							<li class="row-list nofloat">注册电话:<span class="zcdh"></span></li>
+							<li class="row-list nofloat">开户银行:<span class="khyh"></span></li>
+							<li class="row-list nofloat">银行账号:<span class="yhzh"></span></li>
+						</ul>
+						<div class="line" style="height: 110px;"></div>
+						<ul class="row second"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">收件人:<span class="sjr"></span></li>
+							<li class="row-list nofloat">手机号:<span class="sjh"></span></li>
+							<li class="row-list nofloat">所在地区:<span class="szdq"></span></li>
+							<li class="row-list nofloat">详细地址:<span class="xxdz"></span></li>
+						</ul>
+					</div>
+				</div>
+			</div>
+		</div>
+		
+		<!--显示图片-->
+		<div class="modal fade" id="myModal" tabindex="-1" role="dialog" 
+		   aria-labelledby="myModalLabel" aria-hidden="true">
+		   <div class="modal-dialog mimg">
+		      <div class="modal-content">
+		         <div class="modal-header">
+		            <button type="button" class="close" data-dismiss="modal" 
+		               aria-hidden="true">×
+		            </button>
+		         </div>
+		         <div class="modal-body" id="imgshow" style="cursor:pointer;width:100%;" >
+					<img class="showImg" src="">
+		         </div>
+		         <div class="modal-footer">
+		            <button type="button" class="btn btn-default" 
+		               data-dismiss="modal">关闭
+		            </button>
+		         </div>
+		      </div><!-- /.modal-content -->
+		   </div><!-- /.modal-dialog -->
+		</div><!-- /.modal -->
+
+		{{include "/common/bottom.html"}} 
+		<script>
+			var orderCode = {{.T.orderCode}}
+			$(function(){
+				reloadData(1);
+				$("#chakanpz").on('click',function(){
+					$("#myModal").modal("show");
+				})
+			})
+			function reloadData(rt){
+				$.post("/manage/courseOrder/getDetail", {orderCode: orderCode, rt: rt}, function (r) {
+					if(r.res){
+						var res = r.res;//订单信息
+						var resCour = r.resCour//课程信息
+						var dPlan = resCour["s_discountPlan"]//课程折扣
+						var filter = JSON.parse(res["filter"]) 
+						if(filter["transferV"]!=undefined){
+							$(".showImg").attr("src",filter["transferV"])
+						}
+						//退款审核
+						if(res["course_status"]=="5"||res["course_status"]=="6"){
+							$(".sqtksj").text(filter["refundTime"])
+							$(".sqtkyy").text(filter["refundReason"])
+							$(".sqtkje").text(res["order_money"]/100)
+							if(res["course_status"]=="6"){
+								$("#tuikuan").show().find("button").attr("disabled",true).text("已退款");
+							}else{
+								$("#tuikuan").show();
+							}
+						}
+						//订单信息
+						if(res["order_status"]=="0"){
+							$(".status").text("待付款").css({"color":"#EAB62F"})
+						}else if(res["order_status"]=="1"){
+							$(".status").text("已支付").css({"color":"#4DB443"})
+						}else if(res["order_status"]=="-2"){
+							$(".status").text("已取消").css({"color":"#F5585"})
+						}
+						$(".kcmc").text(resCour["s_name"])
+						$(".kclx").text(filter["courseType"])
+						$(".kcdd").text(resCour["s_address"])
+						$(".chrs").text(filter["peoleNum"])
+						$(".lxrdw").text(filter["company"])
+						$(".lxrxm").text(filter["name"])
+						$(".lxryx").text(filter["email"])
+						$(".lxrdh").text(filter["phone"])
+						//支付信息
+						$(".ddbh").text(orderCode)
+						$(".xdsj").text(res["prepay_time"])
+						if(res["pay_time"]!=null){
+							$(".zfsj").text(res["pay_time"])
+						}
+						if(res["pay_way"].indexOf("wx")>-1){
+							$(".zffs").text("微信")
+						}else if(res["pay_way"].indexOf("ali")>-1){
+							$(".zffs").text("支付宝")
+						}else if(res["pay_way"]=="transferAccounts"){
+							$(".zffs").text("公对公转账")
+						}
+						if(res["course_status"]=="2"){
+							$("#chakanpz").parents(".nofloat").show();
+						}else{
+							$(".zfdh").text(res["out_trade_no"]).show();
+						}
+						$(".dj").text(parseInt(resCour["i_price"])/100)
+						$(".ddzj").text(filter["peoleNum"]*resCour["i_price"]/100)
+						for(var i=0;i<dPlan.length;i++){
+							if(dPlan[i]["title"]=="每单立减"){
+								$(".mdlj").text("-"+dPlan[i]["price"])
+							}else{
+								var zhek = 10;
+								if(filter["peoleNum"]>=8){
+									zhek = 0.2
+									var drlj = parseInt(resCour["i_price"])/100*zhek*filter["peoleNum"]
+									$(".drlj").text("-"+drlj.toFixed(2))
+								}else if(filter["peoleNum"]>=4){
+									zhek = 0.1
+									var drlj = parseInt(resCour["i_price"])/100*zhek*filter["peoleNum"]
+									$(".drlj").text("-"+drlj.toFixed(2))
+								}
+							}
+							
+						}
+						$(".sfje").text(res["order_money"]/100)
+						//发票信息
+						var resInv = r.resInv//发票信息
+						if(resInv){
+							$("#fapiao").show();
+							$(".fplx").text(resInv["invoice_type"])
+							$(".fptt").text(resInv["invoice_rise"])
+							$(".fpmx").text(resInv["invoice_content"])
+							$(".kpdwmc").text(resInv["apply_company"])
+							$(".nsrsbh").text(resInv["apply_tinumber"])
+							$(".zcdz").text(resInv["apply_regaddress"])
+							$(".zcdh").text(resInv["apply_regphone"])
+							$(".khyh").text(resInv["apply_accountbank"])
+							$(".yhzh").text(resInv["apply_banknumber"])
+							$(".sjr").text(resInv["apply_addressee"])
+							$(".sjh").text(resInv["apply_phone"])
+							$(".szdq").text(resInv["apply_address"])
+							$(".xxdz").text(resInv["apply_addressmore"])
+						}
+					}
+                })
+			}
+			//退款审核
+			function tuikuan(t){
+				var rt = "2"
+				$.post("/manage/courseOrder/getDetail", {orderCode: orderCode, rt: rt}, function (r) {
+					if(r.id==1){
+						$(t).text("已退款").attr("disabled",true);
+					}else{
+						alert("退款失败,系统异常")
+					}
+				})
+			}
+			//凭证审核
+			function queren(t){
+				var rt = "3"
+				var agreeN = $('input[name="agree"]:checked').val()
+				$.post("/manage/courseOrder/getDetail", {orderCode:orderCode,rt:rt,agreeN:agreeN}, function (r) {
+					if(r.id==1){
+						$(t).parent().parent().hide()
+						if(agreeN=="2"){
+							$(".status").text("已支付").css({"color":"#4DB443"})
+							$(".zfsj").text(r.pay_time)
+						}else{
+							
+						}
+					}else{
+						alert("审核失败,系统异常")
+					}
+				})
+			}
+		</script>   
+	</body>
+</html>

+ 358 - 0
core/src/web/templates/manage/course/order_index.html

@@ -0,0 +1,358 @@
+<html>
+<head>
+    <title>课程订单列表</title>
+    {{include "/common/inc.html"}}
+    <script src="{{Msg "seo" "cdn"}}/js/jquery.cookie.js"></script>
+    <script src="/js/qfwtable.js"></script>
+    <style type="text/css">
+        #courseOrder {
+            background-color: #f5f5f5;
+        }
+
+        #content table {
+            table-layout: fixed;
+            border: 0px;
+            font-size: 14px;
+        }
+
+        #sidebar {
+            margin-left: 0px;
+        }
+
+        .table > thead > tr > th:nth-child(1) {
+            width: 10%;
+        }
+
+        .table > thead > tr > th:nth-child(2) {
+            width: 15%;
+        }
+
+        .table > thead > tr > th:nth-child(3) {
+            width: 15%;
+        }
+
+        .table > thead > tr > th:nth-child(4) {
+            width: 10%;
+        }
+
+        .table > thead > tr > th:nth-child(5) {
+            width: 10%;
+        }
+
+        .table > thead > tr > th:nth-child(6), .table > tbody > tr > td:nth-child(6) {
+            width: 10%;
+            /*text-align: center;*/
+        }
+
+        .table > thead > tr > th:nth-child(7) {
+            width: 10%;
+        }
+
+        .table > thead > tr > th:nth-child(8), .table > tbody > tr > td:nth-child(8) {
+            text-align: center;
+        }
+        .table > thead > tr > th {
+            border: 0px;
+            font-size: 14px;
+        }
+
+        .table > tbody > tr > td {
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            border: 0px;
+            border-bottom: 1px dashed #999999;
+        }
+
+        .table > tbody > tr {
+            cursor: pointer;
+        }
+
+        .addCourse {
+            float: right;
+            margin-right: 20px;
+            color: #fff;
+            background-color: #38b44a;
+            border-color: #38b44a;
+            border-radius: 4px;
+            padding: 8px 12px;
+            margin: 5px;
+        }
+
+        .pagination > .active > a:hover, .pagination > .active > a:focus {
+            background-color: #18CC7D;
+        }
+
+        .editBtn {
+            display: flex;
+        }
+
+        .editBtn span {
+            padding: 3px 7px;
+            margin: 0 3px;
+        }
+
+        .greenStyle {
+            color: #4DB443;
+        }
+
+        .redStyle {
+            color: #F5585C;
+        }
+
+        /*修改弹框样式*/
+        .modal {
+            top: 33%;
+        }
+
+        .modal-dialog {
+            width: 400px;
+            text-align: center;
+        }
+
+        .modal-dialog .bootbox-close-button.close {
+            display: none;
+        }
+
+        .modal-dialog .modal-header .modal-title {
+            color: #4E5051;
+            font-size: 18px;
+        }
+
+        .modal-dialog .bootbox-body {
+            color: #4E5051;
+            font-size: 14px;
+        }
+
+        .modal-dialog .modal-header,
+        .modal-dialog .modal-footer {
+            border: none;
+
+        }
+
+        .modal-dialog .modal-footer{
+            display: flex;
+            justify-content: space-between;
+        }
+
+        .modal-dialog .modal-footer .bootbox-cancel{
+            width: 110px;
+            height: 38px;
+            left: 24px;
+            top: 112px;
+
+            background: #C2C2C2;
+            border-radius: 4px;
+            border-color: #C2C2C2;
+            color: #ffff;
+        }
+
+        .modal-dialog .modal-footer .bootbox-accept{
+            width: 110px;
+            height: 38px;
+            left: 226px;
+            top: 112px;
+
+            background: #4DB443;
+            border-radius: 4px;
+            border-color: #4DB443;
+            color: #ffff;
+        }
+		.dt-table-wrapper{
+			height:460px  !important;
+		}
+    </style>
+</head>
+<body>
+{{include "/manage/audithead.html"}}
+<div class="row" style="width:96%; margin:0 auto;">
+    {{include "/manage/slider.html"}}
+    <div id="content">
+        <div id="audit"></div>
+    </div>
+</div>
+{{include "/common/bottom.html"}}
+</body>
+<script type="text/javascript" src="/js/bootbox.js"></script>
+<script>
+    $(function () {
+        $("#audit").datatable({
+            perPage: 10
+            ,
+            showPagination: true
+            ,
+            checkbox: "" //check radio
+            ,
+            checkboxHeader: false
+            ,
+            idField: "_id"
+            ,
+            classname: "table-hover"
+            ,
+            css: {"height": "550px"}
+            //,post:{"name":"ee"}
+            ,
+            buttons: ['<div style="width:50%;margin:5px" class="input-group pull-right" id="search"><input type="text" id="searchtext" value=""  data-original-title="Search" class="form-control" placeholder="请输入订单编号"><span class="input-group-btn"><button class="btn btn-success" onclick="SearchContent()" data-original-title="Search" id="searchtip" type="button" style="height:38px;">检索</button></span></div><div style="margin:5px;" class="controls pull-right"><select class="form-control" id="select2" ><option value="0">  订单编号  </option><option  value="1">  课程名称</option><option value="2">  联系人姓名 </option><option value="3">  联系人手机号 </option></select></div><div style="margin:5px;" class="controls pull-right"><select class="form-control" id="select1"><option value="">  选择订单状态  </option><option value="1">  已支付 </option><option value="-2">  已取消 </option><option value="0">  未支付 </option></select></div>']
+            ,
+            url: '/manage/courseOrder/list'
+            ,
+            columns: [
+                {
+                    title: "订单状态", field: "index", callback: function (data) {
+                        if (data.order_status == 0) {
+                            return "未支付"
+                        } else if (data.order_status == 1) {
+                            return "已支付"
+                        } else if (data.order_status == -2){
+                            return "已取消"
+                        }
+                    }
+                },
+                {
+                    title: "订单编号", field: "order_code"
+                },
+                {
+                    title: "购买时间", field: "pay_time", callback: function (data) {
+                        if (data.pay_time == null) {
+                            return "-"
+                        } else {
+	                        return data.pay_time
+                        }
+                    }
+                },
+                {
+                    title: "课程类型", field: "courseType"
+                },
+                {
+                    title: "价格", field: "pay_money",callback: function (data) {
+                        if (data.pay_money == ""||data.pay_money == null) {
+                            return data.order_money/100
+                        }
+						return data.pay_money/100
+                    }
+                },
+                {
+                    title: "发票状态", field: "applybill_status", callback: function (data) {
+                         if (data.applybill_status == 0) {
+							return "未申请"
+						}else if(data.applybill_status == 1){
+							return "已申请"
+						}
+                    }
+                },
+                {
+                    title: "支付方式", field: "pay_way", callback: function (data) {
+                         if (data.pay_way.indexOf("wx")>-1) {
+							return "微信"
+						}else if(data.pay_way.indexOf("ali")>-1){
+							return "支付宝"
+						}else if(data.pay_way=="transferAccounts"){
+							return "转账"
+						}
+                    }
+                },
+                {
+                    title: "操作", field: "applybill_company", callback: function (data) {
+                        //申请退款 已退款  转账审核 转账审核未通过  转账审核通过
+					 	if (data.order_code != "") {
+                           var returnHtml = ""
+                           if (data.course_status == 2) {
+                               returnHtml += "<span class='redStyle'>转账待审核</span>"
+                           }else if (data.course_status == 3) {
+                               returnHtml += "<span class='redStyle'>转账审核未通过</span>"
+                           }else if (data.course_status == 4) {
+                               returnHtml += "<span class='greenStyle'>转账审核通过</span>"
+                           }else if (data.course_status == 5) {
+                               returnHtml += "<span class='redStyle'>申请退款</span>"
+                           }else if (data.course_status == 6) {
+                               returnHtml += "<span class='greenStyle'>已退款</span>"
+                           }
+                           return returnHtml
+                       	}
+                    }
+                }
+            ]
+        });
+
+        $("#select1").change(function () {
+            var find = $("#audit").data("datatable");
+            if (!find.options.opost) find.options.opost = find.options.post || {};
+            find.options.post = $.extend(find.options.opost, {
+                strSel1: $("#select1").val(),
+            });
+            find.options.currentPage = 1;
+            find.render();
+        });
+
+        $("#select2").change(function () {
+			var select2 = $("#select2").val();
+			if (select2==0){
+				select2 = "订单编号" 
+			}else if(select2==1){
+				select2 = "课程名称" 
+			}else if(select2 ==2){
+				select2 = "联系人姓名"
+			}else if(select2 ==3){
+				select2 = "联系人手机号"
+			}
+			$("#searchtext").attr("placeholder","请输入"+select2)
+		})
+    });
+
+    //点击跳转新页面
+	//事件委托
+	$("#content").on("click","#audit>.dt-table-wrapper>.table>tbody>tr",function(){
+		var code = $(this).find("td").eq(1).text()
+		window.open("/manage/courseOrder/detail/"+code)
+	});
+
+    //
+    function SearchContent() {
+        var find = $("#audit").data("datatable");
+        if (!find.options.opost) find.options.opost = find.options.post || {};
+        find.options.post = $.extend(find.options.opost, {
+			strCont: $("#searchtext").val(),
+			strSel1: $("#select1").val(),
+			strSel2: $("#select2").val(),
+		});
+        find.options.currentPage = 1;
+        find.render();
+    }
+
+    function doCheck(flag, id) {
+        var tipMsg = "";
+        if (flag === "on") {
+            tipMsg = "确定发布课程?";
+        } else if (flag === "off") {
+            tipMsg = "课程下线后将无法购买,确定是否下线?";
+        } else {
+            return
+        }
+
+        bootbox.confirm({
+            title: "提示",
+            message: tipMsg,
+            buttons: {
+                cancel: {
+                    label: '取消'
+                },
+                confirm: {
+                    label: '确定'
+                }
+            },
+            callback: function (result) {
+                if (!result) {
+                    return
+                }
+                $.post("/manage/course/changeStatus", {id: id, flag: flag}, function (r) {
+                    if (r.success) {
+                        $("#audit").data("datatable").render();
+                    } else {
+                        bootbox.alert(r.errMsg)
+                    }
+                })
+            }
+        });
+    }
+</script>
+</html>

+ 382 - 0
core/src/web/templates/manage/course/preview/course_detail_mobile.html

@@ -0,0 +1,382 @@
+<!DOCTYPE html>
+<html style="max-width: 414px;max-height: 736px">
+
+<head>
+    <meta charset="utf-8">
+    <title>招标管理课程</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+    <link rel="stylesheet" type="text/css" href="/course/css/wx_base.css"/>
+    <link rel="stylesheet" type="text/css" href="/course/iconfont/wx_iconfont.css"/>
+    <link rel="stylesheet" type="text/css" href="/course/css/wx_course_detail.css"/>
+    <script src="/course/js/jquery.js"></script>
+    <script src="/course/js/common.js"></script>
+    <script src="/course/js/rem.js"></script>
+    <style>
+      .info-detail-content em, i {
+        font-style: italic;
+      }
+      .box ol{
+      margin:15px 0;
+      padding-left:40px;
+      list-style-type: decimal;
+    }
+    .box ul{
+      margin:15px 0;
+      padding-left:40px;
+      display: block;
+      list-style-type: disc;
+      margin-block-start: 1em;
+      margin-block-end: 1em;
+      margin-inline-start: 0px;
+      margin-inline-end: 0px;
+      padding-inline-start: 40px;
+    }
+    .box li{
+      float:unset;
+    }
+    </style>
+</head>
+
+<body>
+<div class="course-detail">
+    <div class="detail-content">
+        <div class="course-info-detail">
+            <div class="header-container wp">
+                <div class="header-title ellipsis-3">
+                </div>
+                <div class="header-info">
+                        <span class="info-l">
+                            <span class="course-state in-progress"></span>
+                            <span class="course-city"></span>
+                            <span class="course-date"></span>
+                        </span>
+                    <span class="info-r"></span>
+                </div>
+            </div>
+            <div class="course-time-quantum wp">
+                <span class="time-label">课程时间</span>
+                <div class="time-content"></div>
+            </div>
+            <div class="course-discount wp">
+                <span class="discount-label">优惠</span>
+                <div class="discount-content">
+
+                </div>
+                <div class="iconfont icon-arrow"></div>
+            </div>
+            <div class="info-detail-content">
+                <!-- <ul class="tabs-wrap sticky"> -->
+                <ul class="tabs-wrap sticky wp">
+                    <li class="tab active" data-id="a1">课程介绍</li>
+                    <li class="tab" data-id="a2">课程大纲</li>
+                    <li class="tab" data-id="a3">购买须知</li>
+                    <li class="tab" data-id="a4">客户服务</li>
+                </ul>
+                <div class="box wp">
+
+                </div>
+            </div>
+            <div class="copyright-container">
+                <span class="line"></span>
+                <span class="copyright-info">课程由中国招投标采购培训网提供</span>
+                <span class="line"></span>
+            </div>
+        </div>
+    </div>
+    <div class="bottom-container">
+            <span class="course-price">
+                <span class="yen">&yen;</span>
+                <span class="count">-</span>
+                <span class="unit">元/人</span>
+            </span>
+        <span class="button-container">
+                <span class="icon-box">
+                    <span class="iconfont icon-help"></span>
+                    <span class="icon-text"><a>帮助</a></span>
+                </span>
+                <button class="reserve-now">立即预订</button>
+            </span>
+    </div>
+</div>
+<!-- 优惠弹框 -->
+<div class="discount-picker">
+    <div class="weui-mask"></div>
+    <div class="weui-picker">
+        <div class="weui-dialog__hd">
+            <div class="weui-dialog__hd__left">优惠</div>
+            <div class="weui-dialog__hd__right">
+                <button class="weui-picker__btn iconfont icon-close"></button>
+            </div>
+        </div>
+        <div class="weui-dialog__bd" id="discount_c">
+
+        </div>
+    </div>
+</div>
+<script>
+    $(function () {
+        reloadData();
+
+        // 数组冒泡排序
+        function bSort(arr) {
+            var len = arr.length;
+            for (var i = 0; i < len - 1; i++) {
+                for (var j = 0; j < len - 1 - i; j++) {
+                    // 相邻元素两两对比,元素交换,大的元素交换到后面
+                    if (arr[j].oTop > arr[j + 1].oTop) {
+                        var temp = arr[j];
+                        arr[j] = arr[j + 1];
+                        arr[j + 1] = temp;
+                    }
+                }
+            }
+            return arr;
+        }
+
+        // 滚动距离
+        var scrollTop = 0;
+        initTabChange();
+
+        function initTabChange() {
+            var h2Ids = [];
+            // 获取所有带有id属性的h2标签的位置
+            $('.box h2[id]').each(function (i, dom) {
+                var y = dom.getBoundingClientRect().top + scrollTop;
+                h2Ids.push({
+                    id: dom.id,
+                    oTop: y - 60
+                });
+            });
+            if (h2Ids.length) h2Ids = bSort(h2Ids)
+
+            // 监听滚动,控制tab高亮
+            var cannotTriggerScroll = false;
+            $('.detail-content').on('scroll', function () {
+                if (cannotTriggerScroll) return;
+                cannotTriggerScroll = true;
+                var current = null;
+                scrollTop = $(this).scrollTop();
+                h2Ids.some(function (item, i) {
+                    if (scrollTop < h2Ids[0].oTop) {
+                        current = h2Ids[0];
+                        return true;
+                    }
+
+                    if (scrollTop > h2Ids[h2Ids.length - 1].oTop) {
+                        current = h2Ids[h2Ids.length - 1];
+                        return true;
+                    }
+
+                    if (scrollTop > item.oTop && scrollTop < h2Ids[i + 1].oTop) {
+                        current = item;
+                        return true;
+                    }
+                });
+
+                if (current) {
+                    $('.tabs-wrap .tab[data-id=' + current.id + ']').addClass('active').siblings().removeClass('active');
+                }
+                cannotTriggerScroll = false;
+            });
+
+            // tab点击事件
+            $('.info-detail-content').on('click', '.tab', function () {
+                cannotTriggerScroll = true
+                $this = $(this);
+                var id = $this.attr('data-id');
+                scrollTop = $('.detail-content').scrollTop();
+                // 控制active样式
+                $this.addClass('active').siblings().removeClass('active');
+
+                // 计算滚动距离并滚动
+                // e距离文档顶部的距离 = e相对的与视口的距离 + 滚动距离
+                $('.detail-content').stop()
+                var y = $('#' + id)[0].getBoundingClientRect().top + scrollTop;
+                $('.box.wp').animate({scrollLeft: 0});
+                $('.detail-content').animate({
+                    scrollTop: y - 55 + 'px'
+                }, 300, function () {
+                    cannotTriggerScroll = false
+                });
+            });
+        }
+
+        // picker的显示隐藏
+        function pickerShow(className, f) {
+            if (f) {
+                $(className).show();
+            } else {
+                $(className).hide();
+            }
+        }
+
+        $('.weui-mask').on('click', function () {
+            pickerShow('.discount-picker', false);
+        });
+
+        // 绑定点击事件
+        // 优惠点击显示隐藏
+        $('.course-discount').on('click', function () {
+            pickerShow('.discount-picker', true);
+        });
+        $('.weui-dialog__hd__right').on('click', function () {
+            pickerShow('.discount-picker', false);
+        });
+
+        // 点击帮助显示隐藏
+        $('.jy-alert .weui-dialog__ft').on('click', function () {
+            pickerShow('.jy-alert', false);
+        });
+    })
+
+    // 格式化金钱的函数
+    // s: 金额(number) 必传
+    // n: 保留小数的位数(int:0-100)
+    function formatMoney(s, n) {
+        if (n === undefined) {
+            n = -1
+        } else {
+            n = n > 0 && n <= 20 ? n : 2;
+        }
+        var intS = parseInt(s)
+        var point = '.'
+        var left;
+        var right;
+        s = parseFloat((s + '').replace(/[^\d\.-]/g, ''))
+        // 没传n,默认(如果为整数,则不保留小数。如果为浮点数,则保留两位小数)
+        if (n === -1) {
+            if (s === intS) {
+                n = 0
+                right = ''
+                point = ''
+            } else {
+                n = 2
+                s = s.toFixed(n);
+                right = s.split('.')[1];
+            }
+            s = s + ''
+            left = s.split('.')[0].split("").reverse();
+        } else {
+            s = parseFloat((s + '').replace(/[^\d\.-]/g, '')).toFixed(n) + '';
+            left = s.split('.')[0].split('').reverse();
+            right = s.split('.')[1];
+        }
+
+        t = "";
+        for (i = 0; i < left.length; i++) {
+            t += left[i] + ((i + 1) % 3 == 0 && (i + 1) != left.length ? ',' : '');
+        }
+
+        var money = t.split('').reverse().join('') + point + right;
+        return money;
+    }
+
+    function reloadData() {
+        $.ajax({
+            type: "POST",
+            url: "/manage/course/previewGetDate",
+            data: {_id:{{.T.id}}},
+            async: false,
+            dataType: "json",
+            success: function (r) {
+                if (r.success) {
+                    reloadHmtl(r.data)
+                }
+            },
+            error: function () {
+                console.log("数据查询出错!")
+            }
+        });
+    }
+
+    //
+    function reloadHmtl(r) {
+        var rs = r["detail"]
+        //
+        if (rs.i_type === 2) {
+            $("title").text("投标实务课程");
+        }
+        //
+        if (rs["s_name"] != undefined && rs["s_name"] != "") {
+            $(".header-title").text(rs["s_name"])
+        }
+        //
+        var nowTime = new Date().getTime();
+        // var startTimes = new Date(rs.l_starttime.split(" ")[0] + " 23:59:59").getTime() - 86400000;
+        var startTimes = new Date(rs.l_starttime).getTime();
+        if (nowTime >= startTimes) {
+            var status = "已结束";
+            $(".reserve-now").text("已结束").attr('disabled', true);
+            $(".bottom-container").addClass("ended");
+            $(".course-state").addClass("c_state");
+            $(".course-state").text(status);
+        } else {
+            var status = "报名中";
+            if (parseInt(rs["i_status"]) !== 1) {
+                status = "已结束";
+                $(".reserve-now").text("已结束").attr('disabled', true);
+                $(".bottom-container").addClass("ended");
+                $(".course-state").addClass("c_state");
+            }
+            $(".course-state").text(status);
+        }
+        //
+        // if(rs["i_status"]!=undefined&&rs["i_status"]!=""){
+        // 	var status = "已结束"
+        // 	if(parseInt(rs["i_status"])==1){
+        // 		status = "报名中"
+        // 	}else{
+        // 		$(".reserve-now").text("已结束").attr('disabled',true);
+        // 		$(".bottom-container").addClass("ended");
+        // 		$(".course-state").addClass("c_state");
+        // 	}
+        // 	$(".course-state").text(status)
+        // }
+        if (rs["s_address"] != undefined && rs["s_address"] != "") {
+            $(".course-city").text(rs["s_address"])
+        }
+        if (rs["l_starttime"] != undefined && rs["l_starttime"] != "") {
+            var c_date = rs["l_starttime"].split(" ")[0].substring(5).replace("-", "月") + "日"
+            $(".course-date").text(c_date)
+        }
+        if (rs["l_starttime"] != undefined && rs["l_starttime"] != "" && rs["l_endtime"] != undefined && rs["l_endtime"] != "") {
+            var starttime = datefunc(rs["l_starttime"].split(" ")[0])
+            var endtime = datefunc(rs["l_endtime"])
+            $(".time-content").text(starttime + " - " + endtime)
+        }
+        if (rs["s_discountPlan"] != undefined && rs["s_discountPlan"] != "") {
+            var disc = rs["s_discountPlan"]
+            var discHtml = ''
+            var discCHtml = ''
+            for (var i = 0; i < disc.length; i++) {
+                discHtml += '<div class="discount-item">'
+                    + '<span class="item-l s_title">' + disc[i]["title"] + '</span>'
+                    + '<span class="item-r ellipsis s_remarks">' + disc[i]["remarks"] + '</span>'
+                    + '</div>'
+                discCHtml += '<div class="discount-item">'
+                    + '<div class="item-tip">'
+                    + '<span class="tip-l">' + disc[i]["title"] + '</span>'
+                    + '<span class="tip-r">' + disc[i]["remarks"] + '</span>'
+                    + '</div>'
+                    + '<div class="item-content">' + disc[i]["content"].replace(";", "</br>") + '</div>'
+                    + '</div>'
+            }
+            $(".discount-content").html(discHtml);
+            $("#discount_c").html(discCHtml);
+        }
+        if (rs["s_content"] != undefined && rs["s_content"] != "") {
+            $(".box").html(rs["s_content"])
+        }
+        if (rs["i_price"] != undefined && rs["i_price"] != "") {
+            $(".count").html(formatMoney(parseInt(rs["i_price"]) / 100))
+        }
+    }
+
+    function datefunc(d) {
+        return d.replace("-", "年").replace("-", "月") + "日";
+    }
+</script>
+{{include "/common/baiducc.html"}}
+</body>
+
+</html>

+ 217 - 0
core/src/web/templates/manage/course/preview/course_detail_pc.html

@@ -0,0 +1,217 @@
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>招投标课程详情</title>
+    <link rel="stylesheet" href="/course/css/reset_pc.css">
+    <link rel="stylesheet" href="/course/iconfont/iconfont.css">
+    <link rel="stylesheet" href="/course/css/course_detail.css">
+	<script src="/course/js/jquery.js"></script>
+    <!--[if lt IE 9]>
+    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.3/html5shiv.js"></script>
+    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
+    <![endif]-->
+</head>
+<style type="text/css">
+    .j-wx-code{
+        width: 335px;
+        height: 355px;
+        background-color: #fff;
+        -webkit-border-radius: 6px;
+        -moz-border-radius: 6px;
+        border-radius: 6px;
+        position: relative;
+
+    }
+    .j-wx-code>.code-close{
+        width: 40px;
+        height: 40px;
+        position: absolute;
+        right: -20px;
+        top: -20px;
+        cursor: pointer;
+        -webkit-transition: all 1s;
+        -o-transition: all 1s;
+        -moz-transition: all 1s;
+        transition: all 1s;
+    }
+    .j-wx-code>.code-close:hover{
+        -webkit-transform: scale(1.2);
+        -moz-transform: scale(1.2);
+        -ms-transform: scale(1.2);
+        -o-transform: scale(1.2);
+        transform: scale(1.2);
+    }
+    .j-wx-code>.code-title{
+        height: 82px;
+        background:url(/images/j-wx-code-title.png) center center no-repeat;
+        -webkit-animation: moveYun 15s infinite linear both;
+        -moz-animation: moveYun 15s infinite linear both;
+        -o-animation: moveYun 15s infinite linear both;
+        animation: moveYun 15s infinite linear both;
+    }
+    .j-wx-code>.code-wxm{
+        text-align: center;
+        margin-bottom: -6px;
+        margin-top: -16px;
+
+    }
+    .j-wx-code>.code-wxm>img{
+        width: 200px;
+        height: 200px;
+        margin-top: -5px;
+    }
+    .j-wx-code>.code-text{
+        font: 16px "microsoft yahei";
+        text-align: center;
+        color: #252627;
+    }
+    .j-wx-code>.code-bottom{
+        width: 470px;
+        height: 211px;
+        position: absolute;
+        bottom: -113px;
+        left: -73px;
+        background: url(/images/j-wx-code-bottom.png) 0 0 no-repeat;
+    }
+    .j-wx-code>.code-bottom>img{
+        position: absolute;
+        left: 280px;
+        top: 88px;
+        -webkit-animation: codeWxMove 10s linear both;
+        -moz-animation: codeWxMove 10s linear both;
+        -o-animation: codeWxMove 10s linear both;
+        animation: codeWxMove 10s linear both;
+        -webkit-animation-fill-mode:forwards;
+        -moz-animation-fill-mode:forwards;
+        -o-animation-fill-mode:forwards;
+        animation-fill-mode:forwards;
+    }
+    .recommend_con ul li{
+        float: none;
+    }
+
+    .course_detail .box h1,
+    .course_detail .box h2,
+    .course_detail .box h3,
+    .course_detail .box h4,
+    .course_detail .box h5,
+    .course_detail .box b,
+    .course_detail .box strong {
+      font-weight: 700;
+    }
+    .course_detail .c_middle .box em,
+    .course_detail .c_middle .box i {
+      font-weight: inherit;
+    }
+    .box{
+      line-height:normal;
+    }
+</style>
+<body>
+<!-- header -->
+<section style="line-height: 1;padding-top: 76px;">
+	<!-- main  start -->
+	<div class="course_detail" id="course_detail">
+	    <div class="w" style="min-height: auto">
+	        <div class="advertising">
+				<!--广告-->
+				<div  onclick="adv_statistics(this)" adv_name="PC搜索列表页-底部" class="adv-pcsearch-bottom" id="A1" style="cursor:default;">
+					<script>
+						{{$s:=(Ad "jy-pccourse-detail-right" -1)}}
+						var ADList={{$s}};
+						if(ADList){
+							var random=Math.floor(Math.random()*ADList.length);
+							var AD=ADList[random];
+							var ADHtml = "";
+							if(AD.s_pic){
+								if(AD.s_link){
+									ADHtml += "<a dataHref='"+AD.s_link+"' target='_blank'>";
+								}
+								ADHtml += "<img src='"+AD.s_pic+"'>";
+								if(AD.s_link){
+									ADHtml += "</a>";
+								}
+							}else {
+								ADHtml += AD.s_script;
+							}
+							$("#A1").html(ADHtml);
+						}
+					</script>
+				</div>
+	        </div>
+	        <div class="c_wrap">
+	            <div class="c_top">
+	                <div class="clearfix title">
+	                    <span class="t_name"></span>
+	                    <span class="t_status"></span>
+	                </div>
+	                <div class="price_info">
+	                    <div class="p_price">
+	                        <span class="p_label">价&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;格</span>
+	                        <span class="p_value">¥<strong></strong> 元/人</span>
+	                    </div>
+	                    <div class="p_sale">
+	
+	                    </div>
+	                </div>
+	                <div class="clearfix type_info">
+	                    <div class="type">
+	                        <span class="type_label">课程类型</span>
+	                        <span class="type_value"></span>
+	                    </div>
+	                    <div class="area">
+	                        <span class="area_label">上课地点</span>
+	                        <span class="area_value"></span>
+	                    </div>
+	                </div>
+	                <div class="time_info">
+	                    <span class="time_label">课程时间</span>
+	                    <span class="time_value"></span>
+	                </div>
+	                <div class="handle">
+	                    <a class="buy_btn">立即购买</a>
+	                    <a href="/front/course/helpPage" class="help_btn"><i class="iconfont icon-bangzhu"></i><span>帮助中心</span></a>
+	                </div>
+	            </div>
+	            <div class="c_middle">
+	                <div class="clearfix tabbar">
+	                    <a href="javascript:;" class="tabbar_item active" data-id="a1">课程介绍</a>
+	                    <a href="javascript:;" class="tabbar_item" data-id="a2">课程大纲</a>
+	                    <a href="javascript:;" class="tabbar_item" data-id="a3">购买须知</a>
+	                    <a href="javascript:;" class="tabbar_item" data-id="a4">客户服务</a>
+	                    <div class="handle">
+	                        <a  class="buy_btn">立即购买</a>
+	                        <a href="/front/course/helpPage" class="help_btn"><i class="iconfont icon-bangzhu"></i><span>帮助中心</span></a>
+	                    </div>
+	                </div>
+	                <div class="box">
+						<h2 id="a1">课程介绍</h2>
+						<h2 id="a2">课程大纲</h2>
+						<h2 id="a3">购买须知</h2>
+						<h2 id="a4">客户服务</h2>
+
+	                </div>
+	                <p class="tips"><em>*</em>课程由中国招投标采购培训网提供。</p>
+	            </div>
+	            <div class="c_bottom">
+	                <div class="recommend_con">
+	                    <ul>
+	                    </ul>
+	                </div>
+	            </div>
+	        </div>
+	    </div>
+	</div>
+	<!-- main end -->
+</section>
+<!-- footer -->
+<script>
+    var msgId = {{.T.id}}
+</script>
+<script src="/course/js/course_detail.js"></script>
+</body>
+</html>

+ 234 - 0
core/src/web/templates/manage/entniche_order/entorder.html

@@ -0,0 +1,234 @@
+
+<html>
+<head>
+<title>VIP订阅订单</title>
+{{include "/common/inc.html"}}
+<script src="{{Msg "seo" "cdn"}}/js/jquery.cookie.js"></script>
+<script src="/js/qfwtable.js"></script>
+<style type="text/css">
+#viporder{
+	background-color: #f5f5f5;
+}
+#content table{
+	table-layout: fixed;
+	border:0px;
+	font-size:14px;
+}
+
+.table>thead>tr>th:nth-child(1){
+width:14%;
+}
+.table>thead>tr>th:nth-child(2){
+width:14%;
+}
+.table>thead>tr>th:nth-child(3){
+width:14%;	
+}
+.table>thead>tr>th:nth-child(4){
+width:7%;
+}
+.table>thead>tr>th:nth-child(5){
+	text-align:right;
+	width:14%;
+}
+.table>thead>tr>th:nth-child(6){
+	padding-left:4%;
+	width:14%;
+}
+.table>thead>tr>th:nth-child(7){
+width:14%;
+}
+.table>thead>tr>th:nth-child(8){
+width:14%;
+}
+.table>tbody>tr>td:nth-child(5){
+	text-align:right;
+}
+.table>tbody>tr>td:nth-child(6){
+	padding-left:4%;
+}
+/*
+.table>thead>tr>th:nth-child(9){
+width:10%;
+text-align: center;
+}
+.table>tbody>tr>td:nth-child(9){
+text-align: center;
+}
+*/
+.table>thead>tr>th{
+border:0px;
+font-size:14px;
+}
+.table>tbody>tr>td{
+white-space: nowrap;
+text-overflow: ellipsis;
+overflow: hidden;
+border:0px;
+border-bottom:1px dashed #999999;
+}
+.table >tbody>tr{
+	cursor: pointer;
+}
+#_Container_0{
+background-color:#FFFFFF;
+}
+.buttonStyle{width:64px;height:22px;line-height:22px;color:#369;text-align:center;background:url({{Msg "seo" "cdn"}}/images/buticon.gif) no-repeat left top;border:0;font-size:12px;}
+.buttonStyle:hover{background:url({{Msg "seo" "cdn"}}/images/buticon.gif) no-repeat left -23px;}
+.pagination>.active>a:hover,.pagination>.active>a:focus{
+background-color:#18CC7D;
+}
+#sidebar { margin-left:0px;}
+.hui{color:#999999;}
+.userinfo{
+	margin: 10px -10px 10px;
+	border-radius: 4px !important;
+	height: 38px;
+}
+</style>
+</head>
+<body>
+{{include "/manage/audithead.html"}}
+<div class="row" style="width:96%; margin:0 auto;">
+{{include "/manage/slider.html"}}
+	<div id="content">
+		<div id="audit"></div>
+	</div>	
+</div>
+{{include "/common/bottom.html"}}
+</body>
+<script>
+$(function(){
+	$("#audit").datatable({
+		   perPage: 10
+		  ,showPagination:true
+		  ,checkbox:"" //check radio
+		  ,checkboxHeader:false
+		  ,idField:"_id"
+		  ,classname:"table-hover"
+		  ,css:{"height":"450px"}
+		  //,post:{"name":"ee"}
+		  //<div style="width:27%;margin:10px" class="input-group pull-left" id="search"><input type="text" id="searchtextByOpenId" value=""  data-original-title="Search" class="form-control" placeholder="请输入用户openid"><span class="input-group-btn"><button class="btn btn-success" onclick="SearchContentByOpenId()" data-original-title="Search" id="searchtip" type="button" style="height:38px;">查看用户订单</button></span></div>
+		  ,buttons: ['<div style="width:50%;margin:5px" class="input-group pull-right" id="search"><input type="text" id="searchtext" value=""  data-original-title="Search" class="form-control" placeholder="请输入订单编号"><span class="input-group-btn"><button class="btn btn-success" onclick="SearchContent()" data-original-title="Search" id="searchtip" type="button" style="height:38px;">检索</button></span></div><div style="margin:5px;" class="controls pull-right"><select class="form-control" id="select1"><option value="">  订单状态  </option><option value="1">  已支付 </option><option value="0">  未支付 </option><option value="-2">  已取消 </option></select></div>']
+		  , url: '/manage/entnicheOrder/p'
+		  , columns: [
+				{
+		            title: "序号", field: "index"	
+		        },
+				{
+		            title: "产品类型", field: "product_type"
+		        },
+				{
+		            title: "购买时间",field: "pay_time"
+		        },
+				{
+		            title: "订单状态", field: "order_status"
+		        },
+				{
+		            title: "价格", field: "order_money"
+					,callback:function(ct,cd,val,k,m){
+						if(ct["order_money"]){
+						//return 	ct["order_money"]/100+"元"
+						//保留小数点后两位
+						var o_money =ct["order_money"]/100
+						if (o_money!=0){
+							var a = num(o_money)
+						}else{
+							var a="0"
+						}
+						//return "<div style='padding-right:50%'>"+a+"</div>"
+						return a;
+						}else{
+							return "0";	//升级费用为0
+						}
+					}
+		        },
+				{
+		            title: "发票状态", field: "applybill_status"
+		        },
+				{
+		            title: "发票单位", field: "applybill_company"
+		        },
+				/*{
+		            title: "邮箱", field: "user_mail"
+					,callback:function(ct,cd,val,k,m){
+						if(ct["user_mail"]){
+							return ct["user_mail"];
+						}else{
+							return "-";	//升级费用为0
+						}
+					}
+		        },
+				{
+		            title: "下载链接", field: "download_url"
+					,callback:function(ct,cd,val,k,m){
+						if(ct["download_url"]){
+						return "<a href='"+ct["download_url"]+"' title='"+ct["download_url"]+"'>"+   ct["download_url"]+"</a>"	
+						}
+					}
+		        },
+				{
+		            title: "数据发送状态", field: "service_status"
+		        }
+				*/
+		        {
+		            title: "", field: "order_code"
+					,callback:function(ct,cd,val,k,m){
+						if(ct["order_code"]){
+							var a=ct["order_code"]
+						return "<a style='display:none' onclick='redirect(\""+ct["order_code"]+"\")' style='color:#4e5051;text-decoration:none'>"+   ct["order_code"]+"</a>"
+						}
+					}	
+		        }
+		    ]
+		});
+
+	$("select").change(function(){
+	//$("body").on("change","select",function(){
+		//选择已支付,才能选择是否发送成功
+		if($("#select1").val()=="0"){
+			$("#select2").val("").attr("disabled","disabled");
+		}else{
+			$("#select2").removeAttr("disabled","disabled");
+		}
+		var find=$("#audit").data("datatable");
+		if(!find.options.opost) find.options.opost=find.options.post||{};
+		find.options.post=$.extend(find.options.opost,{strSel1:$("#select1").val(),strSel2:$("#select2").val(),strSel3:$("#select3").val()});
+		find.options.currentPage=1;
+		find.render();
+	});
+	//事件委托
+	$("#content").on("click","#audit>.dt-table-wrapper>.table>tbody>tr",function(){
+		var code = $(this).children().last().children().html();
+		window.open("/manage/entnicheOrder/entnicheOrderDetail/"+code)
+	});
+	
+});
+
+//点击跳转新页面	//TODO 
+function redirect(code){
+	//sessionStorage.setItem("contentHtml",$("#content").prop("outerHTML"));
+	window.open("/manage/entnicheOrder/entnicheOrderDetail/"+code);
+}
+//
+function SearchContent(){
+	var find=$("#audit").data("datatable");
+	if(!find.options.opost) find.options.opost=find.options.post||{};
+	find.options.post=$.extend(find.options.opost,{query:$("#searchtext").val()});
+	find.options.currentPage=1;
+	find.render();
+}//
+function SearchContentByOpenId(){
+	var find=$("#audit").data("datatable");
+	if(!find.options.opost) find.options.opost=find.options.post||{};
+	find.options.post=$.extend(find.options.opost,{queryByOpenId:$("#searchtextByOpenId").val()});
+	find.options.currentPage=1;
+	find.render();
+}
+//保留小数点后两位的方法
+function num(i) {
+	var n = i.toFixed(2);
+	return n
+}
+</script>
+</html>

+ 225 - 0
core/src/web/templates/manage/entniche_order/entorderdetail.html

@@ -0,0 +1,225 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width, initial-scale=1">
+		<title>VIP订阅订单详情</title>
+		{{include "/common/inc.html"}}
+		<link rel="stylesheet" type="text/css" href="{{Msg "seo" "cdn"}}/dataexport/base.css"/>
+		<link rel="stylesheet" type="text/css" href="{{Msg "seo" "cdn"}}/dataexport/dataExport.css"/>
+	</head>
+	<style>
+	.nofloat{float:none}
+	body {
+	    padding-top: 0px;
+	    font-family: tahoma, arial, 'Hiragino Sans GB', 'Microsoft YaHei', 宋体, sans-serif;
+	    color: #4e5051;
+	    background: #f5f5fb;
+	}
+	#viporder {
+	    background-color: #f5f5f5;
+	}
+	.cont-one, .row {
+   		margin-top: 20px  !important;
+	}
+	.pbtn{
+		margin: 20px;
+	    background: #00bcd4;
+		user-select: none;
+	    float: right;
+	    width: 100px;
+	    height: 35px;
+	    line-height: 35px;
+	    text-align: center;
+	    color: #fff;
+      text-decoration:none;
+	}
+  .pbtn:hover{
+      text-decoration:none;
+      color:#fff;
+  }
+  .pbtn:visited {   
+      text-decoration: none;  
+  }
+  .pbtn:link {
+    text-decoration: none;  
+  }
+  .imgdiv{
+    padding: 27px 120px;
+    background: #fff;
+  }
+  .imgdiv img{
+    height: 200px;
+    width:30%;
+    max-width: 300px;
+  }  
+.right .order_info .bd .line, .right .download_link .bd .line, .right .filter .bd .line {
+    float: left;
+    width: 1px;
+    height: 150px !important;
+    background: #ddd;
+    margin-top: 20px;
+}
+.right {
+    float: right;
+    width: calc(100% - 220px);
+    border: 1px solid #ddd;
+    min-height: 658px;
+    background-color: #fff;
+}
+
+/*--------------------------------------------------------*/
+.right .order_info .bd .first, .right .download_link .bd .first, .right .filter .bd .first {
+    padding-left: 14px;
+    width: 50%;
+}
+.payinfo .hd{
+    height: 34px;
+    line-height: 34px;
+    background: #f7f8fa;
+    padding-left: 120px;
+    font-size: 14px;
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+}
+.title h4{
+	height: 78px;
+    line-height: 78px;
+    padding-left: 35px;
+    font-size: 16px;
+    background: #fff;
+}.orderstatus{
+	display:inline-block;
+	margin-left:20px;
+}
+
+	</style>
+	<body>
+		{{include "/manage/audithead.html"}}
+		<div class="main">
+			<div class="left">
+			{{include "/manage/slider.html"}}</div>
+			<div class="right" style="color:#4e5051">
+				<div class="title">
+					<h4>企业商机管理<div class="orderstatus">{{.T.res.order_status}}</div></h4>
+				</div>
+				<script>
+					var order_status={{.T.res.order_status}};
+					console.log(order_status)
+					if (order_status=="已取消"){
+						$(".orderstatus").css("color","orange")
+					}else if (order_status=="已支付"){
+						$(".orderstatus").css("color","green")
+					}else if (order_status=="未支付") {
+						$(".orderstatus").css("color","red")
+					}
+				</script>
+				
+				<!-- 订单信息 -->
+				<div class="order_info" >
+					<div class="hd">订单信息</div>
+					<div class="bd clearfix" style="padding-right: 65px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">企业信息:{{.T.filterData.entname}}</li>
+							<li class="row-list nofloat">管理员:{{.T.filterData.adminname}}</li>
+							<li class="row-list nofloat">使用产品人数:{{.T.filterData.personnum}}人</li>
+						</ul>
+						<div class="line"></div>
+						<ul class="row third"  style="margin-top:20px  !important;padding-right: 0px; margin-left:20px ">	
+							<li class="row-list nofloat">行业:{{.T.filterData.industry}}</li>
+							<li class="row-list nofloat">手机号:{{.T.filterData.phone}}</li>
+							<li class="row-list nofloat">使用周期:{{.T.filterData.cycle}}年</li>
+						</ul>
+					</div>
+				</div>
+				
+				
+				<div class="payinfo order_info">
+					<div class="hd">支付信息</div>
+					<div class="bd clearfix" style="padding-right: 65px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">订单编号:{{.T.res.order_code}}</li>
+							<li class="row-list nofloat">下单时间:{{.T.res.create_time}}</li>
+							{{if eq .T.res.order_status "已支付"}}
+							<li class="row-list nofloat">支付时间:{{.T.res.pay_time}}</li>
+							{{else}}
+							<li class="row-list nofloat">支付时间:-</li>
+							{{end}}
+						</ul>
+						<div class="line"></div>
+						<ul class="row third"  style="margin-top:20px  !important;padding-right: 0px; margin-left:20px ">	
+							<li class="row-list nofloat">支付方式:{{.T.res.pay_way}}</li>
+							<li class="row-list nofloat">支付单号:{{.T.transaction_id}}</li>
+						</ul>
+					</div>
+				</div>
+				
+				<!-- 筛选条件 -->
+				<div class="payinfo order_info">
+					<div class="hd">发票信息</div>
+					<div class="bd clearfix" style="padding-right: 65px;">
+						<ul class="row first"  style="margin-top:20px  !important;">
+							<li class="row-list nofloat">发票类型:普通发票(电子发票)</li>
+							{{if eq .T.res.order_status "未支付"}}
+							<li class="row-list nofloat">发票抬头:-</li>
+							{{else}}
+							<li class="row-list nofloat">发票抬头:{{.T.res.applybill_type}}</li>
+							{{end}}
+							{{if .T.res.applybill_type}}
+							{{if eq .T.res.applybill_type "个人"}}
+							<li class="row-list nofloat" style="display:none">开票单位名称:{{.T.res.applybill_company}}</li>
+							{{else}}
+							{{if eq .T.res.order_status "已支付"}}<li class="row-list nofloat">开票单位名称:{{.T.res.applybill_company}}</li>{{end}}
+							{{end}}
+							{{end}}
+						</ul>
+						<div class="line"></div>
+						<ul class="row third"  style="margin-top:20px  !important;padding-right: 0px; margin-left:20px ">	
+							<li class="row-list nofloat">发票内容:明细</li>
+							<li class="row-list nofloat"> &nbsp</li>
+							{{if eq .T.res.applybill_type "个人"}}
+							<li class="row-list nofloat" style="display:none">纳税人识别号:{{.T.res.applybill_taxnum}}</li>
+							{{else}}
+							<li class="row-list nofloat">纳税人识别号:{{.T.res.applybill_taxnum}}</li>
+							{{end}}
+						</ul>
+					</div>
+				</div>
+
+			</div>
+		</div>
+		{{include "/common/bottom.html"}}
+    <script>
+      function view(obj){
+      	var src=obj.src
+      	if(!src){
+      		alert("请先上传图片");
+      	}
+      	if($("#tooltip1").size()>0){
+      		$("#tooltip1").remove()
+      	}else{	
+      		var nimg=getNaturalWH(src);
+      		var mt=$(document).scrollTop();
+      		var tw1=nimg[0],th1=nimg[1];
+      		var tooltip = "<div id='tooltip1' style='border:1px solid gray;width:"+tw1+"px;height:"+th1+"px;padding:0;overflow:auto'><img src='" + src + "'/></div>";
+      		$("body").append(tooltip);
+      		var smargin=(mt-(parseInt(th1)/2))+"px 0px 0px -"+(parseInt(tw1)/2)+"px";
+      		$("#tooltip1").css({
+      			"position":"absolute",
+      			"z-index":2000,
+      			"margin":smargin,
+      			"top":"50%",
+      			"left":"50%"
+      		}).show("fast").click(function(e){
+      			$("#tooltip1").remove()
+      		});
+      	}
+      }
+      function getNaturalWH(src){
+  	    var image = new Image();
+  	    image.src = src;		
+  	    return [image.width+10,image.height+10];
+      }
+    </script>
+	</body>
+</html>

+ 5 - 2
core/src/web/templates/manage/slider.html

@@ -4,15 +4,18 @@
 		<i class="glyphicon glyphicon-list-alt"></i> <span>企业审核</span></a></li>
 		<li id="expess"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/articlelist"><i class="glyphicon glyphicon-facetime-video"></i> <span>信息发布</span></a></li>
 		<li id="feedback"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/feedback"><i class="glyphicon glyphicon-share"></i> <span>意见反馈</span></a></li>
+		<li id="course"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/course/index"><i class="glyphicon course-icon"></i> <span>招投标课程管理</span></a></li>
+		<li id="courseOrder"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/courseOrder/index"><i class="glyphicon course-icon"></i> <span>招投标订单管理</span></a></li>
 		<li id="seo"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/seo"><i class="glyphicon glyphicon-euro"></i> <span>SEO优化</span></a></li>
 		<li id="ad"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/ad"><i class="glyphicon glyphicon-th-large"></i> <span>广告管理</span></a></li>
 		<li id="count"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/count"><i class="glyphicon glyphicon-signal"></i> <span>数据统计</span></a></li>
 		<li id="cauditbar"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/caudit"><i class="glyphicon glyphicon-user"></i> <span>开发者认证</span></a></li>
 		<li id="message"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/message/index"><i class="glyphicon glyphicon-comment"></i> <span>消息管理</span></a></li>
-    <li id="dataReportOrder"  class="list-group-item"><a style=" font-weight:normal;"  href="/manage/dataReportOrder/list"><i class="glyphicon glyphicon-download-alt"></i> <span>数据报告</span></a></li>
+    	<li id="dataReportOrder"  class="list-group-item"><a style=" font-weight:normal;"  href="/manage/dataReportOrder/list"><i class="glyphicon glyphicon-download-alt"></i> <span>数据报告</span></a></li>
 		<li id="dataExportOrder"  class="list-group-item"><a style=" font-weight:normal;"  href="/manage/dataExportOrder/list"><i class="glyphicon glyphicon-download-alt"></i> <span>数据导出订单</span></a></li>
 		<li id="viporder"  class="list-group-item"><a style=" font-weight:normal;"  href="/manage/vipOrder/list"><i class="glyphicon glyphicon-download-alt"></i> <span>VIP订阅订单</span></a></li>
-    <li id="pcUndate"  class="list-group-item"><a style=" font-weight:normal;" onclick="pushVersion()"><i class="glyphicon glyphicon-level-up"></i> <span>PC助手版本更新</span></a></li>
+		<li id="entnicheorder"  class="list-group-item"><a style=" font-weight:normal;"  href="/manage/entnicheOrder/list"><i class="glyphicon glyphicon-download-alt"></i> <span>企业商机管理</span></a></li>
+    	<li id="pcUndate"  class="list-group-item"><a style=" font-weight:normal;" onclick="pushVersion()"><i class="glyphicon glyphicon-level-up"></i> <span>PC助手版本更新</span></a></li>
 		<!-- <li id="jydata"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/data/index"><i class="glyphicon glyphicon-euro"></i> <span>剑鱼数据管理</span></a></li>
 		<li id="databack"  class="list-group-item"><a style=" font-weight:normal;" href="/manage/data/back"><i class="glyphicon glyphicon-euro"></i> <span>剑鱼备份数据</span></a></li> -->
 		<li id="sendMessage"  class="sendActive list-group-item" style="border-bottom-left-radius: 4px; border-bottom-right-radius: 4px;"><a style="font-weight:normal;"  data-toggle="collapse" 

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.