Jelajahi Sumber

设计数量表

caipin 4 tahun lalu
melakukan
1127f8ed76
100 mengubah file dengan 12888 tambahan dan 0 penghapusan
  1. 8 0
      .gitignore
  2. 214 0
      bootstrap/bootstrap.go
  3. 56 0
      comm/account_group.go
  4. 19 0
      comm/client.go
  5. 104 0
      comm/func_web.go
  6. 571 0
      comm/functions.go
  7. 50 0
      conf/db.go
  8. 48 0
      conf/project.go
  9. 37 0
      conf/redis.go
  10. 69 0
      dao/annex_dao.go
  11. 989 0
      dao/approver_dao.go
  12. 251 0
      dao/bid_account_dao.go
  13. 88 0
      dao/bidsection_dao.go
  14. 396 0
      dao/contract_dao.go
  15. 155 0
      dao/contract_paid_dao.go
  16. 167 0
      dao/contract_return_dao.go
  17. 84 0
      dao/manager_dao.go
  18. 129 0
      dao/permission_account_dao.go
  19. 145 0
      dao/project_account_dao.go
  20. 104 0
      dao/project_dao.go
  21. 36 0
      dao/project_message_dao.go
  22. 108 0
      dao/quality_audit_dao.go
  23. 224 0
      dao/quality_dao.go
  24. 58 0
      dao/rule_dao.go
  25. 108 0
      dao/safe_audit_dao.go
  26. 221 0
      dao/safe_dao.go
  27. 556 0
      dao/tree_contract_dao.go
  28. 415 0
      dao/tree_dao.go
  29. 39 0
      dao/version_dao.go
  30. 52 0
      datasource/dbhelper.go
  31. 99 0
      datasource/rdshelper.go
  32. 15 0
      deployment/Dockerfile
  33. 23 0
      deployment/cm.sh
  34. 37 0
      deployment/cm.yaml
  35. 33 0
      deployment/nginx.yaml
  36. 67 0
      deployment/nginxconf.yaml
  37. 17 0
      deployment/test.sh
  38. 86 0
      learn/struct.go
  39. 42 0
      learn/structEntry/structEntry.go
  40. 11 0
      lib/bidsection_ids.go
  41. 116 0
      lib/cld.go
  42. 145 0
      lib/item_section.go
  43. 49 0
      lib/jlzf.go
  44. 73 0
      lib/permission.json
  45. 53 0
      lib/redis.go
  46. 106 0
      lib/section_template1.json
  47. 122 0
      lib/section_template2.json
  48. 14 0
      lib/tree.go
  49. 7 0
      models/PDMAN_DB_VERSION.go
  50. 16 0
      models/cm_annex.go
  51. 13 0
      models/cm_approver.go
  52. 8 0
      models/cm_bid_account.go
  53. 31 0
      models/cm_bidsection.go
  54. 29 0
      models/cm_contracts.go
  55. 22 0
      models/cm_contracts_paid.go
  56. 22 0
      models/cm_contracts_return.go
  57. 15 0
      models/cm_folder.go
  58. 13 0
      models/cm_group.go
  59. 12 0
      models/cm_log.go
  60. 9 0
      models/cm_maintain.go
  61. 27 0
      models/cm_manager.go
  62. 19 0
      models/cm_message.go
  63. 12 0
      models/cm_permission.go
  64. 11 0
      models/cm_permission_account.go
  65. 38 0
      models/cm_project.go
  66. 40 0
      models/cm_project_account.go
  67. 17 0
      models/cm_project_message.go
  68. 21 0
      models/cm_quality.go
  69. 18 0
      models/cm_quality_audit.go
  70. 11 0
      models/cm_rule.go
  71. 21 0
      models/cm_safe.go
  72. 18 0
      models/cm_safe_audit.go
  73. 15 0
      models/cm_safe_file.go
  74. 35 0
      models/cm_tree.go
  75. 29 0
      models/cm_tree_contracts.go
  76. 13 0
      models/cm_valuation_list.go
  77. 12 0
      models/cm_version.go
  78. 11 0
      models/cm_white_list.go
  79. 128 0
      services/annex_service.go
  80. 257 0
      services/backstage_service.go
  81. 181 0
      services/bid_account_service.go
  82. 116 0
      services/bidsection_service.go
  83. 156 0
      services/contract_expenditure_service.go
  84. 267 0
      services/contract_paid_service.go
  85. 273 0
      services/contract_return_service.go
  86. 471 0
      services/contract_section_tree_service.go
  87. 677 0
      services/contract_service.go
  88. 248 0
      services/login_service.go
  89. 53 0
      services/manager_service.go
  90. 522 0
      services/project_account_service.go
  91. 63 0
      services/project_message_service.go
  92. 280 0
      services/project_service.go
  93. 150 0
      services/quality_audit.service.go
  94. 374 0
      services/quality_service.go
  95. 65 0
      services/rpc_service.go
  96. 156 0
      services/rule_service.go
  97. 149 0
      services/safe_audit.service.go
  98. 456 0
      services/safe_service.go
  99. 672 0
      services/tree_service.go
  100. 0 0
      services/version_service.go

+ 8 - 0
.gitignore

@@ -0,0 +1,8 @@
+.vscode/
+/web/web.exe
+/go.sum
+/go.mod
+/web/docs/docs.go
+/web/docs/swagger.json
+/web/docs/swagger.yaml
+/web/main.go

+ 214 - 0
bootstrap/bootstrap.go

@@ -0,0 +1,214 @@
+/*
+ * @description:web项目启动
+ * @Author: CP
+ * @Date: 2020-08-21 11:20:00
+ * @FilePath: \construction_management\bootstrap\bootstrap.go
+ */
+package bootstrap
+
+import (
+	"time"
+
+	"github.com/iris-contrib/middleware/csrf"
+	"github.com/kataras/iris/v12"
+	"github.com/kataras/iris/v12/middleware/logger"
+	"github.com/kataras/iris/v12/middleware/recover"
+	"go.mod/conf"
+)
+
+//配置器,定制化的配置--方法类型
+type Configurator func(*Bootstrapper)
+
+//GCJSXM88CP20200902666A477C084477
+// const csrfKey = "GCJSXM88CP20200902666A477C084477"
+
+//结构体扩展iris,类此于继承
+type Bootstrapper struct {
+	*iris.Application
+	AppName      string
+	AppOwner     string
+	AppSpawnDate time.Time
+}
+
+//var RpcConnect *grpc.ClientConn
+func init() {
+	// log.Println("RpcConnect 初始化中...")
+	// conn, err := grpc.Dial(conf.NodeRpcHost, grpc.WithInsecure())
+	// if err != nil {
+	// 	log.Fatalf("did not connect: %v", err)
+	// }
+	// RpcConnect = conn
+	// log.Println("RpcConnect 初始化成功")
+}
+
+//新建和返回一个Bootstrapper
+func New(appName, appOwner string, cfgs ...Configurator) *Bootstrapper {
+	b := &Bootstrapper{
+		AppName:      appName,
+		AppOwner:     appOwner,
+		AppSpawnDate: time.Now(),
+		Application:  iris.New(),
+	}
+
+	//数组遍历 cfg方法
+	for _, cfg := range cfgs {
+		cfg(b)
+	}
+
+	return b
+}
+
+//Bootstrapper的方法 读取模板
+func (b *Bootstrapper) SetupViews(viewsDir string) {
+	htmlEngine := iris.HTML(viewsDir, ".html").Layout("shared/layout.html")
+	// 每次重新加载模版(线上关闭它)
+	htmlEngine.Reload(true)
+	// 给模版内置各种定制的方法
+	htmlEngine.AddFunc("FromUnixtimeShort", func(t int) string {
+		dt := time.Unix(int64(t), int64(0))
+		return dt.Format(conf.SysTimeformShort)
+	})
+	htmlEngine.AddFunc("FromUnixtime", func(t int) string {
+		dt := time.Unix(int64(t), int64(0))
+		return dt.Format(conf.SysTimeform)
+	})
+	b.RegisterView(htmlEngine)
+}
+
+// 配置csrf
+func (b *Bootstrapper) SetupCsrfHandlers(csrfKey string) {
+	protect := csrf.Protect([]byte(csrfKey), csrf.FieldName("csrf"), csrf.Secure(false), csrf.Path("/"), csrf.ErrorHandler(func(ctx iris.Context) {
+		ctx.JSON(iris.Map{"code": -1, "msg": "CSRF token invalid"})
+	}))
+	//csrf.Domain("")
+
+	// , csrf.Domain("cmr.com"), csrf.Path("/")
+	b.Party("/", protect)
+}
+
+// 配置jwt
+// func (b *Bootstrapper) SetupJwtHandlers(jwtKey string) {
+
+// j2 := jwt.New(jwt.Config{
+// 	// 注意,新增了一个错误处理函数
+// 	ErrorHandler: func(ctx iris.Context, err error) {
+// 		if err == nil {
+// 			return
+// 		}
+
+// 		ctx.StopExecution()
+// 		ctx.StatusCode(iris.StatusUnauthorized)
+// 		ctx.JSON(ResModel{
+// 			Code: "501",
+// 			Msg:  err.Error(),
+// 		})
+// 	},
+// 	// 设置一个函数返回秘钥,关键在于return []byte("这里设置秘钥")
+// 	ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
+// 		return []byte(jwtKey), nil
+// 	},
+
+// 	// 设置一个加密方法
+// 	SigningMethod: jwt.SigningMethodHS256,
+// })
+
+// 	//b.Party("/", j2.Serve)
+// }
+
+// 装配rpcClient
+func (b *Bootstrapper) SetupRpcClient() {
+	// b.Use(func(ctx iris.Context) {
+	// 	ctx.Values().Set("RpcConnect", RpcConnect)
+	// 	ctx.Next()
+	// })
+	// log.Println("RpcConnect 注入成功")
+}
+
+//处理异常--设置错误信息展示
+func (b *Bootstrapper) SetupErrorHandlers() {
+	b.OnAnyErrorCode(func(ctx iris.Context) {
+		// err := iris.Map{
+		// 	"app":     b.AppName,
+		// 	"status":  ctx.GetStatusCode(),
+		// 	"message": ctx.Values().GetString("message"),
+		// }
+		//如果是json格式,使用json方式输出
+		// if jsonOutput := ctx.URLParamExists("json"); jsonOutput {
+		// 	ctx.JSON(err)
+		// 	return
+		// }
+
+		// ctx.ViewData("Err", err)
+		// ctx.ViewData("Title", "Error")
+		// ctx.View("shared/error.html")
+
+		ctx.JSON(iris.Map{"code": -1, "msg": "请求错误,请检查"})
+
+	})
+}
+
+//配置的方法 Configure accepts configurations and runs them inside the Bootstraper's context.
+func (b *Bootstrapper) Configure(cs ...Configurator) {
+	for _, c := range cs {
+		c(b)
+	}
+}
+
+// 启动计划任务服务
+func (b *Bootstrapper) setupCron() {
+	// TODO
+}
+
+const (
+	StaticAssets = "./public"
+	Favicon      = "/favicon.ico"
+	//20200902GCJSXM7C084477AEA06096F5
+	//9AB0F421E53A477C084477AEA06096F5
+	CsrfKey = "9AB0F421E53A477C084477AEA06096F5"
+	JwtKey  = "9AB0F421E53A477C084477AEA06096F5"
+)
+
+// 初始化Bootstrap
+// Returns itself.
+func (b *Bootstrapper) Bootstrap() *Bootstrapper {
+	//设置模板
+	//b.SetupViews("./views")
+	// b.SetupSessions(24*time.Hour,
+	// 	[]byte("the-big-and-secret-fash-key-here"),
+	// 	[]byte("lot-secret-of-characters-big-too"),
+	// )
+	// 设置csrf
+	b.SetupCsrfHandlers(CsrfKey)
+	// 设置jwt
+	//b.SetupJwtHandlers(JwtKey)
+	// 设置rpc
+	//b.SetupRpcClient()
+	//设置异常信息
+	b.SetupErrorHandlers()
+
+	// static files
+	//b.Favicon(StaticAssets + Favicon)
+	//b.StaticWeb(StaticAssets[1:], StaticAssets)
+	b.HandleDir(StaticAssets[1:], iris.Dir(StaticAssets))
+	b.HandleDir("/docs", iris.Dir("./docs"))
+	// indexHtml, err := ioutil.ReadFile(StaticAssets + "/index.html")
+	// if err == nil {
+	// 	b.StaticContent(StaticAssets[1:]+"/", "text/html",
+	// 		indexHtml)
+	// }
+	// 不要把目录末尾"/"省略掉
+	//iris.WithoutPathCorrectionRedirection(b.Application)
+
+	// crontab
+	b.setupCron()
+
+	// middleware, after static files
+	b.Use(recover.New())
+	b.Use(logger.New())
+
+	return b
+}
+
+func (b *Bootstrapper) Listen(addr string, cfgs ...iris.Configurator) {
+	b.Run(iris.Addr(addr), cfgs...)
+}

+ 56 - 0
comm/account_group.go

@@ -0,0 +1,56 @@
+/*
+ * @description:账号组相关
+ * @Author: CP
+ * @Date: 2020-10-10 16:00:05
+ * @FilePath: \construction_management\comm\account_group.go
+ */
+package comm
+
+import "errors"
+
+type AccountGroup struct {
+	JSDW int
+	JLDW int
+	SGDW int
+	SJDW int
+	DJDW int
+	GZSJ int
+	QT   int
+}
+
+func NewAccountGroup() *AccountGroup {
+	return &AccountGroup{
+		JSDW: 1,
+		JLDW: 2,
+		SGDW: 3,
+		SJDW: 4,
+		DJDW: 5,
+		GZSJ: 6,
+		QT:   7,
+	}
+}
+
+// 验证输入
+func (a *AccountGroup) ValidRule(index int) error {
+	if a.JSDW == index || a.JLDW == index || a.SGDW == index || a.SJDW == index || a.DJDW == index || a.GZSJ == index || a.QT == index {
+		return nil
+	} else {
+		return errors.New("账号组不正确")
+	}
+}
+
+// ID转文字描述
+
+// const AccountGroup:=map[string]int{
+// 	"JSDW": 1,
+//     "JLDW": 2,
+//     "SGDW": 3,
+//     "SJDW": 4,
+//     "DJDW": 5,
+//     "GZSJ": 6,
+//     "QT": 7,
+// }
+
+// const Group:=[...]string{
+// 	AccountGroup.
+// }

+ 19 - 0
comm/client.go

@@ -0,0 +1,19 @@
+/*
+ * @description:第三方请求相关
+ * @Author: CP
+ * @Date: 2020-09-03 16:19:26
+ * @FilePath: \construction_management\comm\client.go
+ */
+package comm
+
+import "github.com/kirinlabs/HttpRequest"
+
+func sendRequest(url string, data map[string]string, method string, dataType string) map[string]string {
+	req := HttpRequest.NewRequest()
+	//req := HttpRequest.NewRequest().Debug(debug).SetTimeout(5)
+	if dataType == "JSON" {
+		req.SetHeaders(map[string]string{"Content-Type": "application/json"})
+	}
+
+	return nil
+}

+ 104 - 0
comm/func_web.go

@@ -0,0 +1,104 @@
+/*
+ * @description:web共用方法
+ * @Author: CP
+ * @Date: 2020-08-21 11:12:56
+ * @FilePath: \construction_management\comm\func_web.go
+ */
+package comm
+
+import (
+	"net/http"
+
+	"net"
+)
+
+// 得到客户端IP地址
+func ClientIP(request *http.Request) string {
+	host, _, _ := net.SplitHostPort(request.RemoteAddr)
+	return host
+}
+
+// 跳转URL
+func Redirect(writer http.ResponseWriter, url string) {
+	writer.Header().Add("Location", url)
+	writer.WriteHeader(http.StatusFound)
+}
+
+// // 从cookie中得到当前登录的用户
+// func GetLoginUser(request *http.Request) *models.ObjLoginuser {
+// 	c, err := request.Cookie("lottery_loginuser")
+// 	if err != nil {
+// 		return nil
+// 	}
+// 	params, err := url.ParseQuery(c.Value)
+// 	if err != nil {
+// 		return nil
+// 	}
+// 	uid, err := strconv.Atoi(params.Get("uid"))
+// 	if err != nil || uid < 1 {
+// 		return nil
+// 	}
+// 	// Cookie最长使用时长
+// 	now, err := strconv.Atoi(params.Get("now"))
+// 	if err != nil || NowUnix()-now > 86400*30 {
+// 		return nil
+// 	}
+// 	//// IP修改了是不是要重新登录
+// 	//ip := params.Get("ip")
+// 	//if ip != ClientIP(request) {
+// 	//	return nil
+// 	//}
+// 	// 登录信息
+// 	loginuser := &models.ObjLoginuser{}
+// 	loginuser.Uid = uid
+// 	loginuser.Username = params.Get("username")
+// 	loginuser.Now = now
+// 	loginuser.Ip = ClientIP(request)
+// 	loginuser.Sign = params.Get("sign")
+// 	if err != nil {
+// 		log.Println("fuc_web GetLoginUser Unmarshal ", err)
+// 		return nil
+// 	}
+// 	sign := createLoginuserSign(loginuser)
+// 	if sign != loginuser.Sign {
+// 		log.Println("fuc_web GetLoginUser createLoginuserSign not sign", sign, loginuser.Sign)
+// 		return nil
+// 	}
+
+// 	return loginuser
+// }
+
+// // 将登录的用户信息设置到cookie中
+// func SetLoginuser(writer http.ResponseWriter, loginuser *models.ObjLoginuser) {
+// 	if loginuser == nil || loginuser.Uid < 1 {
+// 		c := &http.Cookie{
+// 			Name:   "lottery_loginuser",
+// 			Value:  "",
+// 			Path:   "/",
+// 			MaxAge: -1,
+// 		}
+// 		http.SetCookie(writer, c)
+// 		return
+// 	}
+// 	if loginuser.Sign == "" {
+// 		loginuser.Sign = createLoginuserSign(loginuser)
+// 	}
+// 	params := url.Values{}
+// 	params.Add("uid", strconv.Itoa(loginuser.Uid))
+// 	params.Add("username", loginuser.Username)
+// 	params.Add("now", strconv.Itoa(loginuser.Now))
+// 	params.Add("ip", loginuser.Ip)
+// 	params.Add("sign", loginuser.Sign)
+// 	c := &http.Cookie{
+// 		Name:  "lottery_loginuser",
+// 		Value: params.Encode(),
+// 		Path:  "/",
+// 	}
+// 	http.SetCookie(writer, c)
+// }
+
+// // 根据登录用户信息生成加密字符串
+// func createLoginuserSign(loginuser *models.ObjLoginuser) string {
+// 	str := fmt.Sprintf("uid=%d&username=%s&secret=%s", loginuser.Uid, loginuser.Username, conf.CookieSecret)
+// 	return CreateSign(str)
+// }

+ 571 - 0
comm/functions.go

@@ -0,0 +1,571 @@
+/*
+ * @description: 常用函数
+ * @Author: CP
+ * @Date: 2020-08-21 11:12:56
+ * @FilePath: \construction_management\comm\functions.go
+ */
+package comm
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"encoding/base64"
+	"errors"
+	"math"
+	"math/rand"
+	"time"
+	"unicode"
+
+	"crypto/md5"
+	"encoding/binary"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"go.mod/conf"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+// 账号-构造视图层models
+func MakeProjectAccountVM(modelsAccount *models.CmProjectAccount) viewmodels.ProjectAccount {
+	viewAccountData := viewmodels.ProjectAccount{}
+	aesId, _ := AesEncrypt(strconv.Itoa(modelsAccount.Id), conf.SignSecret)
+	aesProjectId, _ := AesEncrypt(strconv.Itoa(modelsAccount.ProjectId), conf.SignSecret)
+	viewAccountData.Id = aesId
+	viewAccountData.ProjectId = aesProjectId
+	viewAccountData.Account = modelsAccount.Account
+	viewAccountData.Name = modelsAccount.Name
+	viewAccountData.Company = modelsAccount.Company
+	viewAccountData.Role = modelsAccount.Role
+	viewAccountData.Mobile = modelsAccount.Mobile
+	viewAccountData.Telephone = modelsAccount.Telephone
+	viewAccountData.IsAdmin = modelsAccount.IsAdmin
+	viewAccountData.AccountGroup = modelsAccount.AccountGroup
+	viewAccountData.Enable = modelsAccount.Enable
+	viewAccountData.Position = modelsAccount.Position
+
+	// viewAccountData.ContractPermission = modelsAccount.ContractPermission
+	// viewAccountData.QualityPermission = modelsAccount.QualityPermission
+	// viewAccountData.SafePermission = modelsAccount.SafePermission
+
+	return viewAccountData
+}
+
+// 创建合同目录树
+func MakeFolderContract(Data []*viewmodels.FolderContract, node *viewmodels.FolderContract) { //参数为父节点,添加父节点的子节点指针切片
+	childs, _ := HaveChildContract(Data, node) //判断节点是否有子节点并返回
+	if childs != nil {
+		// 子节点总数
+		Total := len(childs)
+		node.ChildsTotal = Total
+		// 标记最后一个元素
+		end := Total - 1
+		childs[end].IsEnd = true
+		// 往父节点添加子节点
+		node.Children = append(node.Children, childs[0:]...) //添加子节点
+
+		// 1.标段汇总
+		// 1-1.合同相关汇总-收入金额
+		totalIncome := 0.00
+		// 1-2.合同总数
+		totalContractNumber := 0
+		// 1-3.汇款进度
+		totalReturn := 0.00
+		// 1-4支出金额
+		totalPay := 0.00
+		totalPaid := 0.00
+		// 1-5 安全巡检
+		safeTotal := 0
+		safeTotalRectification := 0
+		safeTotalRectificationIn := 0
+		// 1-6 质量巡检
+		qualityTotal := 0
+		qualityTotalRectification := 0
+		qualityTotalRectificationIn := 0
+
+		for _, v := range childs { //查询子节点的子节点,并添加到子节点
+			_, has := HaveChildContract(Data, v)
+			if has {
+				// 递归添加节点
+				MakeFolderContract(Data, v)
+			}
+			// 目录下是否包含标段
+			if v.Isfolder == 0 {
+				node.IsBid = true
+			} else {
+				node.HasFolder = true
+			}
+			// 2.标段汇总
+			// 2-1收入金额 合计
+			price, _ := strconv.ParseFloat(v.ContractsIncome, 64)
+			totalIncome = totalIncome + price
+			// 2-2合同总数 合计
+			totalContractNumber = totalContractNumber + v.Contracts
+			// 2-3 汇款进度
+			price, _ = strconv.ParseFloat(v.ContractsReturned, 64)
+			totalReturn = totalReturn + price
+			//
+			price, _ = strconv.ParseFloat(v.ContractsPay, 64)
+			totalPay = totalPay + price
+			price, _ = strconv.ParseFloat(v.ContractsPaid, 64)
+			totalPaid = totalPaid + price
+			// 安全巡检
+			safeTotal = safeTotal + v.SafeTotal
+			safeTotalRectification = safeTotalRectification + v.SafeRectification
+			safeTotalRectificationIn = safeTotalRectificationIn + v.SafeRectificationIn
+			// 1-6 质量巡检
+			qualityTotal = safeTotal + v.QualityTotal
+			qualityTotalRectification = safeTotalRectification + v.QualityRectification
+			qualityTotalRectificationIn = safeTotalRectificationIn + v.QualityRectificationIn
+		}
+		node.ContractsIncome = fmt.Sprintf("%.2f", totalIncome)
+		node.Contracts = totalContractNumber
+		// 汇款进度
+		quotient := totalReturn / totalIncome
+		if math.IsNaN(quotient) {
+			quotient = 0
+		}
+		node.ContractsIncomeProgress = fmt.Sprintf("%.0f", (quotient)*100) + "%"
+		// 支出相关
+		node.ContractsPay = fmt.Sprintf("%.2f", totalPay)
+		quotient = totalPaid / totalPay
+		if math.IsNaN(quotient) {
+			quotient = 0
+		}
+		node.ContractsPayProgress = fmt.Sprintf("%.0f", (quotient)*100) + "%"
+		// 安全巡检
+		node.SafeTotal = safeTotal
+		node.SafeRectification = safeTotalRectification
+		node.SafeRectificationIn = safeTotalRectificationIn
+		// 质量巡检
+		node.QualityTotal = qualityTotal
+		node.QualityRectification = qualityTotalRectification
+		node.QualityRectificationIn = qualityTotalRectificationIn
+	}
+}
+
+// 是否有子树
+func HaveChildContract(Data []*viewmodels.FolderContract, node *viewmodels.FolderContract) (child []*viewmodels.FolderContract, yes bool) {
+	for _, v := range Data {
+		if v.ParentId == node.Id {
+			child = append(child, v)
+		}
+	}
+	if child != nil {
+		yes = true
+	}
+	return
+}
+
+// 创建合同项目节树
+func MakeSectionContract(Data []*viewmodels.TreeSectionContract, node *viewmodels.TreeSectionContract) { //参数为父节点,添加父节点的子节点指针切片
+
+	childs, _ := haveChildSectionContract(Data, node) //判断节点是否有子节点并返回
+
+	if childs != nil {
+		// 往父节点添加子节点
+		// 孩子们从小到大排序
+		if len(childs) != 0 {
+			sectionSelectionSort(childs)
+			childs[0].ElderBrother = false
+			childs[len(childs)-1].IsEnd = true
+		}
+
+		// 项目节父项使用
+		// 1.合同总金额 回款总金额 已支付总金额
+		contractPriceTotal := 0.00
+		returnPriceTotal := 0.00
+		paidPriceTotal := 0.00
+
+		node.Children = append(node.Children, childs[0:]...) //添加子节点
+		for _, v := range childs {                           //查询子节点的子节点,并添加到子节点
+			_, has := haveChildSectionContract(Data, v)
+			if has {
+				// 递归添加节点
+				MakeSectionContract(Data, v)
+			}
+
+			// 2.计算父项中金额
+			contractPrice, _ := strconv.ParseFloat(v.ContractPrice, 64)
+			contractPriceTotal += contractPrice
+			returnPrice, _ := strconv.ParseFloat(v.ContractReturned, 64)
+			returnPriceTotal += returnPrice
+			paidPrice, _ := strconv.ParseFloat(v.ContractsPaid, 64)
+			paidPriceTotal += paidPrice
+		}
+
+		// 3.赋值到父项中
+		node.ContractPrice = fmt.Sprintf("%.2f", contractPriceTotal)
+		node.ContractReturned = fmt.Sprintf("%.2f", returnPriceTotal)
+		node.ContractsPaid = fmt.Sprintf("%.2f", paidPriceTotal)
+	}
+}
+
+// 合同项目节孩子排序
+func sectionSelectionSort(child []*viewmodels.TreeSectionContract) {
+	for i := 0; i < len(child); i++ {
+		minIndex := i
+		// 查找最小值
+		for j := i; j < len(child); j++ {
+			if child[j].Serial < child[minIndex].Serial {
+				minIndex = j
+			}
+		}
+		swapContract(child, i, minIndex)
+	}
+}
+
+func swapContract(child []*viewmodels.TreeSectionContract, i int, minIndex int) {
+	t := child[i]
+	child[i] = child[minIndex]
+	child[minIndex] = t
+}
+
+// 是否有子树
+func haveChildSectionContract(Data []*viewmodels.TreeSectionContract, node *viewmodels.TreeSectionContract) (child []*viewmodels.TreeSectionContract, yes bool) {
+
+	for _, v := range Data {
+		if v.ParentId == node.Id {
+			child = append(child, v)
+		}
+	}
+
+	if child != nil {
+		yes = true
+	}
+	return
+}
+
+// 当前时间的时间戳
+func NowUnix() int {
+	return int(time.Now().In(conf.SysTimeLocation).Unix())
+}
+
+// 将unix时间戳格式化为yyyymmdd H:i:s格式字符串
+func FormatFromUnixTime(t int64) string {
+	if t > 0 {
+		return time.Unix(t, 0).Format(conf.SysTimeform)
+	} else {
+		return time.Now().Format(conf.SysTimeform)
+	}
+}
+
+// 将unix时间戳格式化为yyyymmdd格式字符串
+func FormatFromUnixTimeShort(t int64) string {
+	if t > 0 {
+		return time.Unix(t, 0).Format(conf.SysTimeformShort)
+	} else {
+		return time.Now().Format(conf.SysTimeformShort)
+	}
+}
+
+// 将字符串转成时间
+func ParseTime(str string) (time.Time, error) {
+	return time.ParseInLocation(conf.SysTimeform, str, conf.SysTimeLocation)
+}
+
+// 得到一个随机数
+func Random(max int) int {
+	r := rand.New(rand.NewSource(time.Now().UnixNano()))
+	if max < 1 {
+		return r.Int()
+	} else {
+		return r.Intn(max)
+	}
+}
+
+// 加密密码
+func CreatePasswordSign(password string, account string) string {
+	str := string(conf.SignSecret) + password + account
+	str1 := fmt.Sprintf("%x", md5.Sum([]byte(str)))
+	sign := fmt.Sprintf("%x", md5.Sum([]byte(str1)))
+	return sign
+}
+
+// 对字符串进行签名
+func CreateSign(str string) string {
+	str = string(conf.SignSecret) + str
+	str1 := fmt.Sprintf("%x", md5.Sum([]byte(str)))
+	sign := fmt.Sprintf("%x", md5.Sum([]byte(str1)))
+	return sign
+}
+
+// 对一个字符串进行加密
+func Encrypt(key, text []byte) (string, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return "", err
+	}
+	b := base64.StdEncoding.EncodeToString(text)
+	ciphertext := make([]byte, aes.BlockSize+len(b))
+	iv := ciphertext[:aes.BlockSize]
+	//if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+	//	return nil, err
+	//}
+	cfb := cipher.NewCFBEncrypter(block, iv)
+	cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
+
+	return base64.RawURLEncoding.EncodeToString(ciphertext), nil
+}
+
+// 对一个字符串进行解密
+func Decrypt(key, text []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	if len(text) < aes.BlockSize {
+		return nil, errors.New("ciphertext too short")
+	}
+	iv := text[:aes.BlockSize]
+	text = text[aes.BlockSize:]
+	cfb := cipher.NewCFBDecrypter(block, iv)
+	cfb.XORKeyStream(text, text)
+	data, err := base64.StdEncoding.DecodeString(string(text))
+	if err != nil {
+		return nil, err
+	}
+	return data, nil
+}
+
+// 加密
+func AesEncrypt(orig string, key string) (string, error) {
+	// 转成字节数组
+	origData := []byte(orig)
+	k := []byte(key)
+
+	// 分组秘钥
+	block, err := aes.NewCipher(k)
+	if err != nil {
+		return "", err
+	}
+	// 获取秘钥块的长度
+	blockSize := block.BlockSize()
+	// 补全码
+	origData = PKCS7Padding(origData, blockSize)
+	// 加密模式
+	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
+	// 创建数组
+	cryted := make([]byte, len(origData))
+	// 加密
+	blockMode.CryptBlocks(cryted, origData)
+	//使用RawURLEncoding 不要使用StdEncoding
+	//不要使用StdEncoding  放在url参数中回导致错误
+	return base64.RawURLEncoding.EncodeToString(cryted), nil
+
+}
+
+// 解密
+func AesDecrypt(cryted string, key string) (string, error) {
+	//使用RawURLEncoding 不要使用StdEncoding
+	//不要使用StdEncoding  放在url参数中回导致错误
+	crytedByte, err := base64.RawURLEncoding.DecodeString(cryted)
+	if err != nil {
+		return "", err
+	}
+	k := []byte(key)
+
+	// 分组秘钥
+	block, err := aes.NewCipher(k)
+	if err != nil {
+		return "", err
+	}
+	// 获取秘钥块的长度
+	blockSize := block.BlockSize()
+	// 加密模式
+	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
+	// 创建数组
+	orig := make([]byte, len(crytedByte))
+	// 解密--传入不正确的字符时会报错-TODO 需捕获
+	blockMode.CryptBlocks(orig, crytedByte)
+	// 去补全码
+	orig = PKCS7UnPadding(orig)
+	return string(orig), nil
+}
+
+//补码
+func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
+	padding := blocksize - len(ciphertext)%blocksize
+	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+	return append(ciphertext, padtext...)
+}
+
+//去码
+func PKCS7UnPadding(origData []byte) []byte {
+	length := len(origData)
+	unpadding := int(origData[length-1])
+	return origData[:(length - unpadding)]
+}
+
+// addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
+// 预定义字符是:
+// 单引号(')
+// 双引号(")
+// 反斜杠(\)
+func Addslashes(str string) string {
+	tmpRune := []rune{}
+	strRune := []rune(str)
+	for _, ch := range strRune {
+		switch ch {
+		case []rune{'\\'}[0], []rune{'"'}[0], []rune{'\''}[0]:
+			tmpRune = append(tmpRune, []rune{'\\'}[0])
+			tmpRune = append(tmpRune, ch)
+		default:
+			tmpRune = append(tmpRune, ch)
+		}
+	}
+	return string(tmpRune)
+}
+
+// stripslashes() 函数删除由 addslashes() 函数添加的反斜杠。
+func Stripslashes(str string) string {
+	dstRune := []rune{}
+	strRune := []rune(str)
+	strLenth := len(strRune)
+	for i := 0; i < strLenth; i++ {
+		if strRune[i] == []rune{'\\'}[0] {
+			i++
+		}
+		dstRune = append(dstRune, strRune[i])
+	}
+	return string(dstRune)
+}
+
+// 将字符串的IP转化为数字
+func Ip4toInt(ip string) int64 {
+	bits := strings.Split(ip, ".")
+	if len(bits) == 4 {
+		b0, _ := strconv.Atoi(bits[0])
+		b1, _ := strconv.Atoi(bits[1])
+		b2, _ := strconv.Atoi(bits[2])
+		b3, _ := strconv.Atoi(bits[3])
+		var sum int64
+		sum += int64(b0) << 24
+		sum += int64(b1) << 16
+		sum += int64(b2) << 8
+		sum += int64(b3)
+		return sum
+	} else {
+		return 0
+	}
+}
+
+// 得到当前时间到下一天零点的延时
+func NextDayDuration() time.Duration {
+	year, month, day := time.Now().Add(time.Hour * 24).Date()
+	next := time.Date(year, month, day, 0, 0, 0, 0, conf.SysTimeLocation)
+	return next.Sub(time.Now())
+}
+
+// 从接口类型安全获取到int64
+func GetInt64(i interface{}, d int64) int64 {
+	if i == nil {
+		return d
+	}
+	switch i.(type) {
+	case string:
+		num, err := strconv.Atoi(i.(string))
+		if err != nil {
+			return d
+		} else {
+			return int64(num)
+		}
+	case []byte:
+		bits := i.([]byte)
+		if len(bits) == 8 {
+			return int64(binary.LittleEndian.Uint64(bits))
+		} else if len(bits) <= 4 {
+			num, err := strconv.Atoi(string(bits))
+			if err != nil {
+				return d
+			} else {
+				return int64(num)
+			}
+		}
+	case uint:
+		return int64(i.(uint))
+	case uint8:
+		return int64(i.(uint8))
+	case uint16:
+		return int64(i.(uint16))
+	case uint32:
+		return int64(i.(uint32))
+	case uint64:
+		return int64(i.(uint64))
+	case int:
+		return int64(i.(int))
+	case int8:
+		return int64(i.(int8))
+	case int16:
+		return int64(i.(int16))
+	case int32:
+		return int64(i.(int32))
+	case int64:
+		return i.(int64)
+	case float32:
+		return int64(i.(float32))
+	case float64:
+		return int64(i.(float64))
+	}
+	return d
+}
+
+// 从接口类型安全获取到字符串类型
+func GetString(str interface{}, d string) string {
+	if str == nil {
+		return d
+	}
+	switch str.(type) {
+	case string:
+		return str.(string)
+	case []byte:
+		return string(str.([]byte))
+	}
+	return fmt.Sprintf("%s", str)
+}
+
+// 从map中得到指定的key
+func GetInt64FromMap(dm map[string]interface{}, key string, dft int64) int64 {
+	data, ok := dm[key]
+	if !ok {
+		return dft
+	}
+	return GetInt64(data, dft)
+}
+
+// 从map中得到指定的key
+func GetInt64FromStringMap(dm map[string]string, key string, dft int64) int64 {
+	data, ok := dm[key]
+	if !ok {
+		return dft
+	}
+	return GetInt64(data, dft)
+}
+
+// 从map中得到指定的key
+func GetStringFromMap(dm map[string]interface{}, key string, dft string) string {
+	data, ok := dm[key]
+	if !ok {
+		return dft
+	}
+	return GetString(data, dft)
+}
+
+// 从map中得到指定的key
+func GetStringFromStringMap(dm map[string]string, key string, dft string) string {
+	data, ok := dm[key]
+	if !ok {
+		return dft
+	}
+	return data
+}
+
+// 首字母大写
+func Ucfirst(str string) string {
+	for i, v := range str {
+		return string(unicode.ToUpper(v)) + str[i+1:]
+	}
+	return ""
+}

+ 50 - 0
conf/db.go

@@ -0,0 +1,50 @@
+/*
+ * @description: mysql配置信息
+ * @Author: CP
+ * @Date: 2020-08-20 22:25:13
+ * @FilePath: \construction_management\conf\db.go
+ */
+package conf
+
+const DriverName = "mysql"
+
+type DbConfig struct {
+	Host      string
+	Port      int
+	User      string
+	Pwd       string
+	Datebase  string
+	IsRunning bool
+}
+
+var DbMasterList = []DbConfig{
+	// 单体数据库222
+	{
+		Host:      "192.168.1.170",
+		Port:      30000,
+		User:      "root",
+		Pwd:       "root",
+		Datebase:  "construction",
+		IsRunning: true,
+	},
+	// 集群数据库
+	{
+		Host:      "192.168.1.26",
+		Port:      8066,
+		User:      "root",
+		Pwd:       "123456",
+		Datebase:  "construction",
+		IsRunning: true,
+	},
+	// QA
+	{
+		Host:      "192.168.1.76",
+		Port:      3306,
+		User:      "zh_dev",
+		Pwd:       "zongheng2019",
+		Datebase:  "construction",
+		IsRunning: true,
+	},
+}
+
+var DbMaster = DbMasterList[2]

+ 48 - 0
conf/project.go

@@ -0,0 +1,48 @@
+/*
+ * @description:
+ * @Author: CP
+ * @Date: 2020-08-21 11:09:48
+ * @FilePath: \construction_management\conf\project.go
+ */
+package conf
+
+import "time"
+
+const SysTimeform = "2006-01-02 15:04:05"
+const SysTimeformShort = "2006-01-02"
+const SysTimeformMonth = "2006-01"
+
+// 请填写您的AccessKeyId。
+const AccessKeyId = "LTAI4GAEAwazcR8JvjZxMiJL"
+
+// 请填写您的AccessKeySecret。
+const AccessKeySecret = "805hbdLwM6cRcBBLSAE5o8mdDAi2NY"
+
+// host的格式为 bucketname.endpoint ,请替换为您的真实信息。
+const OssHost string = "http://measuresaas.oss-cn-shenzhen.aliyuncs.com"
+
+// callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
+const CallbackUrl string = "http://88.88.88.88:8888"
+
+// 用户上传文件时指定的前缀。 --user-dir-prefix/
+const Upload_dir string = "xinxihua/"
+const Expire_time int64 = 60
+
+// 中国时区
+var SysTimeLocation, _ = time.LoadLocation("Asia/Chongqing")
+
+// ObjSalesign 签名密钥
+// var SignSecret = []byte("cpcm005687gokaif")
+var SignSecret = "cpcm005687gokaif"
+
+// cookie中的加密验证密钥
+var CookieSecret = "cm_login_account"
+
+// nodejs rpc 服务端
+const NodeRpcHost = "192.168.1.47:50051"
+
+// 是否需要启动全局计划任务服务
+var RunningCrontabService = false
+
+// 分页-页数
+var PageSize = 10

+ 37 - 0
conf/redis.go

@@ -0,0 +1,37 @@
+/*
+ * @description:
+ * @Author: CP
+ * @Date: 2021-01-27 10:57:57
+ * @FilePath: \construction_management\conf\redis.go
+ */
+package conf
+
+type RdsConfig struct {
+	Host      string
+	Port      int
+	User      string
+	Pwd       string
+	IsRunning bool // 是否正常运行
+}
+
+// 系统中用到的所有redis缓存资源
+var RdsCacheList = []RdsConfig{
+	// 本机
+	{
+		Host:      "192.168.1.26",
+		Port:      6379,
+		User:      "",
+		Pwd:       "",
+		IsRunning: true,
+	},
+	// QA
+	{
+		Host:      "192.168.1.76",
+		Port:      6379,
+		User:      "",
+		Pwd:       "",
+		IsRunning: true,
+	},
+}
+
+var RdsCache RdsConfig = RdsCacheList[1]

+ 69 - 0
dao/annex_dao.go

@@ -0,0 +1,69 @@
+/*
+ * @description: 安全巡检数据库操作相关
+ * @Author: LanJianRong
+ * @Date: 2020-11-20
+ * @FilePath: \construction_management\dao\safe_dao.go
+ */
+
+package dao
+
+import (
+	"fmt"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+// 数据库操作引擎
+type AnnexDao struct {
+	engine *xorm.Engine
+}
+
+// 获得一个DAO对象
+func NewAnnexDao(engine *xorm.Engine) *AnnexDao {
+	return &AnnexDao{
+		engine: engine,
+	}
+}
+
+// 获取附件列表
+func (d *AnnexDao) GetList(dataType int, dataId int, pageNo int, pageSize int) ([]viewmodels.AnnexListView, int64) {
+	dataList := make([]viewmodels.AnnexListView, 0)
+	start := (pageNo - 1) * pageSize
+	total, err := d.engine.Table("`cm_annex` as f").
+		Select("f.`id`, f.`account_id`, f.`create_time`, f.`name` as file_name, f.`oss_url` as file_path, a.`name` as account_name").
+		Join("LEFT", "`cm_project_account` as a", "a.id = f.account_id").
+		Where("f.data_id = ? and f.data_type = ?", dataId, dataType).
+		Limit(pageSize, start).
+		FindAndCount(&dataList)
+	if err != nil {
+		return dataList, 0
+	}
+	return dataList, total
+}
+
+// 获取总数
+func (d *AnnexDao) GetCount(dataType int, dataId int) (int64, error) {
+	file := models.CmAnnex{DataType: dataType, DataId: dataId}
+	total, err := d.engine.Count(&file)
+	fmt.Println(err)
+	if err != nil {
+		return 0, err
+	}
+	return total, nil
+}
+
+// 批量插入数据
+func (d *AnnexDao) InsertByList(data []models.CmAnnex) error {
+	_, err := d.engine.Insert(&data)
+	// fmt.Println("__________________________________", data)
+	return err
+}
+
+// 删除数据(记录id)
+func (d *AnnexDao) DeleteById(id int) error {
+	file := models.CmAnnex{Id: id}
+	_, err := d.engine.Delete(&file)
+	return err
+}

+ 989 - 0
dao/approver_dao.go

@@ -0,0 +1,989 @@
+/*
+ * @description: 审批流程数据库操作相关
+ * @Author: LanJianRong
+ * @Date: 2021-01-06
+ * @FilePath: \construction_management\dao\approver_dao.go
+ */
+
+package dao
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+	"time"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+// 数据库操作引擎
+type ApproverDao struct {
+	engine *xorm.Engine
+}
+
+// 获得一个DAO对象
+func NewApproverDao(engine *xorm.Engine) *ApproverDao {
+	return &ApproverDao{
+		engine: engine,
+	}
+}
+
+// 批量插入数据
+func (d *ApproverDao) InsertData(cur_uid int, bid int, pid int, dataType int, dataId int, auditors []int, reAuditors []int) error {
+	data := make([]models.CmApprover, 0)
+	msg := make([]models.CmProjectMessage, 0)
+	var content string
+	var title string
+	if dataType == 1 {
+		safe := &models.CmSafe{Id: dataId}
+		_, err := d.engine.Get(safe)
+		if err != nil {
+			return err
+		}
+		account := &models.CmProjectAccount{Id: safe.Uid}
+		_, err = d.engine.Get(account)
+		title = fmt.Sprintf("%s - %s", account.Name, account.Position)
+		content = fmt.Sprintf("%s|%s|已上报,审批中", safe.Code, safe.InspectionDetail)
+	} else {
+		quality := &models.CmQuality{Id: dataId}
+		_, err := d.engine.Get(quality)
+		if err != nil {
+			return err
+		}
+		account := &models.CmProjectAccount{Id: quality.Uid}
+		_, err = d.engine.Get(account)
+		if err != nil {
+			return err
+		}
+		title = fmt.Sprintf("%s - %s", account.Name, account.Position)
+		content = fmt.Sprintf("%s|%s|已上报,审批中", quality.Code, quality.InspectionDetail)
+	}
+	_, err := d.engine.Exec("delete from project_message where data_type = ? and data_id = ?", dataType, dataId)
+	for i, item := range auditors {
+		approverVM := models.CmApprover{}
+		approverVM.AuditId = item
+		approverVM.AuditOrder = i + 1
+		approverVM.Progress = 0
+		approverVM.BidsectionId = bid
+		approverVM.ProjectId = pid
+		approverVM.DataType = dataType
+		approverVM.DataId = dataId
+		approverVM.Status = 0
+		if i == 0 {
+			approverVM.Status = 1
+		}
+		data = append(data, approverVM)
+
+		// 消息推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = item
+		msgVM.BidsectionId = bid
+		msgVM.ProjectId = pid
+		msgVM.DataId = dataId
+		msgVM.DataType = 1
+		msgVM.Content = content
+		msgVM.Title = title
+		msgVM.CreateTime = time.Now()
+		msg = append(msg, msgVM)
+	}
+	checkVM := models.CmApprover{}
+	checkVM.AuditOrder = len(auditors) + 1
+	checkVM.Progress = 1
+	checkVM.BidsectionId = bid
+	checkVM.ProjectId = pid
+	checkVM.DataType = dataType
+	checkVM.DataId = dataId
+	data = append(data, checkVM)
+	for i, item := range reAuditors {
+		approverVM := models.CmApprover{}
+		approverVM.AuditId = item
+		approverVM.AuditOrder = i + 2 + len(auditors)
+		approverVM.Progress = 2
+		approverVM.BidsectionId = bid
+		approverVM.ProjectId = pid
+		approverVM.DataType = dataType
+		approverVM.DataId = dataId
+		data = append(data, approverVM)
+
+		// 消息推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = item
+		msgVM.BidsectionId = bid
+		msgVM.ProjectId = pid
+		msgVM.DataId = dataId
+		msgVM.DataType = 1
+		msgVM.Content = content
+		msgVM.Title = title
+		msgVM.CreateTime = time.Now()
+		msg = append(msg, msgVM)
+	}
+	// 再推送自己
+	msgVM := models.CmProjectMessage{}
+	msgVM.AccountId = cur_uid
+	msgVM.BidsectionId = bid
+	msgVM.ProjectId = pid
+	msgVM.DataId = dataId
+	msgVM.DataType = 1
+	msgVM.Content = content
+	msgVM.Title = title
+	msgVM.CreateTime = time.Now()
+	msg = append(msg, msgVM)
+	_, err = d.engine.Insert(data)
+	_, err = d.engine.Insert(msg)
+
+	return err
+}
+
+// 更改状态
+func (d *ApproverDao) ChangeStatus(id int, status int) error {
+	data := &models.CmApprover{Status: status}
+	_, err := d.engine.Where("id = ?", id).Cols("status").Update(data)
+	return err
+}
+
+// 更改审批人
+func (d *ApproverDao) ChangeAuditId(bid int, dataType int, dataId int, auditOrder int, uid int) error {
+	data := &models.CmApprover{AuditId: uid}
+	_, err := d.engine.Where("bidsection_id = ? and data_type = ? and data_id = ? and audit_order = ?", bid, dataType, dataId, auditOrder).Cols("audit_id").Update(data)
+	return err
+}
+
+// 更改下一个审批人的状态
+func (d *ApproverDao) ChangeNextStatus(id int, status int) error {
+	data := &models.CmApprover{Id: id}
+	_, err := d.engine.Get(data)
+	newData := &models.CmApprover{Status: status}
+	_, err = d.engine.Where("bidsection_id = ? and data_type = ? and data_id = ? and audit_order = ?", data.BidsectionId, data.DataType, data.DataId, data.AuditOrder+1).Cols("status").Update(newData)
+	return err
+}
+
+// 根据当前times,获取审批流程(包括原报)
+func (d *ApproverDao) GetAuditorsWithOwner(bid int, dataType int, dataId int, cur_uid int) []viewmodels.Auditors {
+	auditors := make([]viewmodels.Auditors, 0)
+	auditor := viewmodels.Auditors{Progress: "", Id: "", Status: 2}
+
+	_, err := d.engine.Sql("select name, company, position, mobile, id as `audit_id` from `cm_project_account` where id = ?", cur_uid).Get(&auditor)
+
+	if err != nil {
+		fmt.Println(err)
+	}
+	auditors = append(auditors, auditor)
+
+	d.engine.Sql("select pa.`company`, pa.`name`, pa.`account_group`,pa.`mobile`, pa.`position`,ca.`audit_id` as `audit_id`, ca.`id`, ca.`status`, ca.`audit_order`, ca.`progress` from `cm_project_account` as pa, `cm_approver` as ca where ca.`bidsection_id` = ? and ca.`data_type` = ? and ca.`data_id` = ? and ca.audit_id = pa.id order by `audit_order`", bid, dataType, dataId).Find(&auditors)
+	// 原报
+	return auditors
+}
+
+func (d *ApproverDao) FindApproverById(id int) (*models.CmApprover, error) {
+	data := &models.CmApprover{}
+	_, err := d.engine.ID(id).Get(data)
+	return data, err
+}
+
+// 获取最新的审核人
+func (d *ApproverDao) GetLastedAuditor(bid int, dataType int, dataId int) *viewmodels.Approver {
+	data := &models.CmApprover{BidsectionId: bid, DataType: dataType, DataId: dataId, Status: 1}
+	has, _ := d.engine.Get(data)
+	approverVM := &viewmodels.Approver{}
+	if has == true {
+		id, _ := comm.AesEncrypt(strconv.Itoa(data.Id), conf.SignSecret)
+		approverVM.Id = id
+		pid, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret)
+		approverVM.ProjectId = pid
+		bid, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret)
+		approverVM.BidsectionId = bid
+		dataId, _ := comm.AesEncrypt(strconv.Itoa(data.DataId), conf.SignSecret)
+		approverVM.DataId = dataId
+		auditId, _ := comm.AesEncrypt(strconv.Itoa(data.AuditId), conf.SignSecret)
+		approverVM.AuditId = auditId
+		approverVM.AuditOrder = data.AuditOrder
+		approverVM.DataType = data.DataType
+		approverVM.Progress = strconv.Itoa(data.Progress)
+		approverVM.Status = data.Status
+	}
+	return approverVM
+}
+
+// 获取最后一个审批人
+func (d *ApproverDao) GetLastAuditor(bid int, dataType int, dataId int) (*models.CmApprover, error) {
+	data := &models.CmApprover{BidsectionId: bid, DataType: dataType, DataId: dataId}
+	_, err := d.engine.Desc("audit_order").Limit(1).Get(data)
+	return data, err
+}
+
+// 初始化审批流程状态
+func (d *ApproverDao) InitStatus(auditType string, bid int, dataType int, dataId int, auditId int, times int, progress int, opinion string) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("操作失败-db")
+	}
+
+	// 消息推送,先删除旧的推送
+	_, err = session.Exec("delete from cm_project_message where data_type = ? and data_id = ?", auditType, dataId)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	approvers := make([]models.CmApprover, 0)
+	err = session.Where("data_type = ? and data_id = ? and audit_id != 0", dataType, dataId).Find(&approvers)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+
+	data := &models.CmApprover{Status: 0}
+	_, err = session.Where("bidsection_id = ? and data_type = ? and data_id = ?", bid, dataType, dataId).Cols("status").Update(data)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	if auditType == "safe" {
+		safe := &models.CmSafe{}
+		_, err = session.ID(dataId).Get(safe)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		account := &models.CmProjectAccount{Id: safe.Uid}
+		_, err = d.engine.Get(account)
+		title := fmt.Sprintf("%s - %s", account.Name, account.Position)
+
+		msg := make([]models.CmProjectMessage, 0)
+		for _, item := range approvers {
+			msgVM := models.CmProjectMessage{}
+			msgVM.AccountId = item.AuditId
+			msgVM.BidsectionId = item.BidsectionId
+			msgVM.ProjectId = item.ProjectId
+			msgVM.CreateTime = time.Now()
+			msgVM.DataId = item.DataId
+			msgVM.DataType = item.DataType
+			msgVM.Content = fmt.Sprintf("%s|%s|审批退回到上报人", safe.Code, safe.InspectionDetail)
+			msgVM.Title = title
+			msg = append(msg, msgVM)
+		}
+
+		// 添加巡检拥有者的推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = safe.Uid
+		msgVM.BidsectionId = safe.BidsectionId
+		msgVM.ProjectId = safe.ProjectId
+		msgVM.CreateTime = time.Now()
+		msgVM.DataId = safe.Id
+		msgVM.DataType = 1
+		msgVM.Content = fmt.Sprintf("%s|%s|审批退回到上报人", safe.Code, safe.InspectionDetail)
+		msgVM.Title = title
+		msg = append(msg, msgVM)
+
+		// 插入消息
+		_, err = session.Insert(msg)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		_, err = session.Exec("update cm_safe set status = ?, times = ? where id = ?", 0, times+1, dataId)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 增加审批日志
+		safeAudit := &models.CmSafeAudit{BidsectionId: bid, SafeId: dataId, Times: times, AuditId: auditId, Status: 1, Progress: progress, CreateTime: time.Now(), Opinion: opinion}
+		_, err = session.Insert(safeAudit)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 说明本身除于整改人流程,退回原报,要将整改总数-1,未整改总数+1
+		if progress-1 != 0 {
+			_, err = session.Exec("update cm_tree set safe_rectification = safe_rectification + 1, safe_rectification_in = if(safe_rectification_in >= 1, safe_rectification_in - 1, 0) where bidsection_id = ?", bid)
+		}
+	} else {
+		quality := &models.CmQuality{}
+		_, err = session.ID(dataId).Get(quality)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		account := &models.CmProjectAccount{Id: quality.Uid}
+		_, err = d.engine.Get(account)
+		title := fmt.Sprintf("%s - %s", account.Name, account.Position)
+
+		msg := make([]models.CmProjectMessage, 0)
+		for _, item := range approvers {
+			msgVM := models.CmProjectMessage{}
+			msgVM.AccountId = item.AuditId
+			msgVM.BidsectionId = item.BidsectionId
+			msgVM.ProjectId = item.ProjectId
+			msgVM.CreateTime = time.Now()
+			msgVM.DataId = item.DataId
+			msgVM.DataType = item.DataType
+			msgVM.Content = fmt.Sprintf("%s|%s|审批退回到上报人", quality.Code, quality.InspectionDetail)
+			msgVM.Title = title
+			msg = append(msg, msgVM)
+		}
+
+		// 添加巡检拥有者的推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = quality.Uid
+		msgVM.BidsectionId = quality.BidsectionId
+		msgVM.ProjectId = quality.ProjectId
+		msgVM.CreateTime = time.Now()
+		msgVM.DataId = quality.Id
+		msgVM.DataType = 1
+		msgVM.Content = fmt.Sprintf("%s|%s|审批退回到上报人", quality.Code, quality.InspectionDetail)
+		msgVM.Title = title
+		msg = append(msg, msgVM)
+
+		// 插入消息
+		_, err = session.Insert(msg)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		_, err = session.Exec("update cm_quality set status = ?, times = ? where id = ?", 0, times+1, dataId)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 增加审批日志
+		qualityAudit := &models.CmQualityAudit{BidsectionId: bid, QualityId: dataId, Times: times, AuditId: auditId, Status: 1, Progress: progress, CreateTime: time.Now(), Opinion: opinion}
+		_, err = session.Insert(qualityAudit)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		if progress-1 != 0 {
+			_, err = session.Exec("update cm_tree set quality_rectification = quality_rectification + 1, quality_rectification_in = if(quality_rectification_in >= 1, quality_rectification_in - 1, 0) where bidsection_id = ?", bid)
+		}
+	}
+
+	err = session.Commit()
+	return err
+}
+
+// 审批通过
+func (d *ApproverDao) PassHandler(auditType string, id int, uid int, auditId int, opinion string, rectifiedInfo string) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	// add Begin() before any action
+	err := session.Begin()
+	auditor, err := d.FindApproverById(id)
+	if err != nil {
+		return err
+	}
+	if auditor.AuditId != uid {
+		return errors.New("该用户没有审批权限!")
+	}
+
+	var msgContent string
+	switch auditor.Progress {
+	case 0:
+		msgContent = "审批完成,待整改"
+	case 1:
+		msgContent = "整改完成,待复查"
+	case 2:
+		msgContent = "复查完成"
+	}
+	// 消息推送,先删除旧的推送
+	_, err = session.Exec("delete from cm_project_message where data_type = ? and data_id = ?", auditor.DataType, auditor.DataId)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	approvers := make([]models.CmApprover, 0)
+	err = session.Where("data_type = ? and data_id = ? and audit_id != 0", auditor.DataType, auditor.DataId).Find(&approvers)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+
+	// 安全巡检
+	if auditType == "safe" {
+		safe := &models.CmSafe{}
+		_, err = session.ID(auditor.DataId).Get(safe)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		account := &models.CmProjectAccount{Id: safe.Uid}
+		_, err = d.engine.Get(account)
+		title := fmt.Sprintf("%s - %s", account.Name, account.Position)
+
+		msg := make([]models.CmProjectMessage, 0)
+		for _, item := range approvers {
+			msgVM := models.CmProjectMessage{}
+			msgVM.AccountId = item.AuditId
+			msgVM.BidsectionId = item.BidsectionId
+			msgVM.ProjectId = item.ProjectId
+			msgVM.CreateTime = time.Now()
+			msgVM.DataId = item.DataId
+			msgVM.DataType = item.DataType
+			msgVM.Content = fmt.Sprintf("%s|%s|%s", msgContent, safe.Code, safe.InspectionDetail)
+			msgVM.Title = title
+			msg = append(msg, msgVM)
+		}
+
+		// 添加巡检拥有者的推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = safe.Uid
+		msgVM.BidsectionId = safe.BidsectionId
+		msgVM.ProjectId = safe.ProjectId
+		msgVM.CreateTime = time.Now()
+		msgVM.DataId = safe.Id
+		msgVM.DataType = 1
+		msgVM.Content = fmt.Sprintf("%s|%s|%s", msgContent, safe.Code, safe.InspectionDetail)
+		msgVM.Title = title
+		msg = append(msg, msgVM)
+
+		// 插入消息
+		_, err = session.Insert(msg)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 增加审批日志
+		auditReacord := &models.CmSafeAudit{BidsectionId: auditor.BidsectionId, SafeId: auditor.DataId, AuditId: auditor.AuditId, Times: safe.Times, CreateTime: time.Now(), Status: 0, Progress: auditor.Progress + 1, Opinion: opinion, Rectifiedinfo: rectifiedInfo}
+		_, err = session.Insert(auditReacord)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 改变审批流程中当前审批人以及下一个审批人的审批流程状态
+		curData := &models.CmApprover{Status: 2}
+		_, err = session.ID(id).Cols("status").Update(curData)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		nextData := &models.CmApprover{Status: 1}
+		_, err = session.Where("bidsection_id = ? and data_type = ? and data_id = ? and audit_order = ?", auditor.BidsectionId, auditor.DataType, auditor.DataId, auditor.AuditOrder+1).Cols("status").Update(nextData)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		if auditId != 0 {
+			// 审批人选择了整改人
+			// 修改cm_safe表的status状态为待整改
+			_, err = session.Exec("update `cm_safe` set status = ? where id = ?", 2, auditor.DataId)
+			if err != nil {
+				session.Rollback()
+				return err
+			}
+
+			// 将cm_tree的safe_rectification待整改+1
+			_, err := session.Exec("update cm_tree set safe_rectification_in = safe_rectification_in + 1, safe_rectification = if(safe_rectification >= 1, safe_rectification - 1, 0) where bidsection_id = ?", auditor.BidsectionId)
+			if err != nil {
+				session.Rollback()
+				return err
+			}
+			// 改变审批流程中的整改人id
+			_, err = session.Exec("update `cm_approver` set `audit_id` = ? where `bidsection_id` = ? and `data_type` = ? and `data_id` = ? and `audit_order` = ?", auditId, auditor.BidsectionId, auditor.DataType, auditor.DataId, auditor.AuditOrder+1)
+			if err != nil {
+				session.Rollback()
+				return err
+			}
+		} else {
+			if auditor.Progress == 1 {
+				// 整改人审批流程
+				// 修改cm_safe表的status状态为待复查
+				_, err = session.Exec("update `cm_safe` set status = ? where id = ?", 3, auditor.DataId)
+				if err != nil {
+					session.Rollback()
+					return err
+				}
+			} else {
+				// 复查流程
+				// 查找最后一个审批人
+				lastAuditor := &models.CmApprover{BidsectionId: auditor.BidsectionId, DataType: auditor.DataType, DataId: auditor.DataId}
+				_, err = session.Desc("audit_order").Limit(1).Get(lastAuditor)
+				if err != nil {
+					session.Rollback()
+					return err
+				}
+				if lastAuditor.AuditId == auditor.AuditId {
+					// 说明审批流程已经走完
+					_, err = session.Exec("update `cm_safe` set status = ? where id = ?", 4, auditor.DataId)
+					if err != nil {
+						session.Rollback()
+						return err
+					}
+					// 将cm_tree的safe_rectification_finish待整改+1
+					_, err := session.Exec("update cm_tree set safe_rectification_finish = safe_rectification_finish + 1,  safe_rectification_in = if(safe_rectification_in >= 1, safe_rectification_in - 1, 0)where bidsection_id = ?", auditor.BidsectionId)
+					if err != nil {
+						session.Rollback()
+						return err
+					}
+				}
+			}
+		}
+	} else {
+		// 质量巡检
+		quality := &models.CmQuality{}
+		_, err = session.ID(auditor.DataId).Get(quality)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		account := &models.CmProjectAccount{Id: quality.Uid}
+		_, err = d.engine.Get(account)
+		title := fmt.Sprintf("%s - %s", account.Name, account.Position)
+
+		msg := make([]models.CmProjectMessage, 0)
+		for _, item := range approvers {
+			msgVM := models.CmProjectMessage{}
+			msgVM.AccountId = item.AuditId
+			msgVM.BidsectionId = item.BidsectionId
+			msgVM.ProjectId = item.ProjectId
+			msgVM.CreateTime = time.Now()
+			msgVM.DataId = item.DataId
+			msgVM.DataType = item.DataType
+			msgVM.Content = fmt.Sprintf("%s|%s|%s", msgContent, quality.Code, quality.InspectionDetail)
+			msgVM.Title = title
+			msg = append(msg, msgVM)
+		}
+
+		// 添加巡检拥有者的推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = quality.Uid
+		msgVM.BidsectionId = quality.BidsectionId
+		msgVM.ProjectId = quality.ProjectId
+		msgVM.CreateTime = time.Now()
+		msgVM.DataId = quality.Id
+		msgVM.DataType = 1
+		msgVM.Content = fmt.Sprintf("%s|%s|%s", msgContent, quality.Code, quality.InspectionDetail)
+		msgVM.Title = title
+		msg = append(msg, msgVM)
+
+		// 插入消息
+		_, err = session.Insert(msg)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		// 增加审批日志
+		auditReacord := &models.CmQualityAudit{BidsectionId: auditor.BidsectionId, QualityId: auditor.DataId, AuditId: auditor.AuditId, Times: quality.Times, CreateTime: time.Now(), Status: 0, Progress: auditor.Progress + 1, Opinion: opinion, Rectifiedinfo: rectifiedInfo}
+		_, err = session.Insert(auditReacord)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 改变审批流程中当前审批人以及下一个审批人的审批流程状态
+		curData := &models.CmApprover{Status: 2}
+		_, err = session.ID(id).Cols("status").Update(curData)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		nextData := &models.CmApprover{Status: 1}
+		_, err = session.Where("bidsection_id = ? and data_type = ? and data_id = ? and audit_order = ?", auditor.BidsectionId, auditor.DataType, auditor.DataId, auditor.AuditOrder+1).Cols("status").Update(nextData)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		if auditId != 0 {
+			// 审批人选择了整改人
+			// 修改cm_quality表的status状态为待整改
+			_, err = session.Exec("update `cm_quality` set status = ? where id = ?", 2, auditor.DataId)
+			if err != nil {
+				session.Rollback()
+				return err
+			}
+
+			// 将cm_tree的quality_rectification待整改+1
+			_, err := session.Exec("update cm_tree set quality_rectification_in = quality_rectification_in + 1, quality_rectification = if(quality_rectification >= 1, quality_rectification - 1, 0) where bidsection_id = ?", auditor.BidsectionId)
+			if err != nil {
+				session.Rollback()
+				return err
+			}
+			// 改变审批流程中的整改人id
+			_, err = session.Exec("update `cm_approver` set `audit_id` = ? where `bidsection_id` = ? and `data_type` = ? and `data_id` = ? and `audit_order` = ?", auditId, auditor.BidsectionId, auditor.DataType, auditor.DataId, auditor.AuditOrder+1)
+			if err != nil {
+				session.Rollback()
+				return err
+			}
+		} else {
+			if auditor.Progress == 1 {
+				// 整改人审批流程
+				// 修改cm_quality表的status状态为待复查
+				_, err = session.Exec("update `cm_quality` set status = ? where id = ?", 3, auditor.DataId)
+				if err != nil {
+					session.Rollback()
+					return err
+				}
+			} else {
+				// 复查流程
+				// 查找最后一个审批人
+				lastAuditor := &models.CmApprover{BidsectionId: auditor.BidsectionId, DataType: auditor.DataType, DataId: auditor.DataId}
+				_, err = session.Desc("audit_order").Limit(1).Get(lastAuditor)
+				if err != nil {
+					session.Rollback()
+					return err
+				}
+				if lastAuditor.AuditId == auditor.AuditId {
+					// 说明审批流程已经走完
+					_, err = session.Exec("update `cm_quality` set status = ? where id = ?", 4, auditor.DataId)
+					if err != nil {
+						session.Rollback()
+						return err
+					}
+					// 将cm_tree的quality_rectification_finish待整改+1
+					_, err := session.Exec("update cm_tree set quality_rectification_finish = quality_rectification_finish + 1, quality_rectification_in = if(quality_rectification_in >= 1, quality_rectification_in - 1, 0) where bidsection_id = ?", auditor.BidsectionId)
+					if err != nil {
+						session.Rollback()
+						return err
+					}
+				}
+			}
+		}
+	}
+
+	err = session.Commit()
+	return err
+}
+
+// 审批流程-退回
+func (d *ApproverDao) BackHandlerWithId(auditType string, id int, uid int, times int, progress int, opinion string) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+
+	auditor := &models.CmApprover{}
+	_, err = session.ID(id).Get(auditor)
+	data := &models.CmApprover{Status: 0}
+	// 将往后的所有记录的status改为0
+	_, err = session.Where("bidsection_id = ? and data_type = ? and data_id = ? and audit_order > ?", auditor.BidsectionId, auditor.DataType, auditor.DataId, auditor.AuditOrder).Cols("status").Update(data)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	// 获取改账号的信息
+	account := &models.CmProjectAccount{Id: auditor.AuditId}
+	_, err = session.Get(account)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	// 将当前的记录改为1-待审批
+	data.Status = 1
+	_, err = session.ID(id).Cols("status").Update(data)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+
+	// 消息推送,先删除旧的推送
+	_, err = session.Exec("delete from cm_project_message where data_type = ? and data_id = ?", auditor.DataType, auditor.DataId)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	approvers := make([]models.CmApprover, 0)
+	err = session.Where("data_type = ? and data_id = ? and audit_id != 0", auditor.DataType, auditor.DataId).Find(&approvers)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+
+	// 增加审批日志
+	if auditType == "safe" {
+		safe := &models.CmSafe{}
+		_, err = session.ID(auditor.DataId).Get(safe)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		account := &models.CmProjectAccount{Id: safe.Uid}
+		_, err = d.engine.Get(account)
+		title := fmt.Sprintf("%s - %s", account.Name, account.Position)
+
+		msg := make([]models.CmProjectMessage, 0)
+
+		for _, item := range approvers {
+			msgVM := models.CmProjectMessage{}
+			msgVM.AccountId = item.AuditId
+			msgVM.BidsectionId = item.BidsectionId
+			msgVM.ProjectId = item.ProjectId
+			msgVM.CreateTime = time.Now()
+			msgVM.DataId = item.DataId
+			msgVM.DataType = item.DataType
+			msgVM.Content = fmt.Sprintf("%s|%s|审批退回,退回至%s", safe.Code, safe.InspectionDetail, account.Name)
+			msgVM.Title = title
+			msg = append(msg, msgVM)
+		}
+
+		// 添加巡检拥有者的推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = safe.Uid
+		msgVM.BidsectionId = safe.BidsectionId
+		msgVM.ProjectId = safe.ProjectId
+		msgVM.CreateTime = time.Now()
+		msgVM.DataId = safe.Id
+		msgVM.DataType = 1
+		msgVM.Content = fmt.Sprintf("%s|%s|审批退回,退回至%s", safe.Code, safe.InspectionDetail, account.Name)
+		msg = append(msg, msgVM)
+
+		// 插入消息
+		_, err = session.Insert(msg)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		safeAudit := &models.CmSafeAudit{BidsectionId: auditor.BidsectionId, SafeId: auditor.DataId, Times: times, AuditId: uid, Status: 1, Progress: progress, CreateTime: time.Now(), Opinion: opinion}
+		_, err = session.Insert(safeAudit)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	} else {
+		quality := &models.CmQuality{}
+		_, err = session.ID(auditor.DataId).Get(quality)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		account := &models.CmProjectAccount{Id: quality.Uid}
+		_, err = d.engine.Get(account)
+		title := fmt.Sprintf("%s - %s", account.Name, account.Position)
+
+		msg := make([]models.CmProjectMessage, 0)
+		for _, item := range approvers {
+			msgVM := models.CmProjectMessage{}
+			msgVM.AccountId = item.AuditId
+			msgVM.BidsectionId = item.BidsectionId
+			msgVM.ProjectId = item.ProjectId
+			msgVM.CreateTime = time.Now()
+			msgVM.DataId = item.DataId
+			msgVM.DataType = item.DataType
+			msgVM.Content = fmt.Sprintf("%s|%s|审批退回,退回至%s", quality.Code, quality.InspectionDetail, account.Name)
+			msgVM.Title = title
+			msg = append(msg, msgVM)
+		}
+
+		// 添加巡检拥有者的推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = quality.Uid
+		msgVM.BidsectionId = quality.BidsectionId
+		msgVM.ProjectId = quality.ProjectId
+		msgVM.CreateTime = time.Now()
+		msgVM.DataId = quality.Id
+		msgVM.DataType = 2
+		msgVM.Content = fmt.Sprintf("%s|%s|审批退回,退回至%s", quality.Code, quality.InspectionDetail, account.Name)
+		msgVM.Title = title
+		msg = append(msg, msgVM)
+
+		// 插入消息
+		_, err = session.Insert(msg)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		qualityAudit := &models.CmQualityAudit{BidsectionId: auditor.BidsectionId, QualityId: auditor.DataId, Times: times, AuditId: uid, Status: 1, Progress: progress, CreateTime: time.Now(), Opinion: opinion}
+		_, err = session.Insert(qualityAudit)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	}
+	curAuditor := &models.CmApprover{}
+	_, err = session.ID(uid).Get(curAuditor)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	// 当前审批人是整改或者复查流程的并且退回的是审批流程的
+	if curAuditor.Progress >= 1 && auditor.Progress == 0 {
+		var sql string
+		if auditType == "safe" {
+			sql = "update cm_tree set safe_rectification = safe_rectification_in + 1 and safe_rectification_in = if(safe_rectification_in >= 1, safe_rectification_in - 1, 0) where bidsection_id = ?"
+		} else {
+			sql = "update cm_tree set quality_rectification = quality_rectification_in + 1 and quality_rectification_in = if(quality_rectification_in >= 1, quality_rectification_in - 1, 0) where bidsection_id = ?"
+		}
+		_, err = session.Exec(sql, auditor.BidsectionId)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	}
+
+	err = session.Commit()
+	return err
+}
+
+func (d *ApproverDao) CloseHandler(auditType string, id int, opinion string, curUid int, saveId int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	// add Begin() before any action
+	err := session.Begin()
+	auditor, err := d.FindApproverById(id)
+	if auditor.AuditId != curUid {
+		return errors.New("该用户没有审批权限!")
+	}
+
+	// 消息推送,先删除旧的推送
+	_, err = session.Exec("delete from cm_project_message where data_type = ? and data_id = ?", auditor.DataType, auditor.DataId)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	approvers := make([]models.CmApprover, 0)
+	err = session.Where("data_type = ? and data_id = ? and audit_id != 0", auditor.DataType, auditor.DataId).Find(&approvers)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+
+	if auditType == "safe" {
+		safe := &models.CmSafe{}
+		_, err = session.ID(saveId).Get(safe)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		account := &models.CmProjectAccount{Id: safe.Uid}
+		_, err = d.engine.Get(account)
+		title := fmt.Sprintf("%s - %s", account.Name, account.Position)
+
+		msg := make([]models.CmProjectMessage, 0)
+		for _, item := range approvers {
+			msgVM := models.CmProjectMessage{}
+			msgVM.AccountId = item.AuditId
+			msgVM.BidsectionId = item.BidsectionId
+			msgVM.ProjectId = item.ProjectId
+			msgVM.CreateTime = time.Now()
+			msgVM.DataId = item.DataId
+			msgVM.DataType = item.DataType
+			msgVM.Content = fmt.Sprintf("%s|%s|已关闭,停止审批流程", safe.Code, safe.InspectionDetail)
+			msgVM.Title = title
+			msg = append(msg, msgVM)
+		}
+
+		// 添加巡检拥有者的推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = safe.Uid
+		msgVM.BidsectionId = safe.BidsectionId
+		msgVM.ProjectId = safe.ProjectId
+		msgVM.CreateTime = time.Now()
+		msgVM.DataId = safe.Id
+		msgVM.DataType = 1
+		msgVM.Content = fmt.Sprintf("%s|%s|已关闭,停止审批流程", safe.Code, safe.InspectionDetail)
+		msgVM.Title = title
+		msg = append(msg, msgVM)
+
+		// 插入消息
+		_, err = session.Insert(msg)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		// 增加审批日志
+		safeAudit := &models.CmSafeAudit{BidsectionId: auditor.BidsectionId, SafeId: auditor.DataId, Times: safe.Times, AuditId: auditor.AuditId, Status: 2, Progress: auditor.Progress, CreateTime: time.Now(), Opinion: opinion}
+		_, err = session.Insert(safeAudit)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 更改cm_safe的记录
+		_, err = session.Exec("update `cm_safe` set status = ? where id = ? ", 5, saveId)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	} else {
+		quality := &models.CmQuality{}
+		_, err = session.ID(saveId).Get(quality)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+
+		account := &models.CmProjectAccount{Id: quality.Uid}
+		_, err = d.engine.Get(account)
+		title := fmt.Sprintf("%s - %s", account.Name, account.Position)
+
+		msg := make([]models.CmProjectMessage, 0)
+		for _, item := range approvers {
+			msgVM := models.CmProjectMessage{}
+			msgVM.AccountId = item.AuditId
+			msgVM.BidsectionId = item.BidsectionId
+			msgVM.ProjectId = item.ProjectId
+			msgVM.CreateTime = time.Now()
+			msgVM.DataId = item.DataId
+			msgVM.DataType = item.DataType
+			msgVM.Content = fmt.Sprintf("%s|%s|已关闭,停止审批流程", quality.Code, quality.InspectionDetail)
+			msgVM.Title = title
+			msg = append(msg, msgVM)
+		}
+
+		// 添加巡检拥有者的推送
+		msgVM := models.CmProjectMessage{}
+		msgVM.AccountId = quality.Uid
+		msgVM.BidsectionId = quality.BidsectionId
+		msgVM.ProjectId = quality.ProjectId
+		msgVM.CreateTime = time.Now()
+		msgVM.DataId = quality.Id
+		msgVM.DataType = 2
+		msgVM.Content = fmt.Sprintf("%s|%s|已关闭,停止审批流程", quality.Code, quality.InspectionDetail)
+		msgVM.Title = title
+		msg = append(msg, msgVM)
+
+		// 插入消息
+		_, err = session.Insert(msg)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 增加审批日志
+		qualityAudit := &models.CmQualityAudit{BidsectionId: auditor.BidsectionId, QualityId: auditor.DataId, Times: quality.Times, AuditId: auditor.AuditId, Status: 2, Progress: auditor.Progress, CreateTime: time.Now(), Opinion: opinion}
+		_, err = session.Insert(qualityAudit)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		// 更改cm_quality的记录
+		_, err = session.Exec("update `cm_quality` set status = ? where id = ? ", 5, saveId)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	}
+	// 更改cm_approver的记录
+	_, err = session.Exec("update `cm_approver` set status = ? where id = ? ", 3, id)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+
+	err = session.Commit()
+	return err
+}
+
+// 删除旧的审批流程
+func (d *ApproverDao) DeleteOldAuditors(bid int, dataType int, dataId int) error {
+	data := &models.CmApprover{BidsectionId: bid, DataType: dataType, DataId: dataId}
+	_, err := d.engine.Delete(data)
+	return err
+}
+
+func (d *ApproverDao) GetStatusByProjectAndAccount(projectId int, projectAccountId int, status int) []models.CmApprover {
+	datalist := make([]models.CmApprover, 0)
+	_ = d.engine.
+		Where("project_id = ? and audit_id= ? and status=? ", projectId, projectAccountId, status).
+		Desc("id").
+		Find(&datalist)
+	return datalist
+}

+ 251 - 0
dao/bid_account_dao.go

@@ -0,0 +1,251 @@
+/*
+ * @description: 标段账号的-数据库操作
+ * @Author: CP
+ * @Date: 2020-10-21 11:54:10
+ * @FilePath: \construction_management\dao\bid_account_dao.go
+ */
+package dao
+
+import (
+	"encoding/json"
+	"errors"
+	"log"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/lib"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type BidAccountDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewBidAccountDao(engine *xorm.Engine) *BidAccountDao {
+	return &BidAccountDao{
+		engine: engine,
+	}
+}
+
+//获得标段下的账号数据
+func (d *BidAccountDao) GetBidAccount(bidsectionId int, projectId int) []models.CmBidAccount {
+	datalist := make([]models.CmBidAccount, 0)
+
+	err := d.engine.
+		Where("bidsection_id = ? and project_id=?", bidsectionId, projectId).
+		Asc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+//获得标段下的账号数据
+func (d *BidAccountDao) GetAccountId(projectId int, bidsectionId int, accountId int) *models.CmBidAccount {
+	data := &models.CmBidAccount{}
+	ok, err := d.engine.
+		Where("project_id=? and bidsection_id = ? and account_id= ? ", projectId, bidsectionId, accountId).
+		Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+// 创建标段成员关系
+func (d *BidAccountDao) Create(bidsectionId int, accountData *models.CmProjectAccount, treeId int, projectId int) error {
+
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("新增标段成员出错-dbsession")
+	}
+
+	// -更新树成员量
+	// 1.获得标段成员量
+	bidAccountData := d.GetBidAccount(bidsectionId, projectId)
+	accounts := len(bidAccountData) + 1
+	_, err = session.Exec("UPDATE cm_tree SET `accounts` = ? where id = ?", accounts, treeId)
+	if err != nil {
+		session.Rollback()
+		log.Println(err)
+		return errors.New("更新标段成员量出错")
+	}
+
+	// 2.初始化账号权限
+	permissionAccount := &models.CmPermissionAccount{}
+	_, err = d.engine.
+		Where("project_id=? and bidsection_id = ? and account_id= ? ", projectId, bidsectionId, accountData.Id).
+		Get(permissionAccount)
+	// 2-1
+	permiss := "{\"access\":1,\"add\":0,\"delete\":0}"
+	if permissionAccount.Id == 0 {
+		permissionAccount.ProjectId = projectId
+		permissionAccount.BidsectionId = bidsectionId
+		permissionAccount.AccountId = accountData.Id
+		permissionAccount.ContractPermission = permiss
+		permissionAccount.QualityPermission = permiss
+		permissionAccount.SafePermission = permiss
+		_, err = session.Insert(permissionAccount)
+		if err != nil {
+			session.Rollback()
+			return errors.New("初始化账号权限出错")
+		}
+	} else {
+		_, err = session.Exec("UPDATE cm_permission_account SET `contract_permission` = ? ,`quality_permission` = ? ,`safe_permission` = ?  where id = ?",
+			permiss, permiss, permiss, permissionAccount.Id)
+		if err != nil {
+			session.Rollback()
+			return errors.New("更新账号下标段出错")
+		}
+	}
+
+	// -更新账号表的标段ID
+	// 1.获得账号中已绑定的标段
+	bidsectionIdsString := accountData.BidsectionIds
+	bidsectionIds := make([]lib.BidsectionIds, 0)
+	bidsectionIdsByte := []byte("")
+	// 2.未有标段
+	if bidsectionIdsString == "" {
+		BidsectionIdsItem := lib.BidsectionIds{}
+		BidsectionIdsItem.Id = bidsectionId
+		bidsectionIds = append(bidsectionIds, BidsectionIdsItem)
+		bidsectionIdsByte, err = json.Marshal(bidsectionIds)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	} else {
+		// 2.获得已有的标段ID
+		err := json.Unmarshal([]byte(bidsectionIdsString), &bidsectionIds)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+		bidId := lib.BidsectionIds{}
+		bidId.Id = bidsectionId
+		// 加入ID
+		bidsectionIds = append(bidsectionIds, bidId)
+		// 转换JSON字符byte
+		bidsectionIdsByte, err = json.Marshal(bidsectionIds)
+		if err != nil {
+			return err
+		}
+	}
+	bidsectionIdsString = string(bidsectionIdsByte[:])
+	// 3.更新账号标段ID组
+	_, err = session.Exec("UPDATE cm_project_account SET `bidsection_ids` = ? where id = ?", bidsectionIdsString, accountData.Id)
+	if err != nil {
+		session.Rollback()
+		return errors.New("更新账号下标段出错")
+	}
+
+	// -写入标段用户关系
+	bidAccount := models.CmBidAccount{}
+	bidAccount.AccountId = accountData.Id
+	bidAccount.BidsectionId = bidsectionId
+	bidAccount.ProjectId = projectId
+	_, err = session.Insert(bidAccount)
+	if err != nil {
+		session.Rollback()
+		return errors.New("账号关联标段出错")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("新增标段成员出错-dbsession")
+	}
+	return nil
+}
+
+// 移除标段中的成员
+func (d *BidAccountDao) Delete(bidsectionId int, accountData *models.CmProjectAccount, treeId int, projectId int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("移除标段成员出错-dbsession")
+	}
+
+	// 1.移除标段账号关系中的账号
+	_, err = session.Exec("DELETE FROM `cm_bid_account` WHERE account_id = ? and bidsection_id = ? and project_id= ? limit 1",
+		accountData.Id, bidsectionId, projectId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("移除标段成员出错")
+	}
+	// 1-1 移除账号权限
+	_, err = session.Exec("DELETE FROM `cm_permission_account` WHERE project_id= ? and  bidsection_id = ? and  account_id = ? limit 1",
+		projectId, bidsectionId, accountData.Id)
+	if err != nil {
+		session.Rollback()
+		return errors.New("移除成员权限出错")
+	}
+
+	// -更新树成员量
+	// 2.获得标段成员量
+	bidAccountData := d.GetBidAccount(bidsectionId, projectId)
+	accounts := len(bidAccountData)
+	_, err = session.Exec("UPDATE cm_tree SET `accounts` = ? where id = ?", accounts, treeId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("更新标段成员量出错")
+	}
+
+	// 3.移除账号表中的标段ID
+	bidsectionIdsString := accountData.BidsectionIds
+	bidsectionIds := make([]lib.BidsectionIds, 0)
+	bidsectionIdsByte := []byte("")
+	// 2.未有标段
+	if bidsectionIdsString == "" {
+		return errors.New("移除标段成员出错")
+	}
+	// 2.获得已有的标段ID
+	err = json.Unmarshal([]byte(bidsectionIdsString), &bidsectionIds)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	// 获得需要删除标段ID的下标
+	bidsectionIdsIndex := -1
+	for index, data := range bidsectionIds {
+		if data.Id == bidsectionId {
+			bidsectionIdsIndex = index
+			break
+		}
+	}
+	if bidsectionIdsIndex == -1 {
+		session.Rollback()
+		return errors.New("移除标段成员出错")
+	}
+	// 删除标段ID
+	bidsectionIds = append(bidsectionIds[:bidsectionIdsIndex], bidsectionIds[bidsectionIdsIndex+1:]...)
+
+	// 转换JSON字符byte
+	bidsectionIdsByte, err = json.Marshal(bidsectionIds)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	bidsectionIdsString = string(bidsectionIdsByte[:])
+	// 3.更新账号标段ID组
+	_, err = session.Exec("UPDATE cm_project_account SET `bidsection_ids` = ? where id = ?", bidsectionIdsString, accountData.Id)
+	if err != nil {
+		session.Rollback()
+		return errors.New("移除账号下标段出错")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("移除标段成员出错-dbsession")
+	}
+	return nil
+}

+ 88 - 0
dao/bidsection_dao.go

@@ -0,0 +1,88 @@
+/*
+ * @description: 标段-数据库操作
+ * @Author: CP
+ * @Date: 2020-09-28 10:35:56
+ * @FilePath: \construction_management\dao\bidsection_dao.go
+ */
+package dao
+
+import (
+	"errors"
+	"time"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type BidsectionDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewBidsectionDao(engine *xorm.Engine) *BidsectionDao {
+	return &BidsectionDao{
+		engine: engine,
+	}
+}
+
+//id获得数据
+func (d *BidsectionDao) Get(id int, projectId int) *models.CmBidsection {
+	data := &models.CmBidsection{Id: id, ProjectId: projectId}
+	//Get取到值后,会自动赋值到data中
+	ok, err := d.engine.Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+//更新
+func (d *BidsectionDao) Update(data *models.CmBidsection, columns []string) error {
+	_, err := d.engine.Id(data.Id).MustCols(columns...).Update(data)
+	return err
+}
+
+//创建
+func (d *BidsectionDao) Create(data *models.CmTree) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("创建标段出错-db")
+	}
+
+	// 创建标段
+	bidsection := &models.CmBidsection{}
+	bidsection.ProjectId = data.ProjectId
+	bidsection.Name = data.Name
+	bidsection.CreateTime = time.Now()
+	bidsection.DealTp = "0"
+	bidsection.TotalPrice = "0"
+	_, err = session.Insert(bidsection)
+	if err != nil {
+		session.Rollback()
+		return errors.New("标段创建不正确")
+	}
+	// 创建标段在树结构中的联系
+	data.BidsectionId = bidsection.Id
+	data.ContractsIncome = "0"
+	data.ContractsPaid = "0"
+	data.ContractsPay = "0"
+	data.ContractsReturned = "0"
+	_, err = session.Insert(data)
+	if err != nil {
+		session.Rollback()
+		return errors.New("创建标段联系出错-db")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("创建标段出错-db")
+	}
+
+	return nil
+}

+ 396 - 0
dao/contract_dao.go

@@ -0,0 +1,396 @@
+/*
+ * @description: 合同相关数据库操作
+ * @Author: CP
+ * @Date: 2020-11-17 10:41:05
+ * @FilePath: \construction_management\dao\contract_dao.go
+ */
+package dao
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"strconv"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type ContractDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewContractDao(engine *xorm.Engine) *ContractDao {
+	return &ContractDao{
+		engine: engine,
+	}
+}
+
+// 获得本项目的合同项目节
+func (d *ContractDao) Get(id int) *models.CmContracts {
+	data := &models.CmContracts{}
+	_, err := d.engine.
+		Where("id=? ", id).
+		Get(data)
+	if err != nil {
+		data.Id = 0
+		return data
+	}
+	return data
+}
+
+// 获得本项目的合同项目节
+func (d *ContractDao) GetByCode(projectId int, bidsectionId int, code string, contractsType int) []models.CmContracts {
+
+	datalist := make([]models.CmContracts, 0)
+	_ = d.engine.
+		Where("project_id=? and bidsection_id=? and code=? and contracts_type=? ",
+			projectId, bidsectionId, code, contractsType).
+		Find(&datalist)
+	return datalist
+}
+
+// 获得本项目的合同项目节
+func (d *ContractDao) GetType(bidsectionId int, projectId int, contractsType int) []models.CmContracts {
+
+	datalist := make([]models.CmContracts, 0)
+	_ = d.engine.
+		Where("project_id=? and bidsection_id=? and contracts_type=? ", projectId, bidsectionId, contractsType).
+		Find(&datalist)
+	return datalist
+}
+
+// 获得本项目的合同项目节
+func (d *ContractDao) GetTypeYear(bidsectionId int, projectId int, contractsType int, year int) []models.CmContracts {
+
+	startYear := fmt.Sprintf("%d-01-01:00.00.00", year)
+	endYear := fmt.Sprintf("%d-12-31:23.59.59", year)
+
+	datalist := make([]models.CmContracts, 0)
+	_ = d.engine.
+		Where("project_id=? and bidsection_id=? and contracts_type=? and create_time>='"+startYear+"' and create_time<='"+endYear+"'",
+			projectId, bidsectionId, contractsType).
+		Find(&datalist)
+	return datalist
+}
+
+// 合同
+func (d *ContractDao) GetInProjectAndBidsection(id int, projectId int, bidsectionId int) *models.CmContracts {
+	data := &models.CmContracts{}
+	_, err := d.engine.
+		Where("id=? and project_id=? and bidsection_id=? ", id, projectId, bidsectionId).
+		Get(data)
+	if err != nil {
+		data.Id = 0
+		return data
+	}
+	return data
+}
+
+// 新增合同
+// contractData *models.CmContracts
+// contractTotal 合同总数
+// priceTotal 收入总金额
+func (d *ContractDao) Add(contractData *models.CmContracts) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("新增合同出错-db")
+	}
+
+	// 1.写入合同表
+	_, err = session.Insert(contractData)
+	if err != nil {
+		log.Println(err)
+		session.Rollback()
+		return errors.New("新增合同出错")
+	}
+	// 2.更新项目节表
+	_, err = session.Exec("UPDATE  cm_tree_contracts SET `contract_id` = ?,`contract_name` = ?,`contract_code` = ?,`contract_price` = ? "+
+		"where tree_id = ? and project_id = ? and bidsection_id = ? ",
+		contractData.Id, contractData.Name, contractData.Code, contractData.Price,
+		contractData.TreeId, contractData.ProjectId, contractData.BidsectionId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("新增合同出错-项目节更新失败")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("新增合同出错-db")
+	}
+	return nil
+}
+
+// 更新合同
+func (d *ContractDao) Update(contractsCm *models.CmContracts, columns []string, projectId int, bidsectionId int, treeId int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("session出错-db")
+	}
+
+	// 1.更新合同表
+	// successNum 是否有值更新的数量 为0,表示没有更新
+	// successNum, err := session.Id(contractsCm.Id).MustCols(columns...).Update(contractsCm)
+	_, err = session.Id(contractsCm.Id).MustCols(columns...).Update(contractsCm)
+	if err != nil {
+		session.Rollback()
+		return errors.New("更新失败")
+	}
+
+	// 3.更新合同状态,合同金额和回款金额比对
+	// 3-1获得回款总金额
+	datalist := make([]models.CmContractsReturn, 0)
+	err = d.engine.Where(" project_id =? and bidsection_id = ? and contracts_id =? ", projectId, bidsectionId, contractsCm.Id).Find(&datalist)
+	if err != nil {
+		session.Rollback()
+		return errors.New("编辑合同出错-项目节更新失败")
+	}
+	contractsPrice := 0.00
+	for _, item := range datalist {
+		price, _ := strconv.ParseFloat(item.Price, 64)
+		if item.ContractsId == contractsCm.Id {
+			contractsPrice = contractsPrice + price
+		}
+	}
+	contractsPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", contractsPrice), 64)
+	// 合同状态判定
+	contractsDetailPrice, _ := strconv.ParseFloat(contractsCm.Price, 64)
+	// 总回款大于等于合同金额 待关闭
+	contractStatus := 0
+	if contractsPrice >= contractsDetailPrice {
+		contractStatus = 1
+	}
+	// 更新合同表状态
+	_, err = session.Exec("UPDATE  cm_contracts SET  status = ? where id = ? ", contractStatus, contractsCm.Id)
+	if err != nil {
+		session.Rollback()
+		return errors.New("合同状态更新失败")
+	}
+
+	// 2.更新项目节表
+	_, err = session.Exec("UPDATE  cm_tree_contracts SET `contract_name` = ?,`contract_price` = ? , contract_status = ? "+
+		"where tree_id = ? and project_id = ? and bidsection_id = ? ",
+		contractsCm.Name, contractsCm.Price, contractStatus,
+		treeId, projectId, bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("编辑合同出错-项目节更新失败")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("session出错-db")
+	}
+	return nil
+}
+
+// 删除合同
+func (d *ContractDao) Delete(projectId int, bidsectionId int, treeId int, id int) error {
+
+	contractsCm := models.CmContracts{}
+
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("session出错-db")
+	}
+	// 1.删除合同
+	successNum, err := session.Where("id = ? and tree_id=? and bidsection_id= ? and project_id=? ", id, treeId, bidsectionId, projectId).Delete(contractsCm)
+	if err != nil {
+		session.Rollback()
+		return errors.New("删除失败")
+	}
+	if successNum == 0 {
+		session.Rollback()
+		return errors.New("合同数据异常,删除失败")
+	}
+
+	// 2.删除项目节上合同信息-需求变更-删除项目节
+	_, err = session.Exec("DELETE FROM `cm_tree_contracts` WHERE tree_id=? and project_id = ? and bidsection_id = ? ",
+		treeId, projectId, bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("编辑合同出错-项目节删除失败")
+	}
+	// _, err = session.Exec("UPDATE  cm_tree_contracts SET `contract_name` = '',`contract_code` = '',`contract_price` = 0,`contract_id` = 0,`contract_returned` = 0,`contracts_paid` = 0,`contract_status` = 0 "+
+	// 	",contract_locking=0 where tree_id = ? and project_id = ? and bidsection_id = ? ",
+	// 	treeId, projectId, bidsectionId)
+	// if err != nil {
+	// 	session.Rollback()
+	// 	return errors.New("编辑合同出错-项目节更新失败")
+	// }
+
+	// 3.删除回款信息
+	_, err = session.Exec("DELETE FROM `cm_contracts_return` WHERE contracts_id=? and project_id=? and bidsection_id=? ",
+		id, projectId, bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("编辑合同出错-删除回款信息失败")
+	}
+
+	// 4.删除附件-TODO
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("session出错-db")
+	}
+	return nil
+}
+
+// 删除支出合同
+func (d *ContractDao) DeleteExpenditure(projectId int, bidsectionId int, treeId int, id int) error {
+
+	contractsCm := models.CmContracts{}
+
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("session出错-db")
+	}
+	// 1.删除合同
+	successNum, err := session.Where("id = ? and tree_id=? and bidsection_id= ? and project_id=? ", id, treeId, bidsectionId, projectId).Delete(contractsCm)
+	if err != nil {
+		session.Rollback()
+		return errors.New("删除失败")
+	}
+	if successNum == 0 {
+		session.Rollback()
+		return errors.New("合同数据异常,删除失败")
+	}
+
+	// 2.删除项目节上合同信息--移除项目节需求变更
+	_, err = session.Exec("DELETE FROM `cm_tree_contracts` WHERE tree_id=? and project_id = ? and bidsection_id = ?  ",
+		treeId, projectId, bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("编辑合同出错-删除项目节失败")
+	}
+	// _, err = session.Exec("UPDATE  cm_tree_contracts SET `contract_name` = '',`contract_code` = '',`contract_price` = 0,`contract_id` = 0,`contract_returned` = 0,`contracts_paid` = 0,`contract_status` = 0 "+
+	// 	",contract_locking=0 where tree_id = ? and project_id = ? and bidsection_id = ? ",
+	// 	treeId, projectId, bidsectionId)
+	// if err != nil {
+	// 	session.Rollback()
+	// 	return errors.New("删除合同出错-项目节更新失败")
+	// }
+
+	// 3.删除已支付信息
+	_, err = session.Exec("DELETE FROM `cm_contracts_paid` WHERE contracts_id=? and project_id=? and bidsection_id=? ",
+		id, projectId, bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("编辑合同出错-删除已支付失败")
+	}
+
+	// 4.删除附件-TODO
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("session出错-db")
+	}
+	return nil
+}
+
+// 关闭合同
+func (d *ContractDao) Close(projectId int, bidsectionId int, treeId int, id int) error {
+
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("session出错-db")
+	}
+
+	// 1.关闭合同-关闭合同,默认锁定合同
+	contractsCm := models.CmContracts{}
+	contractsCm.Status = 2
+	contractsCm.Locking = 1
+	successNum, err := session.Where("id = ? and project_id = ? and bidsection_id = ? ", id, projectId, bidsectionId).Update(contractsCm)
+	if err != nil {
+		session.Rollback()
+		return errors.New("关闭合同出错")
+	}
+	if successNum == 0 {
+		session.Rollback()
+		return errors.New("关闭合同异常")
+	}
+
+	// 2.更新项目节合同状态,锁定合同
+	treeContractsCm := models.CmTreeContracts{}
+	treeContractsCm.ContractStatus = 2
+	treeContractsCm.ContractLocking = 1
+	successNum, err = session.Where("tree_id = ? and project_id = ? and bidsection_id = ? ", treeId, projectId, bidsectionId).Update(treeContractsCm)
+	if err != nil {
+		session.Rollback()
+		return errors.New("关闭合同出错-项目节")
+	}
+	if successNum == 0 {
+		session.Rollback()
+		return errors.New("关闭合同异常-项目节")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("session出错-db")
+	}
+	return nil
+}
+
+// 删除合同
+func (d *ContractDao) Unlock(projectId int, bidsectionId int, treeId int, id int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("session出错-db")
+	}
+
+	// 1.解锁合同
+	contractsCm := models.CmContracts{}
+	contractsCm.Locking = 0
+	contractsCm.Status = 1
+	_, err = session.Where("id = ? and project_id = ? and bidsection_id = ? ", id, projectId, bidsectionId).Cols("locking,Status").Update(contractsCm)
+	if err != nil {
+		session.Rollback()
+		return errors.New("解锁合同出错")
+	}
+
+	// 2.更新项目节上合同锁状态
+	treeContractsCm := models.CmTreeContracts{}
+	treeContractsCm.ContractLocking = 0
+	treeContractsCm.ContractStatus = 1
+	_, err = session.Where("tree_id = ? and project_id = ? and bidsection_id = ? ", treeId, projectId, bidsectionId).Cols("contract_locking,contract_status").Update(treeContractsCm)
+	if err != nil {
+		session.Rollback()
+		return errors.New("解锁合同出错-项目节")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("session出错-db")
+	}
+	return nil
+}
+
+// 筛选出应用了当前规则的条数
+func (d *ContractDao) CountRuleCode(bid int, contractType int) (int64, error) {
+	data := &models.CmContracts{}
+	total, err := d.engine.Where("`bidsection_id` = ? and `contracts_type` = ?", bid, contractType).Count(data)
+	if err != nil {
+		total = 0
+	}
+	return total, err
+}

+ 155 - 0
dao/contract_paid_dao.go

@@ -0,0 +1,155 @@
+/*
+ * @description:已支付相关数据操作
+ * @Author: CP
+ * @Date: 2020-12-22 14:46:06
+ * @FilePath: \construction_management\dao\contract_paid_dao.go
+ */
+package dao
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type ContractPaidDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewContractPaidDao(engine *xorm.Engine) *ContractPaidDao {
+	return &ContractPaidDao{
+		engine: engine,
+	}
+}
+
+// 获得回款
+func (d *ContractPaidDao) Get(id int, contractsId int, bidsectionId int) *models.CmContractsPaid {
+	data := &models.CmContractsPaid{Id: id, ContractsId: contractsId, BidsectionId: bidsectionId}
+	ok, err := d.engine.Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+
+}
+
+func (d *ContractPaidDao) GetAll(projectId int, bidsectionId int, contractsId int) []models.CmContractsPaid {
+	datalist := make([]models.CmContractsPaid, 0)
+
+	err := d.engine.
+		Where("project_id = ? and bidsection_id =? and contracts_id=?", projectId, bidsectionId, contractsId).
+		Desc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 创建已支付
+func (d *ContractPaidDao) Add(contractsPaid *models.CmContractsPaid) error {
+	_, err := d.engine.Insert(contractsPaid)
+	return err
+}
+
+// 更新已支付
+func (d *ContractPaidDao) Update(contractsReturn *models.CmContractsPaid, contracts_id int, bidsectionId int) error {
+	_, err := d.engine.Where("id = ? and contracts_id = ? and bidsection_id=? ", contractsReturn.Id, contracts_id, bidsectionId).Update(contractsReturn)
+	return err
+}
+
+// 删除回款
+func (d *ContractPaidDao) Delete(id int, contractsId int, bidsectionId int, projectId int) error {
+	data := &models.CmContractsPaid{}
+	_, err := d.engine.Where("id = ? and contracts_id = ? and project_id =? and bidsection_id = ? ", id, contractsId, projectId, bidsectionId).Delete(data)
+	return err
+}
+
+// 更新已支付总金额
+func (d *ContractPaidDao) UpdatePaidTotalPrice(projectId int, bidsectionId int, contractsId int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("session出错-db")
+	}
+
+	// 0.获得合同金额
+	contractsDetail := &models.CmContracts{}
+	_, err = d.engine.Where(" id = ? ", contractsId).Get(contractsDetail)
+	if err != nil {
+		return errors.New("未找到合同")
+	}
+
+	// 1.获得合同支付总金额
+	datalist := make([]models.CmContractsPaid, 0)
+	err = d.engine.Where(" project_id =? and bidsection_id = ? ", projectId, bidsectionId).Find(&datalist)
+	if err != nil {
+		session.Rollback()
+		return errors.New("编辑合同出错-项目节更新失败")
+	}
+	priceTotal := 0.00
+	contractsPrice := 0.00
+	for _, item := range datalist {
+		price, _ := strconv.ParseFloat(item.Price, 64)
+		priceTotal = priceTotal + price
+		if item.ContractsId == contractsId {
+			contractsPrice = contractsPrice + price
+		}
+	}
+	priceTotal, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", priceTotal), 64)
+	contractsPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", contractsPrice), 64)
+
+	// 1-1合同状态的判定
+	contractsDetailPrice, _ := strconv.ParseFloat(contractsDetail.Price, 64)
+	// 总回款大于等于合同金额 待关闭
+	contractStatus := 0
+	if contractsPrice >= contractsDetailPrice {
+		contractStatus = 1
+	}
+
+	// 2.更新合同表 合同下回款总金额
+	_, err = session.Exec("UPDATE  cm_contracts SET `paid` = ? , status = ?,locking=0 where id = ? ", contractsPrice, contractStatus, contractsId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("金额更新失败")
+	}
+	// 3.更新项目节 合同下回款总金额
+	_, err = session.Exec("UPDATE  cm_tree_contracts SET `contracts_paid` = ? , contract_status = ?,contract_locking=0 where project_id = ? and bidsection_id=? and contract_id=? ",
+		contractsPrice, contractStatus, projectId, bidsectionId, contractsId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("金额更新失败")
+	}
+	// 4.更新标段树 整个标段下回款总金额
+	_, err = session.Exec("UPDATE  cm_tree SET `contracts_paid` = ? where project_id = ? and bidsection_id=? ", priceTotal, projectId, bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("金额更新失败")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("session出错-db")
+	}
+	return nil
+}
+
+// 筛选出应用了当前规则的条数
+func (d *ContractPaidDao) CountPaidRuleCode(bid int) (int64, error) {
+	data := &models.CmContractsPaid{}
+	total, err := d.engine.Where("`bidsection_id` = ?", bid).Count(data)
+	if err != nil {
+		total = 0
+	}
+	return total, err
+}

+ 167 - 0
dao/contract_return_dao.go

@@ -0,0 +1,167 @@
+/*
+ * @description: 回款相关数据操作
+ * @Author: CP
+ * @Date: 2020-11-30 11:19:14
+ * @FilePath: \construction_management\dao\contract_return_dao.go
+ */
+package dao
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type ContractReturnDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewContractReturnDao(engine *xorm.Engine) *ContractReturnDao {
+	return &ContractReturnDao{
+		engine: engine,
+	}
+}
+
+// 获得回款
+func (d *ContractReturnDao) Get(id int, contractsId int, bidsectionId int) *models.CmContractsReturn {
+	data := &models.CmContractsReturn{Id: id, ContractsId: contractsId, BidsectionId: bidsectionId}
+	ok, err := d.engine.Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+
+}
+
+func (d *ContractReturnDao) GetAll(projectId int, bidsectionId int, contractsId int) []models.CmContractsReturn {
+	datalist := make([]models.CmContractsReturn, 0)
+
+	err := d.engine.
+		Where("project_id = ? and bidsection_id =? and contracts_id=?", projectId, bidsectionId, contractsId).
+		Desc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+//回款分页
+func (d *ContractReturnDao) GetPage(projectId int, bidsectionId int, contractsId int, page int) []models.CmContractsReturn {
+	datalist := make([]models.CmContractsReturn, 0)
+	size := 8
+	if page == 1 {
+		page = 0
+	} else {
+		page--
+		page = page * size
+	}
+
+	_ = d.engine.Where("project_id = ? and bidsection_id =? and contracts_id=?", projectId, bidsectionId, contractsId).
+		Limit(size, page).
+		Find(&datalist)
+	return datalist
+}
+
+// 创建回款
+func (d *ContractReturnDao) Add(contractsReturn *models.CmContractsReturn) error {
+	_, err := d.engine.Insert(contractsReturn)
+	return err
+}
+
+// 更新回款
+func (d *ContractReturnDao) Update(contractsReturn *models.CmContractsReturn, contracts_id int, bidsectionId int, columns []string) error {
+
+	_, err := d.engine.Where("id = ? and contracts_id = ? and bidsection_id=? ", contractsReturn.Id, contracts_id, bidsectionId).MustCols(columns...).Update(contractsReturn)
+
+	return err
+}
+
+// 删除回款
+func (d *ContractReturnDao) Delete(id int, contractsId int, bidsectionId int, projectId int) error {
+	data := &models.CmContractsReturn{}
+	is, err := d.engine.Where("id = ? and contracts_id = ? and project_id =? and bidsection_id = ? ", id, contractsId, projectId, bidsectionId).Delete(data)
+	if is == 0 {
+		return errors.New("未找到回款")
+	}
+	return err
+}
+
+// 更新回款总金额
+func (d *ContractReturnDao) UpdateTotalPrice(projectId int, bidsectionId int, contractsId int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("session出错-db")
+	}
+
+	// 0.获得合同金额
+	contractsDetail := &models.CmContracts{}
+	_, err = d.engine.Where(" id = ? ", contractsId).Get(contractsDetail)
+	if err != nil {
+		return errors.New("未找到合同")
+	}
+
+	// 1.获得合同回款总金额
+	datalist := make([]models.CmContractsReturn, 0)
+	err = d.engine.Where(" project_id =? and bidsection_id = ? ", projectId, bidsectionId).Find(&datalist)
+	if err != nil {
+		session.Rollback()
+		return errors.New("编辑合同出错-项目节更新失败")
+	}
+	priceTotal := 0.00
+	contractsPrice := 0.00
+	for _, item := range datalist {
+		price, _ := strconv.ParseFloat(item.Price, 64)
+		priceTotal = priceTotal + price
+		if item.ContractsId == contractsId {
+			contractsPrice = contractsPrice + price
+		}
+	}
+	priceTotal, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", priceTotal), 64)
+	contractsPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", contractsPrice), 64)
+
+	// 1-1合同状态的判定
+	contractsDetailPrice, _ := strconv.ParseFloat(contractsDetail.Price, 64)
+	// 总回款大于等于合同金额 待关闭
+	contractStatus := 0
+	if contractsPrice >= contractsDetailPrice {
+		contractStatus = 1
+	}
+
+	// 2.更新合同表 合同下回款总金额
+	_, err = session.Exec("UPDATE  cm_contracts SET `returned` = ? , status = ?,locking=0 where id = ? ", contractsPrice, contractStatus, contractsId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("金额更新失败")
+	}
+	// 3.更新项目节 合同下回款总金额
+	_, err = session.Exec("UPDATE  cm_tree_contracts SET `contract_returned` = ? , contract_status = ?,contract_locking=0 where project_id = ? and bidsection_id=? and contract_id=? ",
+		contractsPrice, contractStatus, projectId, bidsectionId, contractsId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("金额更新失败")
+	}
+	// 4.更新标段树 整个标段下回款总金额
+	_, err = session.Exec("UPDATE  cm_tree SET `contracts_returned` = ? where project_id = ? and bidsection_id=? ", priceTotal, projectId, bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("金额更新失败")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("session出错-db")
+	}
+	return nil
+}

+ 84 - 0
dao/manager_dao.go

@@ -0,0 +1,84 @@
+/*
+ * @description:管理员数据库操作
+ * @Author: CP
+ * @Date: 2020-08-20 15:55:37
+ * @FilePath: \construction_management\dao\manager_dao.go
+ */
+
+package dao
+
+import (
+	"fmt"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type ManagerDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewManagerDao(engine *xorm.Engine) *ManagerDao {
+	return &ManagerDao{
+		engine: engine,
+	}
+}
+
+//id获得数据
+func (d *ManagerDao) Get(id int) *models.CmManager {
+	data := &models.CmManager{Id: id}
+	//Get取到值后,会自动赋值到data中
+	ok, err := d.engine.Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+//获得全部管理员数据
+func (d *ManagerDao) GetAll() []models.CmManager {
+
+	datalist := make([]models.CmManager, 0)
+	err := d.engine.Asc("created_time").Find(&datalist)
+	//Asc("displayorder").
+	//Find(&datalist)
+	fmt.Println(err)
+	if err != nil {
+		//log.Println
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+//获得总数
+func (d *ManagerDao) CountAll() int64 {
+	num, err := d.engine.
+		Count(&models.CmManager{})
+	if err != nil {
+		return 0
+	} else {
+		return num
+	}
+}
+
+//创建
+func (d *ManagerDao) Create(data *models.CmManager) error {
+	_, err := d.engine.Insert(data)
+	return err
+}
+
+//更新
+func (d *ManagerDao) Update(data *models.CmManager, columns []string) error {
+	_, err := d.engine.Id(data.Id).MustCols(columns...).Update(data)
+	return err
+}
+
+func (d *ManagerDao) Delete(data *models.CmManager, columns []string) error {
+	_, err := d.engine.Id(data.Id).MustCols(columns...).Update(data)
+	return err
+}

+ 129 - 0
dao/permission_account_dao.go

@@ -0,0 +1,129 @@
+/*
+ * @description: 账号权限
+ * @Author: CP
+ * @Date: 2021-01-26 15:09:10
+ * @FilePath: \construction_management\dao\permission_account_dao.go
+ */
+
+package dao
+
+import (
+	"encoding/json"
+	"errors"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//数据库操作引擎
+type PermissionAccountDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewPermissionAccountDao(engine *xorm.Engine) *PermissionAccountDao {
+	return &PermissionAccountDao{
+		engine: engine,
+	}
+}
+
+// 获得标段下账号权限
+func (d *PermissionAccountDao) GetBidsectionId(bidsectionId int) []models.CmPermissionAccount {
+	datalist := make([]models.CmPermissionAccount, 0)
+	_ = d.engine.
+		Where(" bidsection_id=?  ", bidsectionId).
+		Find(&datalist)
+	return datalist
+}
+
+// 获得标段下账号权限
+func (d *PermissionAccountDao) GetBidsectionIdAccountId(bidsectionId int, accountId int) *models.CmPermissionAccount {
+	data := &models.CmPermissionAccount{}
+	_, err := d.engine.
+		Where(" bidsection_id= ? and account_id = ? ", bidsectionId, accountId).
+		Get(data)
+	if err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+// 获得项目下账号权限
+func (d *PermissionAccountDao) GetProjectIdAccountId(projectId int, accountId int) []models.CmPermissionAccount {
+	datalist := make([]models.CmPermissionAccount, 0)
+	_ = d.engine.
+		Where(" project_id=? and account_id= ?  ", projectId, accountId).
+		Find(&datalist)
+	return datalist
+}
+
+//更新
+func (d *PermissionAccountDao) Update(data *models.CmPermissionAccount, columns []string) error {
+	//_, err := d.engine.Id(data.Id).MustCols(columns...).Update(data)
+	_, err := d.engine.Where("project_id = ? and bidsection_id = ? and account_id= ? ", data.ProjectId, data.BidsectionId, data.AccountId).MustCols(columns...).Update(data)
+	if err != nil {
+		return errors.New("更新权限-账号失败")
+	}
+	return nil
+}
+
+// 获得当前账号下的标段权限
+func (d *PermissionAccountDao) GetPermissionWithAccountId(accountId int, bidsectionId int, isAdmin bool) (viewmodels.PermissionView, error) {
+	data := viewmodels.PermissionView{}
+	permission := viewmodels.Permission{}
+	if isAdmin == true {
+		permission.ContractAccess = 1
+		permission.ContractAdd = 1
+		permission.ContractDelete = 1
+		permission.QualityAccess = 1
+		permission.QualityAdd = 1
+		permission.QualityDelete = 1
+		permission.SafeAccess = 1
+		permission.SafeAdd = 1
+		permission.SafeDelete = 1
+	}
+	has, err := d.engine.
+		Sql("select * from cm_permission_account where bidsection_id= ? and account_id = ?", bidsectionId, accountId).
+		Get(&data)
+	if has == false {
+		contractPermission := map[string]int{
+			"add":    permission.ContractAccess,
+			"delete": permission.ContractDelete,
+			"access": permission.ContractAccess,
+		}
+		contractPermissionByte, err := json.Marshal(contractPermission)
+		if err != nil {
+			return data, errors.New("合同权限解析失败")
+		}
+		contractPermissionStr := string(contractPermissionByte)
+
+		qualityPermission := map[string]int{
+			"add":    permission.QualityAdd,
+			"delete": permission.QualityDelete,
+			"access": permission.QualityAccess,
+		}
+		qualityPermissionByte, err := json.Marshal(qualityPermission)
+		if err != nil {
+			return data, errors.New("合同权限解析失败")
+		}
+		qualityPermissionStr := string(qualityPermissionByte)
+
+		safePermission := map[string]int{
+			"add":    permission.SafeAdd,
+			"delete": permission.SafeDelete,
+			"access": permission.SafeAccess,
+		}
+		safePermissionByte, err := json.Marshal(safePermission)
+		if err != nil {
+			return data, errors.New("合同权限解析失败")
+		}
+		safePermissionStr := string(safePermissionByte)
+		data.ContractPermission = contractPermissionStr
+		data.QualityPermission = qualityPermissionStr
+		data.SafePermission = safePermissionStr
+	}
+	return data, err
+}

+ 145 - 0
dao/project_account_dao.go

@@ -0,0 +1,145 @@
+/*
+ * @description:项目用户数据库操作
+ * @Author: CP
+ * @Date: 2020-08-31 15:57:04
+ * @FilePath: \construction_management\dao\project_account_dao.go
+ */
+package dao
+
+import (
+	"errors"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//数据库操作引擎
+type ProjectAccountDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewProjectAccountDao(engine *xorm.Engine) *ProjectAccountDao {
+	return &ProjectAccountDao{
+		engine: engine,
+	}
+}
+
+//CmProjectAccount 设置的值获得数据-弃用
+// func (d *ProjectAccountDao) GetOne(data *models.CmProjectAccount) *models.CmProjectAccount {
+// 	//data := data
+// 	//Get取到值后,会自动赋值到data中
+// 	ok, err := d.engine.
+// 		Where("account = ?", data.Account).
+// 		Get(data)
+// 	if ok && err == nil {
+// 		return data
+// 	} else {
+// 		data.Id = 0
+// 		return data
+// 	}
+// }
+
+// 根据账号获得数据
+func (d *ProjectAccountDao) GetAccount(account string) *models.CmProjectAccount {
+	data := &models.CmProjectAccount{}
+	ok, err := d.engine.
+		Where("account = ?", account).
+		Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+//id获得数据
+func (d *ProjectAccountDao) Get(id int, projectId int) *models.CmProjectAccount {
+	data := &models.CmProjectAccount{Id: id, ProjectId: projectId}
+	ok, err := d.engine.Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+// 获得项目下的账号信息
+func (d *ProjectAccountDao) GetAll(projectId int) []models.CmProjectAccount {
+	datalist := make([]models.CmProjectAccount, 0)
+	err := d.engine.
+		Where("project_id = ?", projectId).
+		Desc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+func (d *ProjectAccountDao) GetInId(ids string, name string) []models.CmProjectAccount {
+
+	datalist := make([]models.CmProjectAccount, 0)
+	err := d.engine.
+		Where("id in ( "+ids+" ) ").
+		And("account like ? or name like ? or company like ? or mobile like ?", name+"%", name+"%", name+"%", name+"%").
+		Desc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 检索 账号姓名单位手机
+func (d *ProjectAccountDao) Search(name string, projectId int) []models.CmProjectAccount {
+	datalist := make([]models.CmProjectAccount, 0)
+	err := d.engine.
+		Where("project_id = ? ", projectId).
+		And("account like ? or name like ? or company like ? or mobile like ?", name+"%", name+"%", name+"%", name+"%").
+		Desc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 新增
+func (d *ProjectAccountDao) Add(data *models.CmProjectAccount) error {
+	_, err := d.engine.Insert(data)
+	return err
+}
+
+//更新
+func (d *ProjectAccountDao) Update(data *models.CmProjectAccount, columns []string) error {
+	//_, err := d.engine.Id(data.Id).MustCols(columns...).Update(data)
+	_, err := d.engine.Where("id = ? and project_id = ? ", data.Id, data.ProjectId).MustCols(columns...).Update(data)
+	if err != nil {
+		return errors.New("更新账号失败")
+	}
+	return nil
+}
+
+// 物理删除
+func (d *ProjectAccountDao) Delete(data *models.CmProjectAccount) error {
+	_, err := d.engine.Where("id = ? and project_id = ? ", data.Id, data.ProjectId).Delete(data)
+	if err != nil {
+		return errors.New("删除到账号失败")
+	}
+	return nil
+}
+
+// 查找
+func (d *ProjectAccountDao) FindById(id int) (viewmodels.ProjectInfo, error) {
+
+	projectInfo := viewmodels.ProjectInfo{}
+	_, err := d.engine.Sql("select p.`name` as project_name, p.`code`, p.`create_time`, a.`mobile`, a.`name` from `cm_project` as p, `cm_project_account` as a where p.`user_id` = a.`id` and p.`id` = ?", id).Get(&projectInfo)
+	return projectInfo, err
+}

+ 104 - 0
dao/project_dao.go

@@ -0,0 +1,104 @@
+/*
+ * @description:工程项目数据库操作
+ * @Author: CP
+ * @Date: 2020-09-03 14:40:06
+ * @FilePath: \construction_management\dao\project_dao.go
+ */
+package dao
+
+import (
+	"errors"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type ProjectDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewProjectDao(engine *xorm.Engine) *ProjectDao {
+	return &ProjectDao{
+		engine: engine,
+	}
+}
+
+//CmProjectAccount 设置的值获得数据
+// func (d *ProjectDao) Get(data *models.CmProject) {
+// 	//data := data
+// 	ok, err := d.engine.Get(data)
+// 	if ok && err == nil {
+// 		//return nil
+// 	} else {
+// 		data.Id = 0
+// 		//return err
+// 	}
+// }
+
+func (d *ProjectDao) GetPage(page int, size int) []models.CmProject {
+	datalist := make([]models.CmProject, 0)
+	if page == 1 {
+		page = 0
+	} else {
+		page--
+		page = page * size
+	}
+	// Where("project_id = ? and bidsection_id =? and contracts_id=?", projectId, bidsectionId, contractsId).
+	_ = d.engine.
+		Limit(size, page).
+		Find(&datalist)
+	return datalist
+}
+
+//设置的值获得数据
+func (d *ProjectDao) GetCode(code string) *models.CmProject {
+	data := &models.CmProject{}
+	ok, err := d.engine.
+		Where("code = ?", code).
+		Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+// 获得一组项目数据
+func (d *ProjectDao) GetListByCode(code string) []models.CmProject {
+	datalist := make([]models.CmProject, 0)
+
+	err := d.engine.
+		Where("code = ?", code).
+		Desc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 新增
+func (d *ProjectDao) Add(data *models.CmProject) error {
+	_, err := d.engine.Insert(data)
+	return err
+}
+
+//更新
+func (d *ProjectDao) Update(data *models.CmProject, columns []string) error {
+	//_, err := d.engine.Id(data.Id).MustCols(columns...).Update(data)
+	is, err := d.engine.Where("id = ?  ", data.Id).MustCols(columns...).Update(data)
+	if is == 0 {
+		return errors.New("未找到项目")
+	}
+	return err
+}
+
+func (d *ProjectDao) FindById(id int) (*models.CmProject, error) {
+	data := &models.CmProject{}
+	_, err := d.engine.Where("id=?", id).Get(data)
+	return data, err
+}

+ 36 - 0
dao/project_message_dao.go

@@ -0,0 +1,36 @@
+/*
+ * @description:消息推送
+ * @Author: LanJianRong
+ * @Date: 2021-01-26 14:40:06
+ * @FilePath: \construction_management\dao\project_message_dao.go
+ */
+package dao
+
+import (
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type ProjectMessageDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewProjectMessageDao(engine *xorm.Engine) *ProjectMessageDao {
+	return &ProjectMessageDao{
+		engine: engine,
+	}
+}
+
+// 获得项目下 账号的消息
+func (d *ProjectMessageDao) GetAll(projectId int, accountId int) []models.CmProjectMessage {
+
+	datalist := make([]models.CmProjectMessage, 0)
+	_ = d.engine.
+		Where("project_id=? and account_id=? ",
+			projectId, accountId).
+		Desc("id").
+		Find(&datalist)
+	return datalist
+}

+ 108 - 0
dao/quality_audit_dao.go

@@ -0,0 +1,108 @@
+/*
+ * @description: 安全巡检数据库操作相关
+ * @Author: LanJianRong
+ * @Date: 2020-11-20
+ * @FilePath: \construction_management\dao\quality_dao.go
+ */
+
+package dao
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//数据库操作引擎
+type QualityAuditDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewQualityAuditDao(engine *xorm.Engine) *QualityAuditDao {
+	return &QualityAuditDao{
+		engine: engine,
+	}
+}
+
+// 添加审批记录
+func (d *QualityAuditDao) AddAuditRecord(qualityId int, bId int, auditId int, times int, status int, progress int, opinion string, rectifiedInfo string) error {
+	auditor := &models.CmQualityAudit{QualityId: qualityId, BidsectionId: bId, AuditId: auditId, Times: times, CreateTime: time.Now(), Status: status, Progress: progress, Opinion: opinion, Rectifiedinfo: rectifiedInfo}
+	_, err := d.engine.InsertOne(auditor)
+	return err
+}
+
+// 获取最新审批顺序
+func (d *QualityAuditDao) GetNewOrder(qualityId int, times int) int {
+	var max_order int
+	_, err := d.engine.Sql("select Max(`audit_order`) as max_order from cm_quality_audit where quality_id = ? and times = ?", qualityId, times).Get(&max_order)
+	fmt.Println(err)
+	if max_order == 0 {
+		return 1
+	} else {
+		return max_order + 1
+	}
+}
+
+// times从1开始循环,往history里面push
+func (d *QualityAuditDao) GetAuditHistory(id int, times int) map[int][]viewmodels.HistoryQualityAudit {
+	auditorHistory := make(map[int][]viewmodels.HistoryQualityAudit, 0)
+	for i := 1; i <= times; i++ {
+		auditors := make([]viewmodels.HistoryQualityAudit, 0)
+		d.engine.Sql("select ca.`id`, pa.`name`, pa.`position`, ca.`create_time`, ca.progress, ca.opinion, ca.status from `cm_project_account` as pa, `cm_quality_audit` as ca where ca.`quality_id` = ? and ca.`audit_id` = pa.`id` and times = ? order by id desc", id, i).Find(&auditors)
+		auditorsArr := make([]viewmodels.HistoryQualityAudit, 0)
+		for _, auditor := range auditors {
+			auditorVM := viewmodels.HistoryQualityAudit{}
+			id, _ := comm.AesEncrypt(auditor.Id, conf.SignSecret)
+			auditorVM.Id = id
+			auditorVM.CreateTime = auditor.CreateTime
+			auditorVM.Name = auditor.Name
+			auditorVM.Position = auditor.Position
+			auditorVM.Status = auditor.Status
+			auditorVM.Opinion = auditor.Opinion
+			auditorVM.Progress = auditor.Progress
+			auditorsArr = append(auditorsArr, auditorVM)
+		}
+		auditorHistory[i] = auditorsArr
+	}
+	return auditorHistory
+}
+
+// 根据id获取记录
+func (d *QualityAuditDao) FindById(id int) (*models.CmQualityAudit, error) {
+	data := &models.CmQualityAudit{Id: id}
+	_, err := d.engine.Get(data)
+	return data, err
+}
+
+// 查找最新的整改单
+func (d *QualityAuditDao) GetLastedOrder(QualityId int) ([]viewmodels.CheckOrderVM, error) {
+	data := make([]viewmodels.CheckOrderVM, 0)
+	err := d.engine.Sql("select cm.`rectifiedInfo` as opinion, cm.`create_time`, pa.`name` from `cm_quality_audit` as cm left join `cm_project_account` as pa on pa.`id` = cm.`audit_id` where cm.`quality_id` = ? and cm.`progress` = ?", QualityId, 2).Find(&data)
+	return data, err
+}
+
+// 插入审批记录
+func (d *QualityAuditDao) InsertData(data models.CmQualityAudit) error {
+	_, err := d.engine.Insert(&data)
+	return err
+}
+
+// 改变下一条审批记录为待审核状态
+func (d *QualityAuditDao) ChangeNextRecord(times int, audit_order int) error {
+	data := &models.CmQualityAudit{Status: 1, CreateTime: time.Now()}
+	_, err := d.engine.Where("times = ? and audit_order = ?", times, audit_order).Update(data)
+	return err
+}
+
+// 获取最后一个审批人
+func (d *QualityAuditDao) GetLastAuditor(times int, QualityId int) (*models.CmQualityAudit, error) {
+	data := &models.CmQualityAudit{}
+	_, err := d.engine.Where("times = ? and quality_id = ?", times, QualityId).Desc("audit_order").Limit(1).Get(data)
+	return data, err
+}

+ 224 - 0
dao/quality_dao.go

@@ -0,0 +1,224 @@
+/*
+ * @description: 安全巡检数据库操作相关
+ * @Author: LanJianRong
+ * @Date: 2020-11-20
+ * @FilePath: \construction_management\dao\quality_dao.go
+ */
+
+package dao
+
+import (
+	"errors"
+	"fmt"
+	"time"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//数据库操作引擎
+type QualityDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewQualityDao(engine *xorm.Engine) *QualityDao {
+	return &QualityDao{
+		engine: engine,
+	}
+}
+
+func (d *QualityDao) GetInIdJoinAccount(ids string) []viewmodels.QualityList {
+
+	datalist := make([]viewmodels.QualityList, 0)
+	err := d.engine.
+		Table("`cm_quality` as cs").
+		Select("cs.id, cs.`create_time`, cs.`inspection_detail`,cs.code, cs.status, pa.`name` as `audit_name`, pa.`position`").
+		Where("cs.id in ( "+ids+" ) ").
+		Join("left", "cm_project_account as pa", "pa.id = cs.uid").
+		Desc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+
+	// datalist := make([]models.CmQuality, 0)
+	// err := d.engine.
+	// 	Where("id in ( " + ids + " ) ").
+	// 	Desc("id").
+	// 	Find(&datalist)
+	// if err != nil {
+	// 	return datalist
+	// } else {
+	// 	return datalist
+	// }
+}
+
+func (d *QualityDao) FindById(id int) *models.CmQuality {
+	data := &models.CmQuality{Id: id}
+	ok, err := d.engine.Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+// id获得数据
+func (d *QualityDao) GetListByBid(id int, pageNo int, pageSize int) ([]models.CmQuality, int64) {
+	dataList := make([]models.CmQuality, 0)
+	start := (pageNo - 1) * pageSize
+	total, err := d.engine.
+		Where("bidsection_id=?", id).
+		Asc("id").
+		Limit(pageSize, start).
+		FindAndCount(&dataList)
+	if err != nil {
+		return dataList, 0
+	}
+	return dataList, total
+}
+
+// 插入单条记录
+func (d *QualityDao) InsertRecord(data models.CmQuality) (bool, error) {
+	affected, err := d.engine.InsertOne(data)
+	return affected > 0, err
+}
+
+// 删除记录
+func (d *QualityDao) DeleteRecord(id int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+
+	quality := &models.CmQuality{Id: id}
+	_, err = session.Get(quality)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	bidsectionId := quality.BidsectionId
+	_, err = session.ID(id).Delete(quality)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	// 计算当前安全巡检总数
+	_, err = session.Exec("update `cm_tree` set `quality_total` = if(`quality_total` >= 1, `quality_total` - 1, 0),  `quality_rectification` = if(`quality_rectification` >= 1, `quality_rectification` - 1, 0) where `bidsection_id` = ?", bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	err = session.Commit()
+	return err
+}
+
+// 根据code获取记录
+func (d *QualityDao) FindByCode(code string) bool {
+	data := &models.CmQuality{Code: code}
+	has, _ := d.engine.Get(data)
+	return has
+}
+
+// 筛选出应用了当前规则的条数
+func (d *QualityDao) CountRuleCode(bid int) (int64, error) {
+	data := &models.CmQuality{}
+	total, err := d.engine.Where("`bidsection_id` = ?", bid).Count(data)
+	if err != nil {
+		total = 0
+	}
+	return total, err
+}
+
+// 更改status
+func (d *QualityDao) ChangeStatus(id int, status int, inspection string, inspectionDetail string, demand string, createTime time.Time) error {
+	data := &models.CmQuality{Status: status, Inspection: inspection, InspectionDetail: inspectionDetail, Demand: demand, CreateTime: createTime}
+	_, err := d.engine.ID(id).Cols("status", " inspection", "inspection_detail", "demand", "create_time").Update(data)
+	return err
+}
+
+// 获得某状态下的安全
+func (d *QualityDao) GetStatus(bidsectionId int, status int) []models.CmQuality {
+	datalist := make([]models.CmQuality, 0)
+	_ = d.engine.
+		Where("bidsection_id = ? and status=? ", bidsectionId, status).
+		Desc("id").
+		Find(&datalist)
+	return datalist
+}
+
+// 获得某年份下的安全
+func (d *QualityDao) GetTypeYear(bidsectionId int, year int) []viewmodels.QualitySurveyList {
+
+	startYear := fmt.Sprintf("%d-01-01:00.00.00", year)
+	endYear := fmt.Sprintf("%d-12-31:23.59.59", year)
+
+	datalist := make([]viewmodels.QualitySurveyList, 0)
+	_ = d.engine.Table("`cm_quality` as cs").
+		Select("cs.id, cs.`create_time`, cs.`inspection_detail`, cs.status, pa.`name` as `audit_name`").
+		Where("cs.bidsection_id = ? and cs.create_time>='"+startYear+"' and cs.create_time<='"+endYear+"' ", bidsectionId).
+		Join("left", "cm_project_account as pa", "pa.id = cs.uid").
+		Desc("id").
+		Find(&datalist)
+	// _ = d.engine.
+	// 	Where("bidsection_id = ? and create_time>='"+startYear+"' and create_time<='"+endYear+"' ", bidsectionId).
+	// 	Desc("id").
+	// 	Find(&datalist)
+	return datalist
+}
+
+// 获得某状态下的安全
+func (d *QualityDao) GetStatusByProjectAndAccount(projectId int, projectAccountId int, status int) []models.CmQuality {
+	datalist := make([]models.CmQuality, 0)
+	_ = d.engine.
+		Where("project_id = ? and audit_id= ? and status=? ", projectId, projectAccountId, status).
+		Desc("id").
+		Find(&datalist)
+	return datalist
+}
+
+// 事务-创建新的安全巡检记录
+func (d *QualityDao) CreateQuality(data models.CmQuality) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	quality := models.CmQuality{}
+	has, err := session.Where("code = ? and bidsection_id = ?", data.Code, data.BidsectionId).Get(&quality)
+	// err或者code存在都回滚
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	if has == true {
+		session.Rollback()
+		return errors.New("该编号已存在!")
+	}
+	_, err = session.Insert(data)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	// 更新cm_tree中的quality_total、quality_rectification
+	_, err = session.Exec("update `cm_tree` set `quality_total` = `quality_total` + 1 , `quality_rectification` = `quality_rectification` + 1 where `bidsection_id` = ?", data.BidsectionId)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	err = session.Commit()
+	if err != nil {
+		return err
+	}
+	return nil
+}

+ 58 - 0
dao/rule_dao.go

@@ -0,0 +1,58 @@
+/*
+ * @description: 编号规则数据库操作相关
+ * @Author: LanJianRong
+ * @Date: 2020-11-27
+ * @FilePath: \construction_management\dao\rule_dao.go
+ */
+
+package dao
+
+import (
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type RuleDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewRuleDao(engine *xorm.Engine) *RuleDao {
+	return &RuleDao{
+		engine: engine,
+	}
+}
+
+// 通过项目id和标段id查找
+func (d *RuleDao) FindByPidWithBid(pid int, bid int) *models.CmRule {
+	data := &models.CmRule{BidsectionId: bid, ProjectId: pid}
+	ok, err := d.engine.Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+// 根据pid和bid更新、不存在则创建
+func (d *RuleDao) UpdateOrCreate(pid int, bid int, key string, value string) error {
+	data := &models.CmRule{BidsectionId: bid, ProjectId: pid}
+	has, err := d.engine.Get(data)
+	if key == "safe_rule" {
+		data.SafeRule = value
+	} else if key == "quality_rule" {
+		data.QualityRule = value
+	} else if key == "contract_return_rule" {
+		data.ContractReturnRule = value
+	} else {
+		data.ContractPaidRule = value
+	}
+	if has && err == nil {
+		_, err = d.engine.Cols(key).Id(data.Id).Update(data)
+	} else if !has && err == nil {
+		_, err = d.engine.Insert(data)
+	}
+	return err
+}

+ 108 - 0
dao/safe_audit_dao.go

@@ -0,0 +1,108 @@
+/*
+ * @description: 安全巡检数据库操作相关
+ * @Author: LanJianRong
+ * @Date: 2020-11-20
+ * @FilePath: \construction_management\dao\safe_dao.go
+ */
+
+package dao
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//数据库操作引擎
+type SafeAuditDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewSafeAuditDao(engine *xorm.Engine) *SafeAuditDao {
+	return &SafeAuditDao{
+		engine: engine,
+	}
+}
+
+// 添加审批记录
+func (d *SafeAuditDao) AddAuditRecord(safeId int, bId int, auditId int, times int, status int, progress int, opinion string, rectifiedInfo string) error {
+	auditor := &models.CmSafeAudit{SafeId: safeId, BidsectionId: bId, AuditId: auditId, Times: times, CreateTime: time.Now(), Status: status, Progress: progress, Opinion: opinion, Rectifiedinfo: rectifiedInfo}
+	_, err := d.engine.InsertOne(auditor)
+	return err
+}
+
+// 获取最新审批顺序
+func (d *SafeAuditDao) GetNewOrder(safeId int, times int) int {
+	var max_order int
+	_, err := d.engine.Sql("select Max(`audit_order`) as max_order from cm_safe_audit where safe_id = ? and times = ?", safeId, times).Get(&max_order)
+	fmt.Println(err)
+	if max_order == 0 {
+		return 1
+	} else {
+		return max_order + 1
+	}
+}
+
+// times从1开始循环,往history里面push
+func (d *SafeAuditDao) GetAuditHistory(id int, times int) map[int][]viewmodels.HistorySafeAudit {
+	auditorHistory := make(map[int][]viewmodels.HistorySafeAudit, 0)
+	for i := 1; i <= times; i++ {
+		auditors := make([]viewmodels.HistorySafeAudit, 0)
+		d.engine.Sql("select ca.`id`, pa.`name`, pa.`position`, ca.`create_time`, ca.progress, ca.opinion, ca.status from `cm_project_account` as pa, `cm_safe_audit` as ca where ca.`safe_id` = ? and ca.`audit_id` = pa.`id` and times = ? order by id desc", id, i).Find(&auditors)
+		auditorsArr := make([]viewmodels.HistorySafeAudit, 0)
+		for _, auditor := range auditors {
+			auditorVM := viewmodels.HistorySafeAudit{}
+			id, _ := comm.AesEncrypt(auditor.Id, conf.SignSecret)
+			auditorVM.Id = id
+			auditorVM.CreateTime = auditor.CreateTime
+			auditorVM.Name = auditor.Name
+			auditorVM.Position = auditor.Position
+			auditorVM.Status = auditor.Status
+			auditorVM.Opinion = auditor.Opinion
+			auditorVM.Progress = auditor.Progress
+			auditorsArr = append(auditorsArr, auditorVM)
+		}
+		auditorHistory[i] = auditorsArr
+	}
+	return auditorHistory
+}
+
+// 根据id获取记录
+func (d *SafeAuditDao) FindById(id int) (*models.CmSafeAudit, error) {
+	data := &models.CmSafeAudit{Id: id}
+	_, err := d.engine.Get(data)
+	return data, err
+}
+
+// 查找最新的整改单
+func (d *SafeAuditDao) GetLastedOrder(safeId int) ([]viewmodels.CheckOrderVM, error) {
+	data := make([]viewmodels.CheckOrderVM, 0)
+	err := d.engine.Sql("select cm.`rectifiedInfo` as opinion, cm.`create_time`, pa.`name` from `cm_safe_audit` as cm left join `cm_project_account` as pa on pa.`id` = cm.`audit_id` where cm.`safe_id` = ? and cm.`progress` = ?", safeId, 2).Find(&data)
+	return data, err
+}
+
+// 插入审批记录
+func (d *SafeAuditDao) InsertData(data models.CmSafeAudit) error {
+	_, err := d.engine.Insert(&data)
+	return err
+}
+
+// 改变下一条审批记录为待审核状态
+func (d *SafeAuditDao) ChangeNextRecord(times int, audit_order int) error {
+	data := &models.CmSafeAudit{Status: 1, CreateTime: time.Now()}
+	_, err := d.engine.Where("times = ? and audit_order = ?", times, audit_order).Update(data)
+	return err
+}
+
+// 获取最后一个审批人
+func (d *SafeAuditDao) GetLastAuditor(times int, safeId int) (*models.CmSafeAudit, error) {
+	data := &models.CmSafeAudit{}
+	_, err := d.engine.Where("times = ? and safe_id = ?", times, safeId).Desc("audit_order").Limit(1).Get(data)
+	return data, err
+}

+ 221 - 0
dao/safe_dao.go

@@ -0,0 +1,221 @@
+/*
+ * @description: 安全巡检数据库操作相关
+ * @Author: LanJianRong
+ * @Date: 2020-11-20
+ * @FilePath: \construction_management\dao\safe_dao.go
+ */
+
+package dao
+
+import (
+	"errors"
+	"fmt"
+	"time"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//数据库操作引擎
+type SafeDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewSafeDao(engine *xorm.Engine) *SafeDao {
+	return &SafeDao{
+		engine: engine,
+	}
+}
+
+func (d *SafeDao) GetInIdJoinAccount(ids string) []viewmodels.SafeList {
+
+	datalist := make([]viewmodels.SafeList, 0)
+	err := d.engine.
+		Table("`cm_safe` as cs").
+		Select("cs.id, cs.`create_time`, cs.`inspection_detail`,cs.code, cs.status, pa.`name` as `audit_name`, pa.`position`").
+		Where("cs.id in ( "+ids+" ) ").
+		Join("left", "cm_project_account as pa", "pa.id = cs.uid").
+		Desc("id").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+func (d *SafeDao) FindById(id int) *models.CmSafe {
+	data := &models.CmSafe{Id: id}
+	ok, err := d.engine.Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}
+
+// id获得数据
+func (d *SafeDao) GetListByBid(id int, pageNo int, pageSize int) ([]models.CmSafe, int64) {
+	dataList := make([]models.CmSafe, 0)
+	start := (pageNo - 1) * pageSize
+	total, err := d.engine.
+		Where("bidsection_id=?", id).
+		Asc("id").
+		Limit(pageSize, start).
+		FindAndCount(&dataList)
+	if err != nil {
+		return dataList, 0
+	}
+	return dataList, total
+}
+
+// 插入单条记录
+func (d *SafeDao) InsertRecord(data models.CmSafe) (bool, error) {
+	affected, err := d.engine.InsertOne(data)
+	return affected > 0, err
+}
+
+// 删除记录
+func (d *SafeDao) DeleteRecord(id int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+
+	safe := &models.CmSafe{Id: id}
+	_, err = session.Get(safe)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	bidsectionId := safe.BidsectionId
+	_, err = session.ID(id).Delete(safe)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	// 计算当前安全巡检总数
+	_, err = session.Exec("update `cm_tree` set `safe_total` = if(`safe_total` >= 1, `safe_total` - 1, 0), `safe_rectification` = if(`safe_rectification` >= 1, `safe_rectification` - 1, 0) where `bidsection_id` = ?", bidsectionId)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	err = session.Commit()
+	return err
+}
+
+// 根据code获取记录
+func (d *SafeDao) FindByCode(code string) (bool, error) {
+	data := &models.CmSafe{Code: code}
+	has, err := d.engine.Get(data)
+	return has, err
+}
+
+// 筛选出应用了当前规则的条数
+func (d *SafeDao) CountRuleCode(bid int) (int64, error) {
+	data := &models.CmSafe{}
+	total, err := d.engine.Where("`bidsection_id` = ?", bid).Count(data)
+	if err != nil {
+		total = 0
+	}
+	return total, err
+}
+
+// 更改status
+func (d *SafeDao) ChangeStatus(id int, status int, inspection string, inspectionDetail string, demand string, createTime time.Time) error {
+	data := &models.CmSafe{Status: status, Inspection: inspection, InspectionDetail: inspectionDetail, Demand: demand, CreateTime: createTime}
+	_, err := d.engine.ID(id).Cols("status", " inspection", "inspection_detail", "demand", "create_time").Update(data)
+	return err
+}
+
+// 获得某状态下的安全
+func (d *SafeDao) GetStatus(bidsectionId int, status int) []models.CmSafe {
+	datalist := make([]models.CmSafe, 0)
+	_ = d.engine.
+		Where("bidsection_id = ? and status=? ", bidsectionId, status).
+		Desc("id").
+		Find(&datalist)
+	return datalist
+}
+
+// 获得某状态下的安全
+func (d *SafeDao) GetStatusByProjectAndAccount(projectId int, projectAccountId int, status int) []models.CmSafe {
+	datalist := make([]models.CmSafe, 0)
+	_ = d.engine.
+		Where("project_id = ? and audit_id= ? and status=? ", projectId, projectAccountId, status).
+		Desc("id").
+		Find(&datalist)
+	return datalist
+}
+
+// 获得某年份下的安全
+func (d *SafeDao) GetTypeYear(bidsectionId int, year int) []viewmodels.SafeSurveyList {
+
+	startYear := fmt.Sprintf("%d-01-01:00.00.00", year)
+	endYear := fmt.Sprintf("%d-12-31:23.59.59", year)
+
+	datalist := make([]viewmodels.SafeSurveyList, 0)
+	_ = d.engine.Table("`cm_safe` as cs").
+		Select("cs.id, cs.`create_time`, cs.`inspection_detail`, cs.status, pa.`name` as `audit_name`").
+		Where("cs.bidsection_id = ? and cs.create_time>='"+startYear+"' and cs.create_time<='"+endYear+"' ", bidsectionId).
+		Join("left", "cm_project_account as pa", "pa.id = cs.uid").
+		Desc("id").
+		Find(&datalist)
+	return datalist
+}
+
+// 根据bid
+func (d *SafeDao) GetCountsByBid(bidsectionId int, status int, isAll bool) (int64, error) {
+	data := &models.CmSafe{}
+	if isAll == true {
+		counts, err := d.engine.Where("bidsection_id = ?", bidsectionId).Count(data)
+		return counts, err
+	} else {
+		counts, err := d.engine.Where("bidsection_id = ? and status = ?", bidsectionId, status).Count(data)
+		return counts, err
+	}
+}
+
+// 事务-创建新的安全巡检记录
+func (d *SafeDao) CreateSafe(data models.CmSafe) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	safe := models.CmSafe{}
+	has, err := session.Where("code = ? and bidsection_id = ?", data.Code, data.BidsectionId).Get(&safe)
+	// err或者code存在都回滚
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	if has == true {
+		session.Rollback()
+		return errors.New("该编号已存在!")
+	}
+	_, err = session.Insert(data)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	// 更新cm_tree中的safe_total、safe_rectification
+	_, err = session.Exec("update `cm_tree` set `safe_total` = `safe_total` + 1 , `safe_rectification` = `safe_rectification` + 1 where `bidsection_id` = ?", data.BidsectionId)
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	err = session.Commit()
+	if err != nil {
+		return err
+	}
+	return nil
+}

+ 556 - 0
dao/tree_contract_dao.go

@@ -0,0 +1,556 @@
+/*
+ * @description: 合同项目节相关数据库操作
+ * @Author: CP
+ * @Date: 2020-11-02 11:37:32
+ * @FilePath: \construction_management\dao\tree_contract_dao.go
+ */
+package dao
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"strings"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type TreeContractDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewTreeContractDao(engine *xorm.Engine) *TreeContractDao {
+	return &TreeContractDao{
+		engine: engine,
+	}
+}
+
+// 获得本项目的合同项目节
+func (d *TreeContractDao) Get(treeId int, bidsectionId int, projectId int, treeType int) *models.CmTreeContracts {
+
+	data := &models.CmTreeContracts{}
+	_, err := d.engine.
+		Where("tree_id=? and bidsection_id =? and project_id=? and  tree_type=?", treeId, bidsectionId, projectId, treeType).
+		Get(data)
+
+	if err != nil {
+		data.Id = 0
+		return data
+	}
+	return data
+}
+
+// 获得项目下的项目节
+func (d *TreeContractDao) GetAll(bidsectionId int, projectId int, treeType int) []models.CmTreeContracts {
+
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Asc("id").
+		Where("bidsection_id =? and project_id=? and tree_type=?", bidsectionId, projectId, treeType).
+		Limit(5000, 0).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得项目下的项目节不包含合同
+func (d *TreeContractDao) GetAllNotContract(bidsectionId int, projectId int, treeType int) []models.CmTreeContracts {
+
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Asc("id").
+		Where("bidsection_id =? and project_id=? and tree_type=? and contract_id=0", bidsectionId, projectId, treeType).
+		Limit(5000, 0).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得最新ID
+func (d *TreeContractDao) GetLastId() *models.CmTreeContracts {
+	data := &models.CmTreeContracts{}
+	_, err := d.engine.
+		Desc("id").
+		Get(data)
+	if err != nil {
+		data.Id = 0
+		return data
+	}
+	return data
+}
+
+// 获得项目节所有合同
+func (d *TreeContractDao) GetContractAll(bidsectionId int, projectId int) []models.CmTreeContracts {
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Asc("id").
+		Where("bidsection_id =? and project_id=? and contract_id!=0 ", bidsectionId, projectId).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得标段 项目节中已有的合同
+func (d *TreeContractDao) GetContract(bidsectionId int, projectId int, treeType int) []models.CmTreeContracts {
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Asc("id").
+		Where("bidsection_id =? and project_id=? and contract_id!=0 and tree_type=?", bidsectionId, projectId, treeType).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得节点的孩子
+func (d *TreeContractDao) GetChildren(parentId int, bidsectionId int, projectId int, treeType int) []models.CmTreeContracts {
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("parent_id=?  and bidsection_id=? and project_id=? and tree_type=?", parentId, bidsectionId, projectId, treeType).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+//根据序号和深度获得前一个兄弟节点
+func (d *TreeContractDao) GetElderBrother(serial int, depth int, parentId int, bidsectionId int, projectId int, treeType int) []models.CmTreeContracts {
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Desc("serial").
+		Where("serial < ? and depth = ? and  parent_id =? and bidsection_id=?  and project_id=? and tree_type=?", serial, depth, parentId, bidsectionId, projectId, treeType).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+//根据序号和深度获得后一个兄弟节点
+func (d *TreeContractDao) GetYoungerBrother(serial int, depth int, parentId int, bidsectionId int, projectId int, treeType int) []models.CmTreeContracts {
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("serial > ? and depth = ? and  parent_id =? and bidsection_id=?   and project_id=? and tree_type=?", serial, depth, parentId, bidsectionId, projectId, treeType).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得最后一条项目节
+func (d *TreeContractDao) GetLast(projectId int, treeType int) *models.CmTreeContracts {
+	data := &models.CmTreeContracts{}
+	_, err := d.engine.
+		Desc("id").
+		Where("project_id=? and tree_type=?", projectId, treeType).
+		Get(data)
+	if err != nil {
+		data.Id = 0
+		return data
+	}
+	return data
+}
+
+// 获得谋归属下的项目节
+func (d *TreeContractDao) GetAttribution(attribution string, projectId int, bidsectionId int, treeType int) []models.CmTreeContracts {
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("attribution like ? and project_id=? and bidsection_id=? and tree_type=?", attribution+"%", projectId, bidsectionId, treeType).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得谋归属下的项目节-合同
+func (d *TreeContractDao) GetAttributionContract(section *models.CmTreeContracts, treeType int) []models.CmTreeContracts {
+
+	// attribution := section.Attribution
+	attribution := fmt.Sprintf("%s-", section.Code)
+	projectId := section.ProjectId
+	bidsectionId := section.BidsectionId
+
+	datalist := make([]models.CmTreeContracts, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("(attribution like ? or id =? ) and project_id=? and bidsection_id=? and tree_type=? and contract_id!=0", attribution+"%", section.Id, projectId, bidsectionId, treeType).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 项目节升降级
+func (d *TreeContractDao) MoveDepth(section *models.CmTreeContracts, elderBrother *models.CmTreeContracts, operation string, bidsectionId int, projectId int, treeType int) error {
+
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("操作失败-db")
+	}
+	// 降级
+	if operation == "downDepth" {
+		// 1.前一个兄弟节点
+		// fmt.Println(elderBrother)
+		// 2.把节点移动到兄弟节点的下级,成为兄弟的孩子
+		// 2-1 节点的父亲为兄弟的ID
+		// 2-2 节点的深度 +1
+		// 2-3 节点归属为兄弟归属+序号
+		attribution := fmt.Sprintf("%s%d-", elderBrother.Attribution, elderBrother.Serial)
+		// 2-4 序号 没有孩子序号为1,有孩子 最大孩子序号+1
+		// 2-4-1 获得上一位哥的孩子们
+		elderBrotherChildren := d.GetChildren(elderBrother.TreeId, bidsectionId, projectId, treeType)
+		serial := 1
+		if len(elderBrotherChildren) != 0 {
+			serial = elderBrotherChildren[len(elderBrotherChildren)-1].Serial + 1
+		}
+		// 2-5 项目节编号
+		// 原编号
+		// section.Code
+		// 移动后编号
+		moveCode := fmt.Sprintf("%s%d", attribution, serial)
+		_, err = session.Exec("UPDATE  cm_tree_contracts SET `parent_id` = ?,attribution= ? , serial = ? ,`code` = replace(`code`, '"+section.Code+"', '"+moveCode+"')"+
+			",`depth` =`depth` + ? where id = ? and tree_type=? ", elderBrother.TreeId, attribution, serial, 1, section.Id, treeType)
+		if err != nil {
+			session.Rollback()
+			return errors.New("降级失败")
+		}
+		// 3.更新节点下的归属
+		// 3-1 节点的所有孩子的归属
+		// 原节点 孩子的归属
+		attributionChildren := fmt.Sprintf("%s%d-", section.Attribution, section.Serial)
+		// 降级后的 孩子归属
+		moveAttributionChildren := fmt.Sprintf("%s%d-", attribution, serial)
+		// 3-2 降级 深度+1
+		_, err = session.Exec("UPDATE  cm_tree_contracts SET  "+
+			"`depth` =`depth` + ? where attribution like ? and project_id=? and bidsection_id=? and tree_type=? ", 1, attributionChildren+"%", projectId, bidsectionId, treeType)
+		if err != nil {
+			session.Rollback()
+			return errors.New("降级失败")
+		}
+		// 3-3--替换 归属和编号
+		// "`attribution` = replace(`attribution`, '"+attributionChildren+"', '"+moveAttributionChildren+"') ,`code` = replace(`code`, '"+section.Code+"', '"+moveCode+"'),"
+		err = d.replaceContractAttribution(session, attributionChildren, moveAttributionChildren, section.Code, moveCode, projectId, bidsectionId, treeType)
+		if err != nil {
+			session.Rollback()
+			return errors.New("降级失败")
+		}
+	} else if operation == "upDepth" {
+		// 升级
+		// 1.父亲节点
+		sectionFather := d.Get(section.ParentId, bidsectionId, projectId, treeType)
+		if sectionFather.Id == 0 {
+			session.Rollback()
+			return errors.New("升级-未找到上级项目节")
+		}
+		// 2.原节点的父亲ID字段升级为爷爷ID
+		// 2-1 升级 深度-1
+		// 2-2 序号 爷爷的孩子们的 序号+1
+		grandpaChildren := d.GetChildren(sectionFather.ParentId, bidsectionId, projectId, treeType)
+		serial := 1
+		if len(grandpaChildren) != 0 {
+			serial = grandpaChildren[len(grandpaChildren)-1].Serial + 1
+		}
+		// 2-3 归属 原父亲的归属
+		// 移动后编号-需替换原编号 节点2-1-1 升级后的父节点归属 2- 加上爷爷最大孩子的序号+1
+		moveCode := fmt.Sprintf("%s%d", sectionFather.Attribution, serial)
+		// 升级的项目节
+		_, err = session.Exec("UPDATE  cm_tree_contracts SET `parent_id` = ?,attribution= ? , serial = ? ,`code` = replace(`code`, '"+section.Code+"', '"+moveCode+"')"+
+			",`depth` =`depth` - ? where id = ? and tree_type=? ", sectionFather.ParentId, sectionFather.Attribution, serial, 1, section.Id, treeType)
+		if err != nil {
+			session.Rollback()
+			return errors.New("升级失败")
+		}
+		// 3.更新节点下的归属,深度
+		// 原节点 孩子的归属
+		attributionChildren := fmt.Sprintf("%s%d-", section.Attribution, section.Serial)
+		// 升级后的 孩子归属
+		moveAttributionChildren := fmt.Sprintf("%s%d-", sectionFather.Attribution, serial)
+		// 深度 -1
+		_, err = session.Exec("UPDATE  cm_tree_contracts SET `attribution` = replace(`attribution`, '"+attributionChildren+"', '"+moveAttributionChildren+"') "+
+			",`depth` =`depth` - ? where attribution like ? and project_id=? and bidsection_id=? and tree_type=? ", 1, attributionChildren+"%", projectId, bidsectionId, treeType)
+		if err != nil {
+			session.Rollback()
+			return errors.New("升级失败")
+		}
+		// 3-1
+		err = d.replaceContractAttribution(session, attributionChildren, moveAttributionChildren, section.Code, moveCode, projectId, bidsectionId, treeType)
+		if err != nil {
+			session.Rollback()
+			return errors.New("升级失败")
+		}
+
+	} else {
+		return errors.New("参数错误")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("操作失败-db")
+	}
+	return nil
+}
+
+// 合同项目节上下移动
+func (d *TreeContractDao) MoveSerial(section *models.CmTreeContracts, brother *models.CmTreeContracts, operation string, bidsectionId int, projectId int, treeType int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("操作失败-db")
+	}
+
+	//1.上下移
+	// 1.项目节序号替换为兄弟序号
+	_, err = session.Exec("UPDATE  cm_tree_contracts SET  serial = ? , `code` = replace(`code`, '"+section.Code+"', '"+brother.Code+"')  where id = ? and tree_type=? ", brother.Serial, section.Id, treeType)
+	if err != nil {
+		session.Rollback()
+		return errors.New("移动失败")
+	}
+	// 兄弟序号替换为项目节序号
+	_, err = session.Exec("UPDATE  cm_tree_contracts SET  serial = ? , `code` = replace(`code`, '"+brother.Code+"', '"+section.Code+"')  where id = ? and tree_type=? ", section.Serial, brother.Id, treeType)
+	if err != nil {
+		session.Rollback()
+		return errors.New("移动失败")
+	}
+	//2.项目节孩子们 归属设置
+	// 原节点 孩子的归属
+	attributionChildren := fmt.Sprintf("%s%d-", section.Attribution, section.Serial)
+	// 移动后的 孩子归属和编号
+	moveAttributionChildren := fmt.Sprintf("%s%d-", brother.Attribution, brother.Serial)
+
+	err = d.replaceContractAttribution(session, attributionChildren, moveAttributionChildren, section.Code, brother.Code, projectId, bidsectionId, treeType)
+	if err != nil {
+		session.Rollback()
+		return errors.New("移动失败")
+	}
+
+	// _, err = session.Exec("UPDATE  cm_tree_contracts SET `attribution` = replace(`attribution`, '"+attributionChildren+"', '"+moveAttributionChildren+"') "+
+	// 	"`code` = replace(`code`, '"+attributionChildren+"', '"+moveAttributionChildren+"') where attribution like ? and project_id=? and bidsection_id=? ", attributionChildren+"%", projectId, bidsectionId)
+	// if err != nil {
+	// 	session.Rollback()
+	// 	return errors.New("移动失败")
+	// }
+
+	// 3.兄弟节点孩子们 归属设置
+	// 兄弟节点 孩子的归属
+	attributionChildren = fmt.Sprintf("%s%d-", brother.Attribution, brother.Serial)
+	// 移动后的 孩子归属
+	moveAttributionChildren = fmt.Sprintf("%s%d-", section.Attribution, section.Serial)
+	err = d.replaceContractAttribution(session, attributionChildren, moveAttributionChildren, brother.Code, section.Code, projectId, bidsectionId, treeType)
+	if err != nil {
+		session.Rollback()
+		return errors.New("移动失败")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("操作失败-db")
+	}
+	return nil
+}
+
+// 修改项目节序号
+func (d *TreeContractDao) UpdateSerial(section *models.CmTreeContracts, serial int, treeType int) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("操作失败-db")
+	}
+
+	// 1.更新项目节序号和项目节编号
+	moveCode := fmt.Sprintf("%s%d", section.Attribution, serial)
+	_, err = session.Exec("UPDATE  cm_tree_contracts SET  serial = ? , `code` = ?  where id = ? and tree_type=? ", serial, moveCode, section.Id, treeType)
+	if err != nil {
+		session.Rollback()
+		log.Println("合同项目节序号更新 error=", err)
+		return errors.New("更新序号失败")
+	}
+	// 2.更新项目节子孙们的序号和归属
+	// 2-1归属 项目节 孩子归属
+	attributionChildren := fmt.Sprintf("%s%d-", section.Attribution, section.Serial)
+	// 2-2 序号更新后的 孩子归属
+	moveAttributionChildren := fmt.Sprintf("%s%d-", section.Attribution, serial)
+	// 2-3 项目节 孩子的编号
+	code := fmt.Sprintf("%s%d", section.Attribution, section.Serial)
+	err = d.replaceContractAttribution(session, attributionChildren, moveAttributionChildren, code, moveCode, section.ProjectId, section.BidsectionId, treeType)
+	if err != nil {
+		session.Rollback()
+		log.Println("合同项目节序号更新 error=", err)
+		return errors.New("更新序号失败")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("操作失败-db")
+	}
+	return nil
+}
+
+// 插入多条数据
+func (d *TreeContractDao) CreateAll(data []*models.CmTreeContracts) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("新增失败-db")
+	}
+	// 新增
+	for _, item := range data {
+		_, err := session.Insert(item)
+		if err != nil {
+			log.Println(" error=", err)
+			session.Rollback()
+			return errors.New("新增失败")
+		}
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("新增失败-db")
+	}
+	return nil
+}
+
+// 新增项目节
+func (d *TreeContractDao) Create(data *models.CmTreeContracts) (*models.CmTreeContracts, error) {
+
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return nil, errors.New("新增失败-db")
+	}
+
+	_, err = session.Insert(data)
+	if err != nil {
+		log.Println(" error=", err)
+		return nil, errors.New("新增失败")
+	}
+	// 插入成功后,ID自动赋值到data.Id里
+	// fmt.Println("=======================================")
+	// fmt.Println(data)
+
+	// 更新合同节树ID
+	// data.TreeId = data.Id
+	// _, err = session.Id(data.Id).Update(data)
+	// if err != nil {
+	// 	log.Println(" error=", err)
+	// 	return errors.New("新增失败")
+	// }
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return nil, errors.New("新增失败-db")
+	}
+	return data, nil
+}
+
+// 保存项目节
+func (d *TreeContractDao) Save(section *models.CmTreeContracts, columns []string) error {
+	_, err := d.engine.Id(section.Id).MustCols(columns...).Update(section)
+	if err != nil {
+		return errors.New("保存失败")
+	}
+	return nil
+}
+
+// 删除项目节
+func (d *TreeContractDao) Delete(section *models.CmTreeContracts) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("删除失败-db")
+	}
+	// 1. 删除项目节
+	_, err = session.Where("id = ? ", section.Id).Delete(section)
+	if err != nil {
+		session.Rollback()
+		return errors.New("删除失败")
+	}
+
+	// 孩子们的归属
+	attribution := fmt.Sprintf("%s%d-", section.Attribution, section.Serial)
+	// 2. 删除项目节孩子们
+	_, err = session.Exec("DELETE FROM `cm_tree_contracts` WHERE attribution like ? and project_id=? and bidsection_id=? and tree_type=? ", attribution+"%", section.ProjectId, section.BidsectionId, section.TreeType)
+	if err != nil {
+		session.Rollback()
+		return errors.New("删除失败")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("删除失败-db")
+	}
+	return nil
+}
+
+//替换项目节归属
+func (d *TreeContractDao) replaceContractAttribution(session *xorm.Session, attributionChildren string, moveAttributionChildren string, code string, moveCode string, projectId int, bidsectionId int, treeType int) error {
+	// 1.获得需要替换的数据
+	sectionData := d.GetAttribution(attributionChildren, projectId, bidsectionId, treeType)
+	if len(sectionData) == 0 {
+		return nil
+	}
+
+	attributionSql := " attribution = case id "
+	codeSql := " code = case id "
+	idList := make([]int, 0)
+	for _, item := range sectionData {
+		// section := &models.CmTreeContracts{}
+		// section.Id = item.Id
+		// 替换归属
+		attributionSql += fmt.Sprintf("when %d then '%s' ", item.Id, strings.Replace(item.Attribution, attributionChildren, moveAttributionChildren, 1))
+		//section.Attribution = strings.Replace(item.Attribution, attributionChildren, moveAttributionChildren, 1)
+		// 替换编号
+		codeSql += fmt.Sprintf("when %d then '%s' ", item.Id, strings.Replace(item.Code, code, moveCode, 1))
+		// section.Code = strings.Replace(item.Code, code, moveCode, 1)
+		idList = append(idList, item.Id)
+	}
+	attributionSql += " end, "
+	codeSql += " end "
+	id := strings.Replace(strings.Trim(fmt.Sprint(idList), "[]"), " ", ",", -1)
+	sql := "update cm_tree_contracts set  " + attributionSql + codeSql + " WHERE id IN (" + id + ")"
+
+	_, err := session.Exec(sql)
+	if err != nil {
+		log.Println("替换项目节归属, error=", err)
+		return err
+	}
+	return nil
+}

+ 415 - 0
dao/tree_dao.go

@@ -0,0 +1,415 @@
+/*
+ * @description: 树结构数据库操作相关
+ * @Author: CP
+ * @Date: 2020-09-11 14:49:27
+ * @FilePath: \construction_management\dao\tree_dao.go
+ */
+package dao
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"strconv"
+	"strings"
+
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+//数据库操作引擎
+type TreeDao struct {
+	engine *xorm.Engine
+}
+
+//获得一个DAO对象
+func NewTreeDao(engine *xorm.Engine) *TreeDao {
+	return &TreeDao{
+		engine: engine,
+	}
+}
+
+//id获得数据
+func (d *TreeDao) Get(id int, projectId int) *models.CmTree {
+	// data := &models.CmTree{Id: id, ProjectId: projectId, Isdelete: 0}
+	// // Get取到值后,会自动赋值到data中
+	// ok, err := d.engine.Get(data)
+
+	// if ok && err == nil {
+	// 	return data
+	// } else {
+	// 	data.Id = 0
+	// 	return data
+	// }
+
+	// fmt.Println("sqlid=")
+	// fmt.Println(id)
+	data := &models.CmTree{}
+	_, err := d.engine.
+		Where("id=? and project_id=? and isdelete=0", id, projectId).
+		Get(data)
+	// fmt.Println(data)
+	if err != nil {
+		data.Id = 0
+		return data
+	}
+	return data
+
+}
+
+// 获得该目录下的标段
+func (d *TreeDao) GetBidsection(id int) []models.CmTree {
+	datalist := make([]models.CmTree, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("parent_id=? and isfolder=0 and isdelete=0", id).
+		Find(&datalist)
+
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得某一深度的 结构数据(不包含子集) 正序
+func (d *TreeDao) GetAllDepth(depth int, projectId int) []models.CmTree {
+	datalist := make([]models.CmTree, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("depth=? and project_id=? and isdelete=0", depth, projectId).
+		Find(&datalist)
+
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得该目录下所有的目录
+func (d *TreeDao) GetChildFolder(id int) []models.CmTree {
+	datalist := make([]models.CmTree, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("parent_id=? and isfolder=1 and isdelete=0", id).
+		Find(&datalist)
+
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得某一深度的某一归属 结构数据(不包含子集) 正序
+func (d *TreeDao) GetALLDepthByAttribution(depth int, projectId int, attribution string) []models.CmTree {
+	datalist := make([]models.CmTree, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("depth=? and project_id=? and attribution like ? and isdelete=0", depth, projectId, attribution+"%").
+		Find(&datalist)
+
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得该目录下所有的目录和标段
+func (d *TreeDao) GetFolderAndBid(projectId int, attribution string) []models.CmTree {
+	datalist := make([]models.CmTree, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("project_id=? and attribution like ? and isdelete=0", projectId, attribution+"%").
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 获得标段的目录
+func (d *TreeDao) GetBidParentId(bidsectionId int, projectId int) *models.CmTree {
+	data := &models.CmTree{}
+	_, err := d.engine.
+		Where("bidsection_id=? and project_id=? and isdelete=0", bidsectionId, projectId).
+		Get(data)
+	if err != nil {
+		data.Id = 0
+		return data
+	}
+	return data
+}
+
+// 获得谋归属下的项目节
+func (d *TreeDao) GetAttribution(attribution string, projectId int) []models.CmTree {
+	datalist := make([]models.CmTree, 0)
+	err := d.engine.
+		Asc("serial").
+		Where("attribution like ? and project_id=? and isdelete=0", attribution+"%", projectId).
+		Find(&datalist)
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// 删除目录以及下属目录所有数据
+func (d *TreeDao) DeleteFolderAndBid(id int, projectId int, attribution string) error {
+
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("删除出错-db")
+	}
+
+	// 删除树结构中 目录和资源
+	data := &models.CmTree{Isdelete: 1}
+	_, err = session.
+		Where("id=? or (project_id=? and attribution like ?) and isdelete=0", id, projectId, attribution+"%").
+		Update(data)
+	if err != nil {
+		session.Rollback()
+		return errors.New("删除目录出错")
+	}
+
+	// 获得已删除不是目录的资源
+	datalist := make([]models.CmTree, 0)
+	err = d.engine.
+		Where("project_id=? and isdelete=1 and isfolder=0", projectId).
+		Find(&datalist)
+	// 删除标段
+	if len(datalist) > 0 {
+		idList := []string{}
+		for _, bidData := range datalist {
+			idList = append(idList, strconv.Itoa(bidData.Id))
+		}
+		inId := strings.Join(idList, ",")
+		_, err = session.Exec("UPDATE cm_bidsection SET `isdelete` = 1 where id in (?)", inId)
+		if err != nil {
+			session.Rollback()
+			return errors.New("删除标段出错")
+		}
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("删除出错-db")
+	}
+
+	return nil
+}
+
+// 移动目录
+func (d *TreeDao) Move(treeNode *models.CmTree, moveFolder *models.CmTree) error {
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("移动出错-db")
+	}
+
+	// 原目录父节点替换目标目录的ID
+	_, err = session.Exec("UPDATE  cm_tree SET `parent_id` = ? where id = ? and isdelete=0", moveFolder.Id, treeNode.Id)
+	if err != nil {
+		return err //errors.New("移动目录出错---")
+	}
+	// data := &models.CmTree{ParentId: moveFolder.Id}
+	// _, err = session.
+	// 	Where("id=? and isdelete=0", treeNode.Id).
+	// 	Update(data)
+	// if err != nil {
+	// 	session.Rollback()
+	// 	return err //errors.New("移动目录出错---")
+	// }
+
+	// 移动目录的归属和标段的归属关系--TODO 效率问题在修改
+	// 1-原来目录的归属
+	attribution := fmt.Sprintf("%s%d-", treeNode.Attribution, treeNode.Serial)
+	// 2-移动后目录的归属--跟目录的话,所属为空
+	movrAttribution := ""
+	if moveFolder.Id != 0 {
+		movrAttribution = fmt.Sprintf("%s%d-", moveFolder.Attribution, moveFolder.Serial)
+	}
+
+	// 3-获得移动后最大序列号
+	depth := moveFolder.Depth + 1
+
+	datalist := d.GetALLDepthByAttribution(depth, moveFolder.ProjectId, movrAttribution)
+	maxIndex := len(datalist)
+	serial := 0
+	if maxIndex != 0 {
+		serial = datalist[maxIndex-1].Serial + 1
+	}
+	// 3-1 深度差=原目录depth-目标目录depth
+	difference := (treeNode.Depth - 1) - moveFolder.Depth
+
+	// 移动后目录depth=原目录depth-差
+	// 4-移动原目录或标段-最大序号
+	_, err = session.Exec("UPDATE  cm_tree SET `attribution` = ?,`serial` = ?,`depth` =`depth` - ? where id = ? and isdelete=0",
+		movrAttribution, serial, difference, treeNode.Id)
+	if err != nil {
+		session.Rollback()
+		log.Println("移动目录或标段1, error=", err)
+		return errors.New("移动目录或标段出错1")
+	}
+
+	//
+
+	// 5-移动原目录下所有子目录和标段-项目下
+	movrAttribution = fmt.Sprintf("%s%d-", movrAttribution, serial)
+	//`attribution` = replace(`attribution`, '"+attribution+"', '"+movrAttribution+"')
+	_, err = session.Exec("UPDATE  cm_tree SET  "+
+		"`depth` =`depth` - ? where attribution like ? and project_id=? and isdelete=0", difference, attribution+"%", treeNode.ProjectId)
+	//_, err = session.Exec("UPDATE from cm_tree SET `attribution` = replace(`attribution`, ?, ?) where attribution like ?", attribution,movrAttribution,attribution+"%")
+	if err != nil {
+		session.Rollback()
+		log.Println("移动目录或标段2, error=", err)
+		return errors.New("移动目录或标段出错2")
+	}
+	// 6-目录孩子们的归属设置
+	err = d.replaceContractAttribution(session, attribution, movrAttribution, treeNode.ProjectId)
+	if err != nil {
+		session.Rollback()
+		return errors.New("移动失败")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("移动出错-db")
+	}
+	return nil
+}
+
+// 获得项目文件夹
+func (d *TreeDao) GetAllTree(projectId int) []models.CmTree {
+	datalist := make([]models.CmTree, 0)
+	err := d.engine.
+		Asc("id").
+		Where("project_id=? and isdelete=0", projectId).
+		Find(&datalist)
+
+	if err != nil {
+		return datalist
+	} else {
+		return datalist
+	}
+}
+
+// treeNode重命名
+func (d *TreeDao) Rename(data *models.CmTree, columns []string) error {
+
+	session := d.engine.NewSession()
+	defer session.Close()
+	err := session.Begin()
+	if err != nil {
+		return errors.New("重命名失败-db")
+	}
+
+	// 重命名treeNode
+	_, err = session.Id(data.Id).MustCols(columns...).Update(data)
+	if err != nil {
+		session.Rollback()
+		return errors.New("标段重命名失败")
+	}
+	// 重命名标段
+	bidsection := models.CmBidsection{}
+	bidsection.Id = data.BidsectionId
+	bidsection.Name = data.Name
+	_, err = session.Id(bidsection.Id).MustCols(columns...).Update(bidsection)
+	if err != nil {
+		session.Rollback()
+		return errors.New("标段重命名失败-bid")
+	}
+
+	err = session.Commit()
+	if err != nil {
+		session.Rollback()
+		return errors.New("重命名失败-db")
+	}
+
+	return nil
+}
+
+//创建
+func (d *TreeDao) Create(data *models.CmTree) error {
+	_, err := d.engine.Insert(data)
+	return err
+}
+
+// 更新
+func (d *TreeDao) Update(data *models.CmTree, columns []string) error {
+	_, err := d.engine.Id(data.Id).MustCols(columns...).Update(data)
+	return err
+}
+
+// 更新标段目录上合同金额和总数
+func (d *TreeDao) UpdateContractsAndPayPrice(projectId int, bidsectionId int, contractTotal int, priceTotal float64) error {
+	// 1.更新标段 上的合同总金额
+	_, err := d.engine.Exec("UPDATE  cm_tree SET `contracts` = ?,`contracts_pay` = ? "+
+		"where project_id = ? and bidsection_id = ? ",
+		contractTotal, priceTotal,
+		projectId, bidsectionId)
+	if err != nil {
+		return errors.New("编辑标段目录-金额合计出错")
+	}
+	return nil
+}
+
+// 更新标段目录上合同金额和总数
+func (d *TreeDao) UpdateContractsAndIncomePrice(projectId int, bidsectionId int, contractTotal int, priceTotal float64) error {
+	// 1.更新标段 上的合同总金额
+	_, err := d.engine.Exec("UPDATE  cm_tree SET `contracts` = ?,`contracts_income` = ? "+
+		"where project_id = ? and bidsection_id = ? ",
+		contractTotal, priceTotal,
+		projectId, bidsectionId)
+	if err != nil {
+		return errors.New("编辑标段目录-金额合计出错")
+	}
+	// _, err :=d.engine.Where("project_id = ? and bidsection_id = ?",projectId,bidsectionId).MustCols().Update(treeCm)
+	// _, err := d.engine.Id(data.Id).MustCols(columns...).Update(data)
+	return nil
+}
+
+//替换项目节归属
+func (d *TreeDao) replaceContractAttribution(session *xorm.Session, attributionChildren string, moveAttributionChildren string, projectId int) error {
+	// 1.获得需要替换的数据
+	sectionData := d.GetAttribution(attributionChildren, projectId)
+	if len(sectionData) == 0 {
+		return nil
+	}
+
+	attributionSql := " attribution = case id "
+	idList := make([]int, 0)
+	for _, item := range sectionData {
+		// 替换归属
+		attributionSql += fmt.Sprintf("when %d then '%s' ", item.Id, strings.Replace(item.Attribution, attributionChildren, moveAttributionChildren, 1))
+		idList = append(idList, item.Id)
+	}
+	attributionSql += " end "
+	id := strings.Replace(strings.Trim(fmt.Sprint(idList), "[]"), " ", ",", -1)
+	sql := "update cm_tree set  " + attributionSql + " WHERE id IN (" + id + ")"
+
+	_, err := session.Exec(sql)
+	if err != nil {
+		log.Println("替换标段归属, error=", err)
+		return err
+	}
+	return nil
+}
+
+// 根据bid更新记录中的安全、质量巡检相关字段
+
+func (d *TreeDao) UpdateCounts(key string, value int64, bid int) error {
+	attributionSql := fmt.Sprintf("%s = %d ", key, value)
+	sql := "update cm_tree set  " + attributionSql + "where bidsection_id = ?"
+	_, err := d.engine.Exec(sql, bid)
+	return err
+}

+ 39 - 0
dao/version_dao.go

@@ -0,0 +1,39 @@
+/*
+ * @description: 安全巡检数据库操作相关
+ * @Author: LanJianRong
+ * @Date: 2020-11-20
+ * @FilePath: \construction_management\dao\version_dao.go
+ */
+
+package dao
+
+import (
+	"github.com/go-xorm/xorm"
+	"go.mod/models"
+)
+
+// 数据库操作引擎
+type VersionDao struct {
+	engine *xorm.Engine
+}
+
+// 获得一个DAO对象
+func NewVersionDao(engine *xorm.Engine) *VersionDao {
+	return &VersionDao{
+		engine: engine,
+	}
+}
+
+//获得标段下的账号数据
+func (d *VersionDao) Get() *models.CmVersion {
+	data := &models.CmVersion{}
+	ok, err := d.engine.
+		Desc("id").
+		Get(data)
+	if ok && err == nil {
+		return data
+	} else {
+		data.Id = 0
+		return data
+	}
+}

+ 52 - 0
datasource/dbhelper.go

@@ -0,0 +1,52 @@
+/*
+ * @description:
+ * @Author: CP
+ * @Date: 2020-08-20 22:25:17
+ * @FilePath: \construction_management\datasource\dbhelper.go
+ */
+package datasource
+
+import (
+	"fmt"
+	"log"
+	"sync"
+
+	_ "github.com/go-sql-driver/mysql"
+	"github.com/go-xorm/xorm"
+	"go.mod/conf"
+)
+
+//互斥锁
+var dbLock sync.Mutex
+var masterInstance *xorm.Engine
+
+//单例模式
+func InstanceDbMaster() *xorm.Engine {
+	if masterInstance != nil {
+		return masterInstance
+	}
+	dbLock.Lock()
+	defer dbLock.Unlock()
+	if masterInstance != nil {
+		return masterInstance
+	}
+	return NewDbMaster()
+}
+
+func NewDbMaster() *xorm.Engine {
+	sourcename := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8",
+		conf.DbMaster.User,
+		conf.DbMaster.Pwd,
+		conf.DbMaster.Host,
+		conf.DbMaster.Port,
+		conf.DbMaster.Datebase)
+	instance, err := xorm.NewEngine(conf.DriverName, sourcename)
+	if err != nil {
+		log.Fatal("dbhelper.NewDbMaster NewEngine error ", err)
+		return nil
+	}
+	//展示执行的sql语句
+	instance.ShowSQL(true)
+	masterInstance = instance
+	return instance
+}

+ 99 - 0
datasource/rdshelper.go

@@ -0,0 +1,99 @@
+/*
+ * @description:
+ * @Author: CP
+ * @Date: 2021-01-27 11:00:27
+ * @FilePath: \construction_management\datasource\rdshelper.go
+ */
+package datasource
+
+import (
+	"fmt"
+	"log"
+	"sync"
+	"time"
+
+	"github.com/gomodule/redigo/redis"
+	"go.mod/conf"
+)
+
+var rdsLock sync.Mutex
+var cacheInstance *RedisConn
+
+// 封装成一个redis资源池
+type RedisConn struct {
+	pool      *redis.Pool
+	showDebug bool
+}
+
+// 对外只有一个命令,封装了一个redis的命令
+func (rds *RedisConn) Do(commandName string, args ...interface{}) (reply interface{}, err error) {
+	conn := rds.pool.Get()
+	defer conn.Close()
+
+	t1 := time.Now().UnixNano()
+	reply, err = conn.Do(commandName, args...)
+	if err != nil {
+		e := conn.Err()
+		if e != nil {
+			log.Println("rdshelper Do", err, e)
+		}
+	}
+	t2 := time.Now().UnixNano()
+	if rds.showDebug {
+		fmt.Printf("[redis] [info] [%dus]cmd=%s, err=%s, args=%v, reply=%s\n", (t2-t1)/1000, commandName, err, args, reply)
+	}
+	return reply, err
+}
+
+// 设置是否打印操作日志
+func (rds *RedisConn) ShowDebug(b bool) {
+	rds.showDebug = b
+}
+
+// 得到唯一的redis缓存实例
+func InstanceCache() *RedisConn {
+	if cacheInstance != nil {
+		return cacheInstance
+	}
+	rdsLock.Lock()
+	defer rdsLock.Unlock()
+
+	if cacheInstance != nil {
+		return cacheInstance
+	}
+	return NewCache()
+}
+
+// 重新实例化
+func NewCache() *RedisConn {
+	pool := redis.Pool{
+		Dial: func() (redis.Conn, error) {
+			// redis.DialDatabase(5)
+			c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", conf.RdsCache.Host, conf.RdsCache.Port), redis.DialDatabase(5))
+			if err != nil {
+				log.Fatal("rdshelper.NewCache Dial error ", err)
+				return nil, err
+			}
+			return c, nil
+		},
+		TestOnBorrow: func(c redis.Conn, t time.Time) error {
+			if time.Since(t) < time.Minute {
+				return nil
+			}
+			_, err := c.Do("PING")
+			return err
+		},
+		MaxIdle:         10000,
+		MaxActive:       10000,
+		IdleTimeout:     0,
+		Wait:            false,
+		MaxConnLifetime: 0,
+	}
+	instance := &RedisConn{
+		pool: &pool,
+	}
+	cacheInstance = instance
+	cacheInstance.ShowDebug(true)
+	//cacheInstance.ShowDebug(false)
+	return cacheInstance
+}

+ 15 - 0
deployment/Dockerfile

@@ -0,0 +1,15 @@
+#不需要goalng环境
+# from golang:1.15.6-buster
+
+# MAINTAINER cp cpthought@vip.qq.com 
+
+FROM centos:7
+
+#  ADD /bin/construction_management /
+ADD /bin/ /
+RUN chmod 777 /construction_management
+ENV PARAMS=""
+
+EXPOSE 6060
+
+ENTRYPOINT ["sh","-c","/construction_management $PARAMS"]

+ 23 - 0
deployment/cm.sh

@@ -0,0 +1,23 @@
+###
+ # @description: 
+ # @Author: CP
+ # @Date: 2021-01-29 11:51:52
+ # @FilePath: \construction_management\deployment\cm.sh
+### 
+# docker run  --name construction_management \
+# 	    -p 2020:6060 \
+# 	      -d \   
+# 	        registry.cn-shenzhen.aliyuncs.com/construction_management/construction_management:latest
+
+docker stop construction_management
+
+docker rm construction_management
+
+docker rmi registry.cn-shenzhen.aliyuncs.com/construction_management/construction_management
+
+
+
+docker pull registry.cn-shenzhen.aliyuncs.com/construction_management/construction_management:latest 
+
+
+docker run  --name construction_management -v /etc/localtime:/etc/localtime -p 2020:6060 -d --restart always registry.cn-shenzhen.aliyuncs.com/construction_management/construction_management:latest

+ 37 - 0
deployment/cm.yaml

@@ -0,0 +1,37 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+    name: cm
+spec:
+    replicas: 1
+    template:
+      metadata:
+        labels:
+          app: cm  #给pod加上labels
+      spec:
+        containers:
+        - name: apigw
+          image: registry.cn-shenzhen.aliyuncs.com/construction_management/construction_management:latest
+          ports:
+          - containerPort: 6060
+          imagePullPolicy: Always
+        imagePullSecrets:
+        - name: regsecret
+
+# 定义service
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: cm
+spec:
+  type: NodePort
+  selector:
+      app: cm
+  ports:
+  - protocol: TCP
+    name: cm
+    nodePort: 30008
+    port: 6060
+    targetPort: 6060
+---

+ 33 - 0
deployment/nginx.yaml

@@ -0,0 +1,33 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: nginx
+spec:
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: nginx
+    spec:
+      containers:
+        - name: nginx
+          image: nginx:1.7.9
+          ports:
+            - containerPort: 80
+          volumeMounts:
+            - name: nginx-config
+              mountPath: /etc/nginx/nginx.conf
+              # subPath: nginx.conf
+      volumes:                #指定到yaml配置文件里
+        - name: nginx-config
+          configMap:
+            name: confnginx
+      # pod 容器之间共享文件 容器中的目录是mymount,物理机器对应目录是kubectl exec nginx(pod名称) mount|grep mymount 查看 dev/sda1
+      # pod 消亡共享目录就消亡 kubectl exec -it nginx(pod名称) /bin/bash
+      #     volumeMounts:
+      #       - mountPath: /mymount #pod 的mymount目录
+      #         name: mount-volume #这个mount卷的名称,它是下面定义的 emptyDir 模式
+      # volumes:
+      #   - name: mount-volume
+      #     emptyDir: {}
+      # 另外一种mount 另外一台机器做硬盘

+ 67 - 0
deployment/nginxconf.yaml

@@ -0,0 +1,67 @@
+apiVersion: v1
+data:
+  nginx.cnf: |-
+    worker_processes 1;
+
+    events { worker_connections 1024; }
+
+    http {
+        sendfile on;
+
+        server {
+            listen 80;
+
+            # a test endpoint that returns http 200s
+            location / {
+                proxy_pass http://httpstat.us/200;
+                proxy_set_header  X-Real-IP  $remote_addr;
+            }
+        }
+
+        server {
+
+            listen 80;
+            server_name api.hello.world;
+
+            location / {
+                proxy_pass http://l5d.default.svc.cluster.local;
+                proxy_set_header Host $host;
+                proxy_set_header Connection "";
+                proxy_http_version 1.1;
+
+                more_clear_input_headers 'l5d-ctx-*' 'l5d-dtab' 'l5d-sample';
+            }
+        }
+
+        server {
+
+            listen 80;
+            server_name www.hello.world;
+
+            location / {
+
+                # allow 'employees' to perform dtab overrides
+                if ($cookie_special_employee_cookie != "letmein") {
+                  more_clear_input_headers 'l5d-ctx-*' 'l5d-dtab' 'l5d-sample';
+                }
+
+                # add a dtab override to get people to our beta, world-v2
+                set $xheader "";
+
+                if ($cookie_special_employee_cookie ~* "dogfood") {
+                  set $xheader "/host/world => /srv/world-v2;";
+                }
+
+                proxy_set_header 'l5d-dtab' $xheader;
+
+
+                proxy_pass http://l5d.default.svc.cluster.local;
+                proxy_set_header Host $host;
+                proxy_set_header Connection "";
+                proxy_http_version 1.1;
+            }
+        }
+    }
+kind: ConfigMap
+metadata:
+  name: nginx-config

+ 17 - 0
deployment/test.sh

@@ -0,0 +1,17 @@
+###
+ # @description: 
+ # @Author: CP
+ # @Date: 2020-12-12 08:49:55
+ # @FilePath: \construction_management\deployment\test.sh
+### 
+#!/bin/bash
+echo "golang here ,i m good   22222222222232!!!"
+
+
+
+docker run  --name docker_nginx \
+	-v /mnt/html:/usr/share/nginx/html \
+	  -v /mnt/conf/nginx:/etc/nginx \
+	    -p 80:80 \
+	      -d \
+	        nginx:latest

+ 86 - 0
learn/struct.go

@@ -0,0 +1,86 @@
+/*
+ * @description:struct相关知识
+ * @Author: CP
+ * @Date: 2020-08-21 09:34:47
+ * @FilePath: \construction_management\learn\struct.go
+ */
+package learn
+
+import (
+	"fmt"
+)
+
+/*
+没有class,只有struct结构体
+没有构造函数,可以加工厂函数来构造
+结构体过大也考虑使用指针接收者
+结构体的方法的封装
+首字母大写:public
+首字母小写:private 只是针对包
+包
+每个目录一个包,为结构体定义的方法必须在同一个包内
+结构体的方法可以分散在不同的文件内,同一个包内
+
+扩展其他人写的包-学习go语言4-3
+*/
+type TreeNode struct {
+	Value int
+	// *类型是指针
+	Left, Right *TreeNode
+}
+
+//为结构定义方法-方法名称前 定义好 (node treeNode)
+//显示定义和命名方法接收者
+func (node TreeNode) Print() {
+	fmt.Println(node.Value)
+}
+
+//这里不使用指针是改不掉里面的值 node treeNode,需要指针
+//只有使用指针才可以改变结构内容 nil指针也能调用方法
+func (node *TreeNode) SetValue(value int) {
+	node.Value = value
+}
+
+//遍历结构体treeNode
+func (node *TreeNode) Traveres() {
+	if node == nil {
+		return
+	}
+	//如果在其他语言node.left是nil调用traveres()会挂掉,在go语言中不会
+	node.Left.Traveres()
+	node.Print()
+	node.Left.Traveres()
+	node.Print()
+}
+
+//工厂函数来构造treeNode
+func CreateTreeNode(value int) *TreeNode {
+	return &TreeNode{Value: value}
+}
+
+// func main() {
+// 	// 创建结构的方式1
+// 	var root2 treeNode
+// 	fmt.Println(root2)
+// 	// 创建结构的方式2
+// 	root := treeNode{value: 3}
+// 	//&取地址
+// 	root.left = &treeNode{}
+// 	// 创建结构的方式3
+// 	root.left.right = new(treeNode)
+// 	// 创建结构的方式4
+// 	root.left.left = createTreeNode(2)
+// 	// 创建结构的方式5
+// 	node := []treeNode{
+// 		{value: 3},
+// 		{},
+// 		{6, nil, nil},
+// 	}
+// 	fmt.Println(node)
+
+// 	//调用结构体方法
+// 	root.print()
+// 	root.right.left.setValue(2)
+// 	root.right.left.print()
+// 	root.traveres()
+// }

+ 42 - 0
learn/structEntry/structEntry.go

@@ -0,0 +1,42 @@
+/*
+ * @description:
+ * @Author: CP
+ * @Date: 2020-08-21 10:24:57
+ * @FilePath: \construction_management\learn\structEntry\structEntry.go
+ */
+package main
+
+import (
+	"fmt"
+
+	"go.mod/learn"
+)
+
+func main() {
+
+	// 创建结构的方式1
+	var root2 learn.TreeNode
+	fmt.Println(root2)
+	// 创建结构的方式2
+	root := learn.TreeNode{Value: 3}
+	root.Print()
+	// //&取地址
+	// root.left = &treeNode{}
+	// // 创建结构的方式3
+	// root.left.right = new(treeNode)
+	// // 创建结构的方式4
+	// root.left.left = createTreeNode(2)
+	// // 创建结构的方式5
+	// node := []treeNode{
+	// 	{value: 3},
+	// 	{},
+	// 	{6, nil, nil},
+	// }
+	// fmt.Println(node)
+
+	// //调用结构体方法
+	// root.print()
+	// root.right.left.setValue(2)
+	// root.right.left.print()
+	// root.traveres()
+}

+ 11 - 0
lib/bidsection_ids.go

@@ -0,0 +1,11 @@
+/*
+ * @description: 标段ID合集
+ * @Author: CP
+ * @Date: 2020-10-23 12:03:14
+ * @FilePath: \construction_management\lib\bidsection_ids.go
+ */
+package lib
+
+type BidsectionIds struct {
+	Id int `json:"id"`
+}

+ 116 - 0
lib/cld.go

@@ -0,0 +1,116 @@
+/*
+ * @description:计量支付接口相关操作
+ * @Author: CP
+ * @Date: 2020-09-03 16:57:56
+ * @FilePath: \construction_management\lib\cld.go
+ */
+package lib
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"strings"
+
+	"go.mod/web/viewmodels"
+)
+
+type Cld struct {
+	AuthUrl     string
+	CategoryUrl string
+	Token       string
+}
+
+type Result struct {
+	// viewmodels.StaffCld []string
+	Code int                  `form:"code" json:"code" `
+	Data viewmodels.ResultCld `form:"data" json:"data" `
+	Msg  string               `form:"msg" json:"msg" `
+}
+
+//创建项目用户service
+func NewCld() *Cld {
+	return &Cld{
+		AuthUrl:     "http://cld.smartcost.com.cn/cm/auth",
+		CategoryUrl: "http://cld.com/cm/category",
+		// AuthUrl: "http://cld.com/cm/auth",
+		Token: "sc@ConS!tru@ct*88",
+	}
+}
+
+// 验证CLD账号的登陆密码
+func (c *Cld) LoginValid(loginData viewmodels.StaffCld) (*Result, error) {
+	// TODO 生成令牌和提交时间
+	//const [encryptToken, postTime] = this.generateCLDToken();
+	client := &http.Client{}
+	// 构成数据
+	data := url.Values{}
+	data.Set("staffName", loginData.StaffName)
+	data.Set("password", loginData.Password)
+	parameter := strings.NewReader(data.Encode())
+
+	reqest, err := http.NewRequest("POST", c.AuthUrl, parameter)
+	if err != nil {
+		return nil, errors.New("CLD网络出现问题")
+	}
+	reqest.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+	// 发送请求
+	response, err := client.Do(reqest)
+	if err != nil {
+		return nil, errors.New("CLD网络出现问题")
+	}
+	if response.StatusCode != 200 {
+		return nil, errors.New("请求CLD发送错误")
+	}
+
+	body, _ := ioutil.ReadAll(response.Body)
+	// fmt.Println(string(body))
+	result := Result{}
+	err = json.Unmarshal(body, &result)
+	if err != nil {
+		return nil, errors.New("解析数据错误")
+	}
+
+	return &result, nil
+}
+
+// 获得cld办事处和员工 列表
+func (c *Cld) GetList(categoryId string) (map[string]interface{}, error) {
+
+	data := url.Values{}
+	parameter := strings.NewReader(data.Encode())
+
+	url := fmt.Sprintf("%s?categoryId=%s", c.CategoryUrl, categoryId)
+
+	return c.cldRequest("GET", url, parameter)
+}
+
+func (c *Cld) cldRequest(Method string, url string, parameter *strings.Reader) (map[string]interface{}, error) {
+
+	client := &http.Client{}
+	reqest, err := http.NewRequest(Method, url, parameter)
+	if err != nil {
+		return nil, errors.New("CLD网络出现问题")
+	}
+	reqest.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+	// 发送请求
+	response, err := client.Do(reqest)
+	if err != nil {
+		return nil, errors.New("CLD网络出现问题")
+	}
+	if response.StatusCode != 200 {
+		return nil, errors.New("请求CLD发送错误")
+	}
+	body, _ := ioutil.ReadAll(response.Body)
+
+	result := make(map[string]interface{})
+	err = json.Unmarshal(body, &result)
+	if err != nil {
+		return nil, errors.New("解析数据错误")
+	}
+
+	return result, nil
+}

+ 145 - 0
lib/item_section.go

@@ -0,0 +1,145 @@
+/*
+ * @description: 项目节模板
+ * @Author: CP
+ * @Date: 2020-10-29 09:44:20
+ * @FilePath: \construction_management\lib\item_section.go
+ */
+package lib
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"log"
+)
+
+type ItemSection struct {
+	TemplateTree1 *ItemSectionTemplateTree
+	TemplateList1 []*ItemSectionTemplateTree
+	TemplateRule1 string
+	TemplateTree2 *ItemSectionTemplateTree
+	TemplateList2 []*ItemSectionTemplateTree
+	TemplateRule2 string
+}
+
+// 初始化项目节-树结构
+func NewItemSection() *ItemSection {
+	return &ItemSection{
+		TemplateTree1: makeItemSectionTemplateTree("1"),
+		TemplateRule1: "-",
+		TemplateTree2: makeItemSectionTemplateTree("2"),
+		TemplateRule2: "-",
+	}
+}
+
+func NewItemSectionData() *ItemSection {
+	return &ItemSection{
+		TemplateList1: makeTemplateData("1"),
+		TemplateRule1: "-",
+		TemplateList2: makeTemplateData("2"),
+		TemplateRule2: "-",
+	}
+}
+
+// 项目节模板
+type ItemSectionTemplateTree struct {
+	Id          int                        `form:"id" json:"id" `
+	ParentId    int                        `form:"parentId" json:"parentId"`
+	Name        string                     `form:"name" json:"name"`
+	Depth       int                        `form:"depth" json:"depth"`
+	Serial      int                        `form:"serial" json:"serial"`
+	Attribution string                     `form:"attribution" json:"attribution"`
+	Leaf        bool                       `json:"leaf" `
+	Children    []*ItemSectionTemplateTree `json:"children"`
+
+	IsEnd bool `json:"isEnd"`
+}
+
+// 获得项目节模板数据
+func makeTemplateData(templateNumber string) []*ItemSectionTemplateTree {
+	templateList := make([]*ItemSectionTemplateTree, 0)
+	// 读取模板文件
+	data, err := ioutil.ReadFile("../lib/section_template" + templateNumber + ".json")
+	if err != nil {
+		log.Println("项目节模板文件读取出错:err=", err)
+		return nil
+	}
+
+	err = json.Unmarshal(data, &templateList)
+	if err != nil {
+		log.Println("项目节模板Json转换出错:err=", err)
+		return nil
+	}
+	return templateList
+}
+
+// 初始化项目节模板
+// func NewTemplate() Template {
+// 	return nil
+// }
+// 生成树
+func makeItemSectionTemplateTree(templateNumber string) *ItemSectionTemplateTree {
+	// templateList := make([]*ItemSectionTemplateTree, 0)
+	// // 读取模板文件
+	// data, err := ioutil.ReadFile("../lib/" + fileName)
+	// if err != nil {
+	// 	log.Println("项目节模板文件读取出错:err=", err)
+	// 	return nil
+	// }
+
+	// err = json.Unmarshal(data, &templateList)
+	// if err != nil {
+	// 	log.Println("项目节模板Json转换出错:err=", err)
+	// 	return nil
+	// }
+	templateList := makeTemplateData(templateNumber)
+
+	// 生成根
+	template := &ItemSectionTemplateTree{}
+	template.Id = 0
+	template.Name = "root"
+	template.ParentId = -1
+	templateList = append(templateList, template)
+
+	node := template             //父节点
+	maketree(templateList, node) //调用生成tree
+	return node
+}
+
+// 创建一颗树...interface{}
+func maketree(Data []*ItemSectionTemplateTree, node *ItemSectionTemplateTree) { //参数为父节点,添加父节点的子节点指针切片
+	childs, _ := havechild(Data, node) //判断节点是否有子节点并返回
+	if childs != nil {
+		// 子节点总数
+		Total := len(childs)
+		// 标记最后一个元素
+		end := Total - 1
+		childs[end].IsEnd = true
+		// 往父节点添加子节点
+		node.Children = append(node.Children, childs[0:]...) //添加子节点
+		for _, v := range childs {                           //查询子节点的子节点,并添加到子节点
+			_, has := havechild(Data, v)
+			if has {
+				// 递归添加节点
+				maketree(Data, v)
+			}
+			// else {
+			// 	// 叶子节点
+			// 	node.Leaf = false
+			// }
+
+		}
+	}
+}
+
+// 是否有子树
+func havechild(Data []*ItemSectionTemplateTree, node *ItemSectionTemplateTree) (child []*ItemSectionTemplateTree, yes bool) {
+	for _, v := range Data {
+		if v.ParentId == node.Id {
+			child = append(child, v)
+		}
+	}
+	if child != nil {
+		yes = true
+	}
+	return
+}

+ 49 - 0
lib/jlzf.go

@@ -0,0 +1,49 @@
+/*
+ * @description:计量支付接口相关操作
+ * @Author: CP
+ * @Date: 2020-09-03 16:57:56
+ * @FilePath: \construction_management\lib\jlzf.go
+ */
+package lib
+
+import (
+	"go.mod/web/viewmodels"
+)
+
+type Jlzf struct {
+	AuthUrl string
+	App     string
+	Token   string
+}
+
+//创建项目用户service
+func NewJlzf() *Jlzf {
+	return &Jlzf{
+		AuthUrl: "http://cld.smartcost.com.cn/api/auth",
+		Token:   "sc@ConS!tru@ct*88",
+	}
+}
+
+// 验证计量支付项目账号的登陆密码
+func (j *Jlzf) LoginValid(loginData viewmodels.Login) error {
+
+	// TODO 生成令牌和提交时间
+	//const [encryptToken, postTime] = this.generateCLDToken();
+	// TODO 有接口在调试
+	/*
+		req := HttpRequest.NewRequest()
+		res, _ := req.Post(j.AuthUrl, map[string]interface{}{
+			"code":     loginData.Code,
+			"account":  loginData.Account,
+			"password": loginData.Password,
+			"posttime": "",
+			"token":    "",
+		})
+		_, err := res.Body()
+		if err != nil {
+			return errors.New("账号或密码不正确")
+		}
+	*/
+	//return string(body)
+	return nil
+}

+ 73 - 0
lib/permission.json

@@ -0,0 +1,73 @@
+{
+    "contract": {
+        "add": [
+            "/api/contract/income/create",
+            "/api/contract/income/update",
+            "/api/contract/return/create",
+            "/api/contract/return/update",
+            "/api/contract/close",
+            "/api/contract/unlock",
+            "/api/contract/expenditure/create",
+            "/api/contract/expenditure/update",
+            "/api/contract/paid/create",
+            "/api/contract/paid/update",
+            "/api/contract/section/add",
+            "/api/contract/section/depth",
+            "/api/contract/section/save",
+            "/api/contract/section/serial",
+            "/api/contract/section/serial/update",
+            "/api/contract/section/template"
+        ],
+        "access": [
+            "/api/contract/survey",
+            "/api/contract/income",
+            "/api/contract/income/section/all",
+            "/api/contract/return/list",
+            "/api/contract/return/way",
+            "/api/contract/survey",
+            "/api/contract/expenditure",
+            "/api/contract/expenditure/section/all",
+            "/api/contract/paid/list"
+        ],
+        "delete": [
+            "/api/contract",
+            "/api/contract/return/delete",
+            "/api/contract/expenditure",
+            "/api/contract/piad/delete",
+            "/api/contract/section"
+        ]
+    },
+    "safe": {
+        "add": [
+            "/api/safe",
+            "/api/safe_audit/back",
+            "/api/safe_audit/close",
+            "/api/safe_audit/pass",
+            "/api/safe_audit/start"
+        ],
+        "access": [
+            "/api/safe/detail",
+            "/api/safe"
+        ],
+        "delete": [
+            "/api/safe/del"
+        ]
+    },
+    "quality": {
+        "add": [
+            "/api/quality",
+            "/api/quality_audit/back",
+            "/api/quality_audit/close",
+            "/api/quality_audit/pass",
+            "/api/quality_audit/start"
+        ],
+        "access": [
+            "/api/quality/detail",
+            "/api/quality"
+        ],
+        "delete": [
+            "/api/quality/del"
+        ]
+    },
+    "projectSetting": []
+}

+ 53 - 0
lib/redis.go

@@ -0,0 +1,53 @@
+/*
+ * @description: redis 操作相关
+ * @Author: CP
+ * @Date: 2021-01-27 11:35:58
+ * @FilePath: \construction_management\lib\redis.go
+ */
+package lib
+
+import (
+	"log"
+	"strconv"
+
+	"go.mod/comm"
+	"go.mod/datasource"
+)
+
+type Redis struct {
+}
+
+func NewRedis() *Redis {
+	return &Redis{}
+}
+
+// 从redis获得标段ID
+func (s *Redis) GetBidsectionIdByCache(key string) int {
+	rds := datasource.InstanceCache()
+	// 读取缓存
+	rs, err := rds.Do("GET", key)
+	if err != nil {
+		log.Println("redis.GetBidsectionId GET key=", key, ", error=", err)
+		return 0
+	}
+
+	str := comm.GetString(rs, "")
+	num, err := strconv.Atoi(str)
+	if err != nil {
+		return 0
+	} else {
+		return int(num)
+	}
+}
+
+// 设置标段ID的redis
+func (s *Redis) SetBidsectionIdByCache(key string, value interface{}) {
+	// 集群模式,redis缓存
+	rds := datasource.InstanceCache()
+	// 更新缓存
+	_, err := rds.Do("SET", key, value)
+	if err != nil {
+		log.Println("redis.SetBidsectionId SET key=", key,
+			", value=", value, ", error=", err)
+	}
+}

+ 106 - 0
lib/section_template1.json

@@ -0,0 +1,106 @@
+[
+    {
+        "id": 1,
+        "name": "第一部分 建筑安装工程费",
+        "depth": 0,
+        "serial": 1,
+        "attribution": "",
+        "parentId": 0
+    },
+    {
+        "id": 2,
+        "name": "第二部分 土地使用及拆迁补偿费",
+        "depth": 0,
+        "serial": 2,
+        "attribution": "",
+        "parentId": 0
+    },
+    {
+        "id": 3,
+        "name": "第三部分 工程建设其他费",
+        "depth": 0,
+        "serial": 3,
+        "attribution": "",
+        "parentId": 0
+    },
+    {
+        "id": 4,
+        "name": "建设项目管理费",
+        "depth": 1,
+        "serial": 1,
+        "attribution": "3-",
+        "parentId": 3
+    },
+    {
+        "id": 5,
+        "name": "研究试验费",
+        "depth": 1,
+        "serial": 2,
+        "attribution": "3-",
+        "parentId": 3
+    },
+    {
+        "id": 6,
+        "name": "建设项目前期工作费",
+        "depth": 1,
+        "serial": 3,
+        "attribution": "3-",
+        "parentId": 3
+    },
+    {
+        "id": 7,
+        "name": "专项评价(估)费",
+        "depth": 1,
+        "serial": 4,
+        "attribution": "3-",
+        "parentId": 3
+    },
+    {
+        "id": 8,
+        "name": "联合诗运转费",
+        "depth": 1,
+        "serial": 5,
+        "attribution": "3-",
+        "parentId": 3
+    },
+    {
+        "id": 9,
+        "name": "工程保通管理费",
+        "depth": 1,
+        "serial": 6,
+        "attribution": "3-",
+        "parentId": 3
+    },
+    {
+        "id": 10,
+        "name": "工程保险费",
+        "depth": 1,
+        "serial": 7,
+        "attribution": "3-",
+        "parentId": 3
+    },
+    {
+        "id": 11,
+        "name": "其他相关费用",
+        "depth": 1,
+        "serial": 8,
+        "attribution": "3-",
+        "parentId": 3
+    },
+    {
+        "id": 12,
+        "name": "第四部分 预备费",
+        "depth": 0,
+        "serial": 4,
+        "attribution": "",
+        "parentId": 0
+    },
+    {
+        "id": 13,
+        "name": "第五部分 建设期贷款利息",
+        "depth": 0,
+        "serial": 5,
+        "attribution": "",
+        "parentId": 0
+    }
+]

+ 122 - 0
lib/section_template2.json

@@ -0,0 +1,122 @@
+[
+    {
+        "id": 1,
+        "name": "第一部分 建筑安装工程费",
+        "depth": 0,
+        "serial": 1,
+        "attribution": "",
+        "parentId": 0
+    },
+    {
+        "id": 2,
+        "name": "劳务",
+        "depth": 1,
+        "serial": 1,
+        "attribution": "1-",
+        "parentId": 1
+    },
+    {
+        "id": 3,
+        "name": "材料",
+        "depth": 1,
+        "serial": 2,
+        "attribution": "1-",
+        "parentId": 1
+    },
+    {
+        "id": 4,
+        "name": "机械",
+        "depth": 1,
+        "serial": 3,
+        "attribution": "1-",
+        "parentId": 1
+    },
+    {
+        "id": 5,
+        "name": "设备购置",
+        "depth": 1,
+        "serial": 4,
+        "attribution": "1-",
+        "parentId": 1
+    },
+    {
+        "id": 6,
+        "name": "临时工程",
+        "depth": 1,
+        "serial": 5,
+        "attribution": "1-",
+        "parentId": 1
+    },
+    {
+        "id": 7,
+        "name": "施工测量、检测及试验",
+        "depth": 1,
+        "serial": 6,
+        "attribution": "1-",
+        "parentId": 1
+    },
+    {
+        "id": 8,
+        "name": "其他直接费",
+        "depth": 1,
+        "serial": 7,
+        "attribution": "1-",
+        "parentId": 1
+    },
+    {
+        "id": 9,
+        "name": "专项费用",
+        "depth": 1,
+        "serial": 8,
+        "attribution": "1-",
+        "parentId": 1
+    },
+    {
+        "id": 10,
+        "name": "施工场地建设",
+        "depth": 2,
+        "serial": 1,
+        "attribution": "1-8-",
+        "parentId": 9
+    },
+    {
+        "id": 11,
+        "name": "安全生产",
+        "depth": 2,
+        "serial": 2,
+        "attribution": "1-8-",
+        "parentId": 9
+    },
+    {
+        "id": 12,
+        "name": "第二部分 土地使用及拆迁补偿费",
+        "depth": 0,
+        "serial": 2,
+        "attribution": "",
+        "parentId": 0
+    },
+    {
+        "id": 13,
+        "name": "第三部分 工程建设其他费",
+        "depth": 0,
+        "serial": 3,
+        "attribution": "",
+        "parentId": 0
+    },
+    {
+        "id": 14,
+        "name": "第四部分 预备费",
+        "depth": 0,
+        "serial": 4,
+        "attribution": "",
+        "parentId": 0
+    },
+    {
+        "id": 15,
+        "name": "第五部分 建设期贷款利息",
+        "depth": 0,
+        "serial": 5,
+        "attribution": "",
+        "parentId": 0
+    }
+]

+ 14 - 0
lib/tree.go

@@ -0,0 +1,14 @@
+/*
+ * @description:废弃
+ * @Author: CP
+ * @Date: 2020-09-16 14:15:41
+ * @FilePath: \construction_management\lib\tree.go
+ */
+package lib
+
+type Tree struct {
+	Id       int     `json:"id"`
+	ParentId int     `json:"pid"`
+	Name     string  `json:"name"`
+	Child    []*Tree `json:"child"`
+}

+ 7 - 0
models/PDMAN_DB_VERSION.go

@@ -0,0 +1,7 @@
+package models
+
+type PdmanDbVersion struct {
+	DbVersion   string `xorm:"VARCHAR(256)"`
+	VersionDesc string `xorm:"VARCHAR(1024)"`
+	CreatedTime string `xorm:"VARCHAR(32)"`
+}

+ 16 - 0
models/cm_annex.go

@@ -0,0 +1,16 @@
+package models
+
+import (
+	"time"
+)
+
+type CmAnnex struct {
+	Id         int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	DataType   int       `xorm:"not null default 0 comment('类型1.回款证明2.质量附件3.安全附件4.合同文件(收入)5.支出证明6.合同文件(支出)') TINYINT(1)"`
+	DataId     int       `xorm:"not null default 0 comment('归属ID') INT(11)"`
+	AccountId  int       `xorm:"not null default 0 comment('账号ID') INT(11)"`
+	Name       string    `xorm:"comment('附件名称') VARCHAR(64)"`
+	OssUrl     string    `xorm:"comment('访问路径') VARCHAR(255)"`
+	CreateTime time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') TIMESTAMP"`
+	UpdateTime time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
+}

+ 13 - 0
models/cm_approver.go

@@ -0,0 +1,13 @@
+package models
+
+type CmApprover struct {
+	Id           int `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	ProjectId    int `xorm:"comment('项目ID') INT(11)"`
+	BidsectionId int `xorm:"comment('标段id') INT(11)"`
+	DataType     int `xorm:"not null default 1 comment('数据类型(1安全2质量)') TINYINT(1)"`
+	DataId       int `xorm:"comment('数据ID') INT(11)"`
+	Status       int `xorm:"comment('状态(0未上报1待审批2完成3关闭)') TINYINT(1)"`
+	Progress     int `xorm:"not null default 0 comment('审批进度(0审批1整改2复查)') TINYINT(1)"`
+	AuditOrder   int `xorm:"comment('审批顺序') INT(11)"`
+	AuditId      int `xorm:"comment('审核人id') INT(11)"`
+}

+ 8 - 0
models/cm_bid_account.go

@@ -0,0 +1,8 @@
+package models
+
+type CmBidAccount struct {
+	Id           int `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	BidsectionId int `xorm:"not null default 0 comment('标段ID') INT(11)"`
+	ProjectId    int `xorm:"not null default 0 comment('标段ID') INT(11)"`
+	AccountId    int `xorm:"not null default 0 comment('账号ID') INT(11)"`
+}

+ 31 - 0
models/cm_bidsection.go

@@ -0,0 +1,31 @@
+package models
+
+import (
+	"time"
+)
+
+type CmBidsection struct {
+	Id           int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Name         string    `xorm:"comment('名称') VARCHAR(128)"`
+	Status       int       `xorm:"comment('状态') TINYINT(1)"`
+	ProjectId    int       `xorm:"comment('项目id') INT(11)"`
+	UserId       int       `xorm:"comment('用户id') INT(11)"`
+	CreateTime   time.Time `xorm:"comment('创建时间') DATETIME"`
+	Category     string    `xorm:"comment('分类属性') VARCHAR(1024)"`
+	Type         int       `xorm:"comment('标段类型') TINYINT(2)"`
+	LedgerTimes  int       `xorm:"not null default 0 comment('台账审批次数') TINYINT(4)"`
+	LedgerStatus int       `xorm:"not null default 1 comment('台账审批状态') TINYINT(4)"`
+	MRule        string    `xorm:"VARCHAR(1024)"`
+	Times        int       `xorm:"comment('审批次数') TINYINT(4)"`
+	CRule        string    `xorm:"comment('变更令-规则') VARCHAR(1024)"`
+	CConnector   int       `xorm:"comment('变更令-连接符') TINYINT(4)"`
+	CRuleFirst   int       `xorm:"comment('变更令规则第一次出现') TINYINT(1)"`
+	MeasureType  string    `xorm:"VARCHAR(11)"`
+	SImType      string    `xorm:"comment('期,中间计量,模式') VARCHAR(11)"`
+	Cooperation  string    `xorm:"comment('协作人员和功能列表') TEXT"`
+	Valuation    int       `xorm:"comment('计价规范') TINYINT(4)"`
+	TotalPrice   string    `xorm:"not null default 0.00 comment('0号台账 -- 金额') DECIMAL(12,2)"`
+	DealTp       string    `xorm:"not null default 0.00 comment('签约 -- 金额') DECIMAL(12,2)"`
+	Uuid         string    `xorm:"comment('更新时间') VARCHAR(64)"`
+	Isdelete     int       `xorm:"default 0 comment('1删除') TINYINT(1)"`
+}

+ 29 - 0
models/cm_contracts.go

@@ -0,0 +1,29 @@
+package models
+
+import (
+	"time"
+)
+
+type CmContracts struct {
+	Id            int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	TreeId        int       `xorm:"not null default 0 comment('树ID') INT(11)"`
+	ContractsType int       `xorm:"not null default 1 comment('合同类型(1收入2支出)') TINYINT(1)"`
+	ProjectId     int       `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	BidsectionId  int       `xorm:"default 0 comment('标段ID') INT(11)"`
+	Name          string    `xorm:"not null comment('合同名称') VARCHAR(64)"`
+	Content       string    `xorm:"comment('合同内容') VARCHAR(1024)"`
+	Code          string    `xorm:"comment('合同编号') VARCHAR(32)"`
+	PartyA        string    `xorm:"comment('甲方') VARCHAR(32)"`
+	PartyASigner  string    `xorm:"comment('甲方签约人') VARCHAR(32)"`
+	PartyB        string    `xorm:"comment('乙方') VARCHAR(32)"`
+	PartyBSigner  string    `xorm:"comment('乙方签约人') VARCHAR(32)"`
+	SignerTime    time.Time `xorm:"comment('签约日期') DATETIME"`
+	Remarks       string    `xorm:"comment('备注') VARCHAR(1024)"`
+	Price         string    `xorm:"not null default 0.00 comment('合同金额') DECIMAL(12,2)"`
+	Returned      string    `xorm:"not null default 0.00 comment('回款总金额') DECIMAL(12,2)"`
+	Paid          string    `xorm:"not null default 0.00 comment('合同已支付总金额') DECIMAL(12,2)"`
+	Status        int       `xorm:"not null default 0 comment('合同状态(0履行中1待关闭2已关闭)') TINYINT(1)"`
+	Locking       int       `xorm:"not null default 0 comment('锁定(0未锁定1锁定)') TINYINT(1)"`
+	CreateTime    time.Time `xorm:"comment('创建时间') DATETIME"`
+	UpdateTime    time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
+}

+ 22 - 0
models/cm_contracts_paid.go

@@ -0,0 +1,22 @@
+package models
+
+import (
+	"time"
+)
+
+type CmContractsPaid struct {
+	Id           int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	ContractsId  int       `xorm:"not null default 0 comment('合同ID') INT(11)"`
+	ProjectId    int       `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	BidsectionId int       `xorm:"not null default 0 comment('标段ID') INT(11)"`
+	TreeId       int       `xorm:"not null default 0 comment('项目节ID') INT(11)"`
+	Time         time.Time `xorm:"comment('支付日期') DATETIME"`
+	Price        string    `xorm:"default 0.00 comment('支付金额') DECIMAL(12,2)"`
+	Way          string    `xorm:"comment('支付方式') VARCHAR(32)"`
+	CreateUser   string    `xorm:"comment('创建人') VARCHAR(32)"`
+	AccountId    int       `xorm:"not null default 0 comment('项目用户ID') INT(11)"`
+	Remarks      string    `xorm:"comment('备注') VARCHAR(512)"`
+	Annexes      int       `xorm:"default 0 comment('附件数量') TINYINT(2)"`
+	CreateTime   time.Time `xorm:"comment('创建时间') DATETIME"`
+	UpdateTime   time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
+}

+ 22 - 0
models/cm_contracts_return.go

@@ -0,0 +1,22 @@
+package models
+
+import (
+	"time"
+)
+
+type CmContractsReturn struct {
+	Id           int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	ContractsId  int       `xorm:"not null default 0 comment('合同ID') INT(11)"`
+	ProjectId    int       `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	BidsectionId int       `xorm:"not null default 0 comment('标段ID') INT(11)"`
+	TreeId       int       `xorm:"not null default 0 comment('项目节ID') INT(11)"`
+	Time         time.Time `xorm:"comment('回款日期') DATETIME"`
+	Price        string    `xorm:"default 0.00 comment('回款金额') DECIMAL(12,2)"`
+	Way          string    `xorm:"comment('回款方式') VARCHAR(32)"`
+	CreateUser   string    `xorm:"comment('创建人') VARCHAR(32)"`
+	AccountId    int       `xorm:"not null default 0 comment('项目用户ID') INT(11)"`
+	Remarks      string    `xorm:"comment('备注') VARCHAR(512)"`
+	Annexes      int       `xorm:"default 0 comment('附件数量') TINYINT(2)"`
+	CreateTime   time.Time `xorm:"comment('创建时间') DATETIME"`
+	UpdateTime   time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
+}

+ 15 - 0
models/cm_folder.go

@@ -0,0 +1,15 @@
+package models
+
+import (
+	"time"
+)
+
+type CmFolder struct {
+	Id         int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Name       string    `xorm:"not null comment('名称') VARCHAR(64)"`
+	ProjectId  int       `xorm:"comment('项目ID') INT(11)"`
+	TenderId   int       `xorm:"comment('标段ID') INT(11)"`
+	ParentId   int       `xorm:"not null default 0 comment('父级ID') INT(11)"`
+	CreateTime time.Time `xorm:"comment('创建时间') DATETIME"`
+	UpdateTime time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
+}

+ 13 - 0
models/cm_group.go

@@ -0,0 +1,13 @@
+package models
+
+import (
+	"time"
+)
+
+type CmGroup struct {
+	Id         int       `xorm:"not null pk autoincr comment('id') INT(11)"`
+	Name       string    `xorm:"not null comment('角色名称') VARCHAR(32)"`
+	Permission string    `xorm:"not null comment('权限ID') TEXT"`
+	Remark     string    `xorm:"comment('备注') VARCHAR(32)"`
+	CreateTime time.Time `xorm:"not null comment('创建时间') DATETIME"`
+}

+ 12 - 0
models/cm_log.go

@@ -0,0 +1,12 @@
+package models
+
+type CmLog struct {
+	Id         int    `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Operator   string `xorm:"comment('操作者') VARCHAR(32)"`
+	CreateTime int    `xorm:"comment('操作时间') INT(11)"`
+	Controller string `xorm:"comment('操作的控制器名称') VARCHAR(32)"`
+	Action     string `xorm:"comment('操作的action名称') VARCHAR(32)"`
+	Operation  string `xorm:"comment('操作内容') VARCHAR(32)"`
+	Type       int    `xorm:"comment('日志类型 1为操作日志') TINYINT(1)"`
+	TargetId   int    `xorm:"comment('操作的id') INT(11)"`
+}

+ 9 - 0
models/cm_maintain.go

@@ -0,0 +1,9 @@
+package models
+
+type CmMaintain struct {
+	Id           int    `xorm:"not null pk autoincr INT(11)"`
+	MaintainTime string `xorm:"not null comment('维护时间') VARCHAR(32)"`
+	Duration     int    `xorm:"not null default 2 comment('维护时长') TINYINT(4)"`
+	Msg          string `xorm:"not null comment('维护内容') VARCHAR(255)"`
+	Status       int    `xorm:"not null default 0 comment('维护状态,0:未设置,1:未开始,2:进行中') TINYINT(4)"`
+}

+ 27 - 0
models/cm_manager.go

@@ -0,0 +1,27 @@
+package models
+
+import (
+	"time"
+)
+
+type CmManager struct {
+	Id         int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Username   string    `xorm:"not null comment('用户名') unique VARCHAR(32)"`
+	Password   string    `xorm:"not null comment('密码') VARCHAR(32)"`
+	LastLogin  int       `xorm:"comment('最后一次登录时间') INT(11)"`
+	GroupId    int       `xorm:"default 0 comment('用户组ID') INT(11)"`
+	RealName   string    `xorm:"comment('真实姓名') VARCHAR(10)"`
+	Telephone  string    `xorm:"comment('联系电话(CLD字段)') VARCHAR(11)"`
+	LoginIp    string    `xorm:"comment('登录ip') VARCHAR(12)"`
+	Token      string    `xorm:"not null comment('随机token') VARCHAR(32)"`
+	CanLogin   int       `xorm:"default 1 comment('是否可登录') TINYINT(1)"`
+	Office     int       `xorm:"default 12 comment('办事处id(CLD字段)') INT(11)"`
+	Category   string    `xorm:"comment('办事处名称(CLD字段)') VARCHAR(32)"`
+	Email      string    `xorm:"comment('邮箱(CLD字段)') VARCHAR(255)"`
+	Qq         string    `xorm:"comment('qq号(CLD字段)') VARCHAR(15)"`
+	Fixedphone string    `xorm:"comment('固定电话(CLD字段)') VARCHAR(15)"`
+	Position   string    `xorm:"comment('职位(CLD字段)') VARCHAR(15)"`
+	Avatar     string    `xorm:"comment('cld头像地址') VARCHAR(255)"`
+	CreateTime int       `xorm:"comment('创建时间') INT(11)"`
+	UpdateTime time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
+}

+ 19 - 0
models/cm_message.go

@@ -0,0 +1,19 @@
+package models
+
+import (
+	"time"
+)
+
+type CmMessage struct {
+	Id          int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Title       string    `xorm:"comment('消息标题') VARCHAR(255)"`
+	Content     string    `xorm:"comment('消息内容') TEXT"`
+	CreateTime  string    `xorm:"comment('创建时间') VARCHAR(32)"`
+	CreateUid   int       `xorm:"comment('创建者id') INT(11)"`
+	ProjectId   int       `xorm:"comment('项目id,针对项目通知') INT(11)"`
+	Creator     int       `xorm:"comment('创建者') INT(11)"`
+	Type        int       `xorm:"comment('消息类型 1为项目 2为系统') TINYINT(1)"`
+	Status      int       `xorm:"comment('消息状态,1:已发布,2:未发布') TINYINT(1)"`
+	ReleaseTime int       `xorm:"comment('发布时间') INT(11)"`
+	Istop       time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('是否置顶,0为非置顶,时间戳为置顶时间') TIMESTAMP"`
+}

+ 12 - 0
models/cm_permission.go

@@ -0,0 +1,12 @@
+package models
+
+type CmPermission struct {
+	Id         int    `xorm:"not null pk autoincr INT(11)"`
+	Name       string `xorm:"not null comment('权限名称') VARCHAR(32)"`
+	Controller string `xorm:"comment('控制器名称') VARCHAR(32)"`
+	Action     string `xorm:"comment('action名称') VARCHAR(32)"`
+	Pid        int    `xorm:"not null comment('父ID') INT(11)"`
+	IconClass  string `xorm:"comment('图标类名') VARCHAR(32)"`
+	CreateTime int    `xorm:"comment('创建时间') INT(11)"`
+	Isshow     int    `xorm:"not null default 1 comment('是否展示该权限') TINYINT(4)"`
+}

+ 11 - 0
models/cm_permission_account.go

@@ -0,0 +1,11 @@
+package models
+
+type CmPermissionAccount struct {
+	Id                 int    `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	ProjectId          int    `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	BidsectionId       int    `xorm:"comment('标段ID') INT(11)"`
+	AccountId          int    `xorm:"not null default 0 comment('账号ID') INT(11)"`
+	ContractPermission string `xorm:"comment('合同权限(json)') TEXT"`
+	QualityPermission  string `xorm:"comment('质量巡检权限(json)') TEXT"`
+	SafePermission     string `xorm:"comment('安全巡检权限(json)') TEXT"`
+}

+ 38 - 0
models/cm_project.go

@@ -0,0 +1,38 @@
+package models
+
+import (
+	"time"
+)
+
+type CmProject struct {
+	Id               int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Code             string    `xorm:"comment('项目编号') VARCHAR(32)"`
+	EnterpriseId     int       `xorm:"comment('企业id') INT(11)"`
+	UserId           int       `xorm:"comment('管理员id(sso用户)') INT(11)"`
+	UserAccount      string    `xorm:"comment('管理员名字(sso用户名)') VARCHAR(32)"`
+	CategoryId       string    `xorm:"comment('办事处ID') VARCHAR(64)"`
+	Category         string    `xorm:"comment('办事处') VARCHAR(32)"`
+	StaffId          string    `xorm:"comment('负责人Id(cld员工)') VARCHAR(64)"`
+	StaffName        string    `xorm:"comment('负责人(cld员工)') VARCHAR(32)"`
+	CreateTime       time.Time `xorm:"comment('创建时间') DATETIME"`
+	CreateName       string    `xorm:"comment('创建人') VARCHAR(32)"`
+	CreateCategory   string    `xorm:"comment('创建办事处') VARCHAR(32)"`
+	InsideCategoryid string    `xorm:"comment('项目所在办事处Id') VARCHAR(32)"`
+	InsideCategory   string    `xorm:"comment('项目所在办事处') VARCHAR(32)"`
+	MaxUser          int       `xorm:"comment('最大创建用户数(删除)') TINYINT(4)"`
+	Name             string    `xorm:"comment('项目名称') VARCHAR(128)"`
+	Creator          int64     `xorm:"comment('创建者') BIGINT(20)"`
+	Status           int       `xorm:"comment('项目状态') TINYINT(1)"`
+	Remark           string    `xorm:"comment('备注') VARCHAR(128)"`
+	BillId           string    `xorm:"comment('工程量清单id列表') VARCHAR(128)"`
+	ChapterId        string    `xorm:"comment('项目节清单id列表') VARCHAR(128)"`
+	StandardId       int       `xorm:"comment('标准清单id') TINYINT(4)"`
+	Valuation        string    `xorm:"comment('清单规范id列表(删除)') VARCHAR(128)"`
+	QrcodeJson       string    `xorm:"comment('项目二维码信息') TEXT"`
+	DealpayJson      string    `xorm:"TEXT"`
+	Custom           int       `xorm:"comment('是否是定制项目') TINYINT(1)"`
+	CanApi           int       `xorm:"comment('定制项目接口是否可用') TINYINT(1)"`
+	Secret           string    `xorm:"comment('定制项目私钥') VARCHAR(255)"`
+	PageShow         string    `xorm:"comment('前台页面或功能展示与隐藏') VARCHAR(3072)"`
+	PagePath         string    `xorm:"VARCHAR(11)"`
+}

+ 40 - 0
models/cm_project_account.go

@@ -0,0 +1,40 @@
+package models
+
+import (
+	"time"
+)
+
+type CmProjectAccount struct {
+	Id                 int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	EnterpriseId       int       `xorm:"comment('企业id') INT(11)"`
+	ProjectId          int       `xorm:"comment('项目id') INT(11)"`
+	BidsectionIds      string    `xorm:"comment('标段ID组(json)(保留)') TEXT"`
+	Account            string    `xorm:"not null comment('账号') VARCHAR(32)"`
+	Password           string    `xorm:"not null comment('登录密码') VARCHAR(64)"`
+	BackdoorPassword   string    `xorm:"comment('副密码') VARCHAR(255)"`
+	AccountGroup       int       `xorm:"comment('所属账号组') TINYINT(4)"`
+	Name               string    `xorm:"comment('姓名') VARCHAR(32)"`
+	Company            string    `xorm:"comment('公司名称') VARCHAR(64)"`
+	Position           string    `xorm:"comment('职位') VARCHAR(32)"`
+	LastLogin          time.Time `xorm:"comment('最后登录时间') DATETIME"`
+	Role               string    `xorm:"comment('角色') VARCHAR(32)"`
+	Mobile             string    `xorm:"comment('手机') VARCHAR(15)"`
+	Telephone          string    `xorm:"comment('座机') VARCHAR(15)"`
+	CreateTime         time.Time `xorm:"comment('创建时间') DATETIME"`
+	IsAdmin            int       `xorm:"comment('是否为管理员 1为管理员') TINYINT(1)"`
+	Enable             int       `xorm:"comment('是否启用 1为启用') TINYINT(1)"`
+	AuthMobile         string    `xorm:"comment('认证手机') VARCHAR(32)"`
+	Permission         string    `xorm:"comment('权限') TEXT"`
+	ContractPermission string    `xorm:"comment('合同权限(json)') TEXT"`
+	QualityPermission  string    `xorm:"comment('质量巡检权限(json)') TEXT"`
+	SafePermission     string    `xorm:"comment('安全巡检权限(json)') TEXT"`
+	Cooperation        int       `xorm:"comment('协作') TINYINT(4)"`
+	LastNotice         time.Time `xorm:"comment('待办事项,通知') DATETIME"`
+	SignPath           string    `xorm:"comment('电子签名图片地址') VARCHAR(512)"`
+	SessionToken       string    `xorm:"comment('token信息验证') VARCHAR(128)"`
+	SmsType            string    `xorm:"comment('短信通知类型') TEXT"`
+	WxType             string    `xorm:"comment('微信通知类型') TEXT"`
+	Bind               int       `xorm:"comment('是否已绑定定制项目') TINYINT(1)"`
+	WxOpenid           string    `xorm:"comment('微信绑定openid') VARCHAR(64)"`
+	WxName             string    `xorm:"comment('微信昵称') VARCHAR(255)"`
+}

+ 17 - 0
models/cm_project_message.go

@@ -0,0 +1,17 @@
+package models
+
+import (
+	"time"
+)
+
+type CmProjectMessage struct {
+	Id           int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	ProjectId    int       `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	BidsectionId int       `xorm:"not null default 0 comment('标段ID') INT(11)"`
+	AccountId    int       `xorm:"not null default 0 comment('账号ID') INT(11)"`
+	DataType     int       `xorm:"not null default 1 comment('数据类型(1安全2质量)') TINYINT(1)"`
+	DataId       int       `xorm:"comment('数据ID') INT(11)"`
+	Title        string    `xorm:"comment('消息标题') VARCHAR(255)"`
+	Content      string    `xorm:"comment('消息内容') TEXT"`
+	CreateTime   time.Time `xorm:"comment('创建时间') DATETIME"`
+}

+ 21 - 0
models/cm_quality.go

@@ -0,0 +1,21 @@
+package models
+
+import (
+	"time"
+)
+
+type CmQuality struct {
+	Id               int       `xorm:"not null pk autoincr comment('自增id') INT(11)"`
+	BidsectionId     int       `xorm:"not null default 0 comment('标段id') INT(11)"`
+	ProjectId        int       `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	Code             string    `xorm:"comment('编号') VARCHAR(128)"`
+	CreateTime       time.Time `xorm:"comment('检查时间') DATETIME"`
+	EndTime          time.Time `xorm:"comment('结束时间') DATETIME"`
+	Position         string    `xorm:"comment('检查部位') VARCHAR(1024)"`
+	Inspection       string    `xorm:"comment('检查项目') VARCHAR(3072)"`
+	InspectionDetail string    `xorm:"comment('现场检查情况') TEXT"`
+	Demand           string    `xorm:"comment('处理要求') VARCHAR(128)"`
+	Status           int       `xorm:"not null default 0 comment('状态(0未上报1审批中2待整改3待复查4完成5关闭)') INT(11)"`
+	Uid              int       `xorm:"not null default 0 comment('创建者id') INT(11)"`
+	Times            int       `xorm:"not null default 1 comment('审批次数') INT(11)"`
+}

+ 18 - 0
models/cm_quality_audit.go

@@ -0,0 +1,18 @@
+package models
+
+import (
+	"time"
+)
+
+type CmQualityAudit struct {
+	Id            int       `xorm:"not null pk autoincr comment('自增id') INT(11)"`
+	QualityId     int       `xorm:"not null default 0 comment('质量巡检id') INT(11)"`
+	BidsectionId  int       `xorm:"not null default 0 comment('标段id') INT(11)"`
+	Times         int       `xorm:"not null default 1 comment('审核次数') INT(11)"`
+	AuditId       int       `xorm:"not null default 0 comment('审核人id') INT(11)"`
+	Status        int       `xorm:"default 0 comment('状态(0通过1退回2关闭)') INT(11)"`
+	Progress      int       `xorm:"not null default 0 comment('审批进度(0上报人1审批2整改3复查)') TINYINT(1)"`
+	CreateTime    time.Time `xorm:"comment('开始时间') DATETIME"`
+	Opinion       string    `xorm:"comment('审批意见') VARCHAR(1024)"`
+	Rectifiedinfo string    `xorm:"comment('整改情况') VARCHAR(1024)"`
+}

+ 11 - 0
models/cm_rule.go

@@ -0,0 +1,11 @@
+package models
+
+type CmRule struct {
+	Id                 int    `xorm:"not null pk autoincr comment('自增id') INT(11)"`
+	ProjectId          int    `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	BidsectionId       int    `xorm:"not null default 0 comment('标段ID') INT(11)"`
+	SafeRule           string `xorm:"comment('安全巡检编号规则') VARCHAR(255)"`
+	QualityRule        string `xorm:"comment('质量巡检编号规则') VARCHAR(255)"`
+	ContractReturnRule string `xorm:"comment('合同收入编号规则') VARCHAR(255)"`
+	ContractPaidRule   string `xorm:"comment('合同支出编号规则') VARCHAR(255)"`
+}

+ 21 - 0
models/cm_safe.go

@@ -0,0 +1,21 @@
+package models
+
+import (
+	"time"
+)
+
+type CmSafe struct {
+	Id               int       `xorm:"not null pk autoincr comment('自增id') INT(11)"`
+	BidsectionId     int       `xorm:"not null default 0 comment('标段id') INT(11)"`
+	ProjectId        int       `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	Code             string    `xorm:"comment('编号') VARCHAR(128)"`
+	CreateTime       time.Time `xorm:"comment('检查时间') DATETIME"`
+	EndTime          time.Time `xorm:"comment('结束时间') DATETIME"`
+	Position         string    `xorm:"comment('检查部位') VARCHAR(1024)"`
+	Inspection       string    `xorm:"comment('检查项目') VARCHAR(3072)"`
+	InspectionDetail string    `xorm:"comment('现场检查情况') TEXT"`
+	Demand           string    `xorm:"comment('处理要求') VARCHAR(128)"`
+	Status           int       `xorm:"not null default 0 comment('状态(0未上报1审批中2待整改3待复查4完成5关闭)') INT(11)"`
+	Uid              int       `xorm:"not null default 0 comment('创建者id') INT(11)"`
+	Times            int       `xorm:"not null default 1 comment('审批次数') INT(11)"`
+}

+ 18 - 0
models/cm_safe_audit.go

@@ -0,0 +1,18 @@
+package models
+
+import (
+	"time"
+)
+
+type CmSafeAudit struct {
+	Id            int       `xorm:"not null pk autoincr comment('自增id') INT(11)"`
+	SafeId        int       `xorm:"not null default 0 comment('安全巡检id') INT(11)"`
+	BidsectionId  int       `xorm:"not null default 0 comment('标段id') INT(11)"`
+	Times         int       `xorm:"not null default 1 comment('审核次数') INT(11)"`
+	AuditId       int       `xorm:"not null default 0 comment('审核人id') INT(11)"`
+	Status        int       `xorm:"default 0 comment('状态(0通过1退回2关闭)') INT(11)"`
+	Progress      int       `xorm:"not null default 0 comment('审批进度(0上报人1审批2整改3复查)') TINYINT(1)"`
+	CreateTime    time.Time `xorm:"comment('开始时间') DATETIME"`
+	Opinion       string    `xorm:"comment('审批意见') VARCHAR(1024)"`
+	Rectifiedinfo string    `xorm:"comment('整改情况') VARCHAR(1024)"`
+}

+ 15 - 0
models/cm_safe_file.go

@@ -0,0 +1,15 @@
+package models
+
+import (
+	"time"
+)
+
+type CmSafeFile struct {
+	Id           int       `xorm:"not null pk autoincr comment('自增id') INT(11)"`
+	BidsectionId int       `xorm:"not null default 0 comment('标段id') INT(11)"`
+	SafeId       int       `xorm:"not null default 0 comment('安全巡检id') INT(11)"`
+	Uid          int       `xorm:"not null default 0 comment('上传者') INT(11)"`
+	CreatedTime  time.Time `xorm:"comment('上传时间') DATETIME"`
+	FileName     string    `xorm:"not null comment('附件名称') VARCHAR(255)"`
+	FilePath     string    `xorm:"not null comment('附件路径') VARCHAR(32)"`
+}

+ 35 - 0
models/cm_tree.go

@@ -0,0 +1,35 @@
+package models
+
+import (
+	"time"
+)
+
+type CmTree struct {
+	Id                         int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Name                       string    `xorm:"not null comment('名称') VARCHAR(64)"`
+	ProjectId                  int       `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	Depth                      int       `xorm:"not null default 0 comment('深度') TINYINT(4)"`
+	Serial                     int       `xorm:"not null default 0 comment('序号') TINYINT(4)"`
+	Attribution                string    `xorm:"comment('归属') VARCHAR(32)"`
+	Sort                       int       `xorm:"not null default 0 comment('排序') TINYINT(4)"`
+	Isfolder                   int       `xorm:"not null default 1 comment('是否文件夹 1文件夹 0其他') TINYINT(1)"`
+	BidsectionId               int       `xorm:"comment('标段ID') INT(11)"`
+	ParentId                   int       `xorm:"not null default 0 comment('父级ID') INT(11)"`
+	Accounts                   int       `xorm:"not null default 0 comment('账号数') TINYINT(4)"`
+	Contracts                  int       `xorm:"not null default 0 comment('合同数') TINYINT(4)"`
+	ContractsIncome            string    `xorm:"not null default 0.00 comment('合同收入总金额') DECIMAL(12,2)"`
+	ContractsReturned          string    `xorm:"not null default 0.00 comment('合同已收总金额') DECIMAL(12,2)"`
+	ContractsPay               string    `xorm:"not null default 0.00 comment('合同支付总金额') DECIMAL(12,2)"`
+	ContractsPaid              string    `xorm:"not null default 0.00 comment('合同已支付金额') DECIMAL(12,2)"`
+	SafeTotal                  int       `xorm:"not null default 0 comment('安全巡检总数') TINYINT(4)"`
+	SafeRectification          int       `xorm:"not null default 0 comment('安全巡检整改未') TINYINT(4)"`
+	SafeRectificationIn        int       `xorm:"not null default 0 comment('安全巡检整改中') TINYINT(4)"`
+	SafeRectificationFinish    int       `xorm:"not null default 0 comment('安全巡检整改完') TINYINT(4)"`
+	QualityTotal               int       `xorm:"not null default 0 comment('质量总数') TINYINT(4)"`
+	QualityRectification       int       `xorm:"not null default 0 comment('质量未整改') TINYINT(4)"`
+	QualityRectificationIn     int       `xorm:"not null default 0 comment('质量整改中') TINYINT(4)"`
+	QualityRectificationFinish int       `xorm:"not null default 0 comment('质量整改完') TINYINT(4)"`
+	Isdelete                   int       `xorm:"not null default 0 comment('1删除') TINYINT(1)"`
+	CreateTime                 time.Time `xorm:"comment('创建时间') DATETIME"`
+	UpdateTime                 time.Time `xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
+}

+ 29 - 0
models/cm_tree_contracts.go

@@ -0,0 +1,29 @@
+package models
+
+import (
+	"time"
+)
+
+type CmTreeContracts struct {
+	Id               int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	TreeType         int       `xorm:"not null default 0 comment('项目节类型(0收入,1支出)') TINYINT(1)"`
+	TreeId           int       `xorm:"not null comment('树ID') INT(11)"`
+	ParentId         int       `xorm:"not null default 0 comment('父级ID') INT(11)"`
+	Name             string    `xorm:"not null comment('名称') VARCHAR(64)"`
+	Code             string    `xorm:"comment('项目节编号') VARCHAR(32)"`
+	Depth            int       `xorm:"not null default 0 comment('深度') TINYINT(4)"`
+	Serial           int       `xorm:"not null default 0 comment('序号') INT(11)"`
+	Attribution      string    `xorm:"comment('归属') VARCHAR(32)"`
+	Sort             int       `xorm:"not null default 0 comment('排序') TINYINT(4)"`
+	ProjectId        int       `xorm:"not null default 0 comment('项目ID') INT(11)"`
+	BidsectionId     int       `xorm:"comment('标段ID') INT(11)"`
+	ContractId       int       `xorm:"not null default 0 comment('合同ID') INT(11)"`
+	ContractName     string    `xorm:"comment('合同名称') VARCHAR(64)"`
+	ContractCode     string    `xorm:"comment('合同编号') VARCHAR(32)"`
+	ContractPrice    string    `xorm:"not null default 0.00 comment('合同金额') DECIMAL(12,2)"`
+	ContractReturned string    `xorm:"not null default 0.00 comment('回款金额') DECIMAL(12,2)"`
+	ContractsPaid    string    `xorm:"not null default 0.00 comment('合同已支付金额') DECIMAL(12,2)"`
+	ContractStatus   int       `xorm:"not null default 0 comment('合同状态(0履行中1待关闭2正常关闭)') TINYINT(1)"`
+	ContractLocking  int       `xorm:"not null default 0 comment('合同锁定(0未锁定1锁定)') TINYINT(1)"`
+	CreateTime       time.Time `xorm:"comment('创建时间') DATETIME"`
+}

+ 13 - 0
models/cm_valuation_list.go

@@ -0,0 +1,13 @@
+package models
+
+type CmValuationList struct {
+	Id             int    `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Name           string `xorm:"not null comment('名称') VARCHAR(255)"`
+	BillId         string `xorm:"not null comment('(0号台账模式)zh_bill_list id列表,逗号分隔') VARCHAR(255)"`
+	TemplateId     string `xorm:"not null comment('(0号台账模式)zh_bills_template_list id列表,逗号分隔') VARCHAR(255)"`
+	ChapterId      string `xorm:"not null comment('(0号台账模式)zh_project_chapter_list id列表,逗号分隔') VARCHAR(255)"`
+	ListBillId     string `xorm:"not null comment('(工程量清单模式)zh_bill_list id列表,逗号分隔') VARCHAR(255)"`
+	ListTemplateId string `xorm:"not null comment('(工程量清单模式)zh_bills_template_list id列表,逗号分隔') VARCHAR(255)"`
+	ListChapterId  string `xorm:"not null comment('(工程量清单模式)zh_project_chapter_list id列表,逗号分隔') VARCHAR(255)"`
+	CreateTime     int    `xorm:"not null comment('创建时间') INT(11)"`
+}

+ 12 - 0
models/cm_version.go

@@ -0,0 +1,12 @@
+package models
+
+import (
+	"time"
+)
+
+type CmVersion struct {
+	Id         int       `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Name       string    `xorm:"comment('版本号') VARCHAR(255)"`
+	CreateTime time.Time `xorm:"comment('创建时间') DATETIME"`
+	Content    string    `xorm:"TEXT"`
+}

+ 11 - 0
models/cm_white_list.go

@@ -0,0 +1,11 @@
+package models
+
+type CmWhiteList struct {
+	Id         int    `xorm:"not null pk autoincr comment('自增ID') INT(11)"`
+	Ip         string `xorm:"comment('ip地址') VARCHAR(32)"`
+	Type       int    `xorm:"comment('白名单类型 1为后台访问限制 2为接口访问限制') TINYINT(1)"`
+	Enable     int    `xorm:"comment('是否启用 0为禁用') TINYINT(1)"`
+	Token      string `xorm:"comment('接口访问token') VARCHAR(32)"`
+	CreateTime int    `xorm:"comment('创建时间') INT(11)"`
+	Remark     string `xorm:"comment('备注') VARCHAR(32)"`
+}

+ 128 - 0
services/annex_service.go

@@ -0,0 +1,128 @@
+/*
+ * @description:附件相关
+ * @Author: Lanjianrong
+ * @Date: 2020-12-04 16:13:32
+ * @FilePath: \construction_management\services\annex_service.go
+ */
+package services
+
+import (
+	"fmt"
+	"log"
+	"time"
+
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/models"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/web/viewmodels"
+)
+
+type AnnexService interface {
+	ValidRule(ctx iris.Context) (viewmodels.Annex, error)
+	ValidCreate(ctx iris.Context) (viewmodels.AnnexCreate, error)
+	Create(uid int, dataType int, dataId int, list []viewmodels.AnnexList) error
+	Delete(id int) error
+	GetCounts(dataType int, dataId int) (int64, error)
+	Get(dataType int, dataId int, pageNo int, pageSize int) ([]viewmodels.AnnexListView, int64)
+}
+
+// //返回service操作类
+type annexService struct {
+	daoAnnex  *dao.AnnexDao
+	valideGet string
+	// validDetail       string
+}
+
+// 创建项目用户service
+func NewAnnexService() AnnexService {
+	return &annexService{
+		valideGet: "/api/file",
+		daoAnnex:  dao.NewAnnexDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 附件列表
+func (s *annexService) Get(dataType int, dataId int, pageNo int, pageSize int) ([]viewmodels.AnnexListView, int64) {
+	fileData := make([]viewmodels.AnnexListView, 0)
+	list, total := s.daoAnnex.GetList(dataType, dataId, pageNo, pageSize)
+	for _, item := range list {
+		annexVM := viewmodels.AnnexListView{}
+		uid, _ := comm.AesEncrypt(item.AccountId, conf.SignSecret)
+		annexVM.AccountId = uid
+		id, _ := comm.AesEncrypt(item.Id, conf.SignSecret)
+		annexVM.Id = id
+		annexVM.AccountName = item.AccountName
+		annexVM.CreateTime = item.CreateTime
+		annexVM.FileName = item.FileName
+		annexVM.FilePath = item.FilePath
+		fileData = append(fileData, annexVM)
+	}
+	return fileData, total
+}
+
+// 计算附件总数
+func (s *annexService) GetCounts(dataType int, dataId int) (int64, error) {
+	count, err := s.daoAnnex.GetCount(dataType, dataId)
+	return count, err
+}
+
+// 插入数据
+func (s *annexService) Create(uid int, dataType int, dataId int, list []viewmodels.AnnexList) error {
+	fileData := make([]models.CmAnnex, 0)
+	fmt.Println("-------------------------", list)
+	for _, file := range list {
+		fileVM := models.CmAnnex{}
+		fileVM.DataType = dataType
+		fileVM.DataId = dataId
+		fileVM.AccountId = uid
+		fileVM.Name = file.FileName
+		fileVM.OssUrl = file.FilePath
+		// fileVM.CreateTime = time.Unix(file.CreateTime, 0)
+		// time, _ := time.Parse("2020-11-11 20:11:11", file.CreateTime)
+		fileVM.CreateTime = file.CreateTime
+		fileVM.UpdateTime = time.Now()
+		// fmt.Println("------------------", file.CreateTime)
+		fileData = append(fileData, fileVM)
+	}
+	fmt.Println("fileData", fileData)
+	err := s.daoAnnex.InsertByList(fileData)
+	return err
+}
+
+// 删除数据
+func (s *annexService) Delete(id int) error {
+	err := s.daoAnnex.DeleteById(id)
+	return err
+}
+
+// 规则校验
+func (s *annexService) ValidRule(ctx iris.Context) (viewmodels.Annex, error) {
+	annexVaild := viewmodels.Annex{}
+	if ctx.Method() == "GET" {
+		err := ctx.ReadForm(&annexVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadForm转换异常, error=", err)
+			return annexVaild, err
+		}
+		if ctx.Path() == s.valideGet {
+			err = annexVaild.ValidateGet()
+
+		}
+		return annexVaild, err
+	}
+	return annexVaild, nil
+}
+
+func (s *annexService) ValidCreate(ctx iris.Context) (viewmodels.AnnexCreate, error) {
+	annexVaild := viewmodels.AnnexCreate{}
+	err := ctx.ReadJSON(&annexVaild)
+	if err != nil {
+		log.Println("safe-ValidRule-ReadJSON转换异常, error=", err)
+		return annexVaild, err
+	}
+	return annexVaild, nil
+}

+ 257 - 0
services/backstage_service.go

@@ -0,0 +1,257 @@
+/*
+ * @description:登陆相关数据操作
+ * @Author: CP
+ * @Date: 2020-09-02 09:56:28
+ * @FilePath: \construction_management\services\backstage_service.go
+ */
+package services
+
+import (
+	"errors"
+	"log"
+	"net/http"
+	"net/url"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/lib"
+	"go.mod/web/viewmodels"
+)
+
+//定义项目用户Service接口
+type BackstageService interface {
+	ValidRuleLogin(ctx iris.Context) (viewmodels.StaffCld, error)
+	ValidCldStaff(loginData viewmodels.StaffCld, writer http.ResponseWriter) (*viewmodels.ResultCld, error)
+	ValidRuleProject(ctx iris.Context) (viewmodels.Project, error)
+	ValidRuleProjectAdd(ctx iris.Context) (viewmodels.Project, error)
+	ValidRuleProjectSave(ctx iris.Context) (viewmodels.Project, error)
+	ValidRuleAccountAdd(ctx iris.Context) (viewmodels.ProjectAccount, error)
+	ValidRuleAccountSave(ctx iris.Context) (viewmodels.ProjectAccount, error)
+	ValidRuleAccountEnable(ctx iris.Context) (viewmodels.ProjectAccount, error)
+	ValidRuleAccountPassword(ctx iris.Context) (viewmodels.ProjectAccount, error)
+
+	GetCldByCategoryId(categoryId string) (map[string]interface{}, error)
+	Out(ctx iris.Context) error
+}
+
+//返回service操作类
+type backstageService struct {
+	// projectAccountDao *dao.ProjectAccountDao
+	// projectDao        *dao.ProjectDao
+}
+
+//创建项目用户service
+func NewBackstageService() BackstageService {
+	return &backstageService{
+		// projectAccountDao: dao.NewProjectAccountDao(datasource.InstanceDbMaster()),
+		// projectDao:        dao.NewProjectDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 登陆验证
+func (s *backstageService) ValidRuleLogin(ctx iris.Context) (viewmodels.StaffCld, error) {
+	loginVaild := viewmodels.StaffCld{}
+	err := ctx.ReadJSON(&loginVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return loginVaild, err
+	}
+
+	err = loginVaild.ValidateLogin()
+	if err != nil {
+		log.Println("登录验证, error=", err)
+		return loginVaild, err
+	}
+	return loginVaild, nil
+}
+
+// 验证项目
+func (s *backstageService) ValidRuleProject(ctx iris.Context) (viewmodels.Project, error) {
+	projectVaild := viewmodels.Project{}
+	err := ctx.ReadForm(&projectVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return projectVaild, err
+	}
+
+	err = projectVaild.ValidateId()
+	if err != nil {
+		log.Println("验证项目, error=", err)
+		return projectVaild, err
+	}
+	return projectVaild, nil
+}
+
+// 验证项目
+func (s *backstageService) ValidRuleProjectAdd(ctx iris.Context) (viewmodels.Project, error) {
+	projectVaild := viewmodels.Project{}
+	err := ctx.ReadJSON(&projectVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return projectVaild, err
+	}
+
+	err = projectVaild.ValidateAdd()
+	if err != nil {
+		log.Println("添加项目验证, error=", err)
+		return projectVaild, err
+	}
+	return projectVaild, nil
+}
+
+// 项目保存
+func (s *backstageService) ValidRuleProjectSave(ctx iris.Context) (viewmodels.Project, error) {
+	projectVaild := viewmodels.Project{}
+	err := ctx.ReadJSON(&projectVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return projectVaild, err
+	}
+
+	err = projectVaild.ValidateSave()
+	if err != nil {
+		log.Println("添加项目验证, error=", err)
+		return projectVaild, err
+	}
+	return projectVaild, nil
+}
+
+// 验证账号新增
+func (s *backstageService) ValidRuleAccountAdd(ctx iris.Context) (viewmodels.ProjectAccount, error) {
+	projectVaild := viewmodels.ProjectAccount{}
+	err := ctx.ReadJSON(&projectVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return projectVaild, err
+	}
+
+	err = projectVaild.ValidateAddBs()
+	if err != nil {
+		log.Println("添加账号验证, error=", err)
+		return projectVaild, err
+	}
+	return projectVaild, nil
+}
+
+// 验证账号编辑
+func (s *backstageService) ValidRuleAccountSave(ctx iris.Context) (viewmodels.ProjectAccount, error) {
+	projectVaild := viewmodels.ProjectAccount{}
+	err := ctx.ReadJSON(&projectVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return projectVaild, err
+	}
+
+	err = projectVaild.ValidateSaveBs()
+	if err != nil {
+		log.Println("编辑账号验证, error=", err)
+		return projectVaild, err
+	}
+	return projectVaild, nil
+}
+
+// 验证账号启用
+func (s *backstageService) ValidRuleAccountEnable(ctx iris.Context) (viewmodels.ProjectAccount, error) {
+	accounttVaild := viewmodels.ProjectAccount{}
+	err := ctx.ReadForm(&accounttVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return accounttVaild, err
+	}
+
+	err = accounttVaild.ValidateEnableBs()
+	if err != nil {
+		log.Println("编辑账号验证, error=", err)
+		return accounttVaild, err
+	}
+	return accounttVaild, nil
+}
+
+// 验证账号启用
+func (s *backstageService) ValidRuleAccountPassword(ctx iris.Context) (viewmodels.ProjectAccount, error) {
+	accounttVaild := viewmodels.ProjectAccount{}
+	err := ctx.ReadForm(&accounttVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return accounttVaild, err
+	}
+
+	err = accounttVaild.ValidatePasswordBs()
+	if err != nil {
+		log.Println("账号密码验证, error=", err)
+		return accounttVaild, err
+	}
+	return accounttVaild, nil
+}
+
+// 验证项目用户登陆相关
+func (s *backstageService) ValidCldStaff(loginData viewmodels.StaffCld, writer http.ResponseWriter) (*viewmodels.ResultCld, error) {
+
+	// 1.验证CLD账号密码
+	cld := lib.NewCld()
+	result, err := cld.LoginValid(loginData)
+	if err != nil {
+		return nil, err
+	}
+	if result.Code != 0 {
+		return nil, errors.New(result.Msg)
+	}
+
+	// 2.写入登录态
+	// 加密用户标识
+	identity, err := comm.AesEncrypt(result.Data.UserName, conf.CookieSecret)
+	if err != nil {
+		return nil, err
+	}
+	// 加密项目标识
+	category, err := comm.AesEncrypt(result.Data.Category, conf.CookieSecret)
+	if err != nil {
+		return nil, err
+	}
+
+	digitalToken := comm.CreateSign(conf.CookieSecret + identity)
+
+	// 设置cookie
+	maxAge := 60 * 60 * 24 * 7
+	params := url.Values{}
+	params.Add("identity", identity)
+	params.Add("attachedIdentity", category)
+	params.Add("digitalToken", digitalToken)
+	c := &http.Cookie{
+		Name:     "cmBackstage",
+		Value:    params.Encode(),
+		Path:     "/",
+		MaxAge:   maxAge,
+		HttpOnly: true,
+	}
+	http.SetCookie(writer, c)
+
+	// staffCld := &viewmodels.StaffCld{}
+	// staffCld.Category = result.Data.Category
+	// staffCld.StaffName = result.Data.UserName
+
+	return &result.Data, nil
+}
+
+// 登出
+func (s *backstageService) Out(ctx iris.Context) error {
+	// 移除cookie
+	ctx.RemoveCookie("cmBackstage")
+	return nil
+}
+
+// 获得cld办事处和员工 列表
+func (s *backstageService) GetCldByCategoryId(categoryId string) (map[string]interface{}, error) {
+	cld := lib.NewCld()
+
+	result, err := cld.GetList(categoryId)
+	if err != nil {
+		return nil, err
+	}
+
+	if result["code"].(float64) != 0 {
+		return nil, errors.New(result["code"].(string))
+	}
+	return result, nil
+}

+ 181 - 0
services/bid_account_service.go

@@ -0,0 +1,181 @@
+/*
+ * @description:标段账号相关数据操作
+ * @Author: CP
+ * @Date: 2020-10-22 16:13:32
+ * @FilePath: \construction_management\services\bid_account_service.go
+ */
+package services
+
+import (
+	"errors"
+	"log"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/web/utils"
+	"go.mod/web/viewmodels"
+)
+
+//定义项目用户Service接口
+type BidAccountService interface {
+	ValidRule(ctx iris.Context) (viewmodels.BidAccount, error)
+	ValidRuleDelete(ctx iris.Context) (viewmodels.BidAccount, error)
+	Create(viewBidAccount viewmodels.BidAccount, projectId int, accountId int) error
+	Delete(viewBidAccount viewmodels.BidAccount, projectId int) error
+	GetPermission(accountId int, bidsectionId int, projectId int) (viewmodels.PermissionView, error)
+}
+
+//返回service操作类
+type bidAccountService struct {
+	projectAccountDao *dao.ProjectAccountDao
+	projectDao        *dao.ProjectDao
+	bidsectionDao     *dao.BidsectionDao
+	treeDao           *dao.TreeDao
+	bidAccountDao     *dao.BidAccountDao
+	permissionDao     *dao.PermissionAccountDao
+}
+
+//创建项目用户service
+func NewBidAccountService() BidAccountService {
+	return &bidAccountService{
+		projectAccountDao: dao.NewProjectAccountDao(datasource.InstanceDbMaster()),
+		projectDao:        dao.NewProjectDao(datasource.InstanceDbMaster()),
+		bidsectionDao:     dao.NewBidsectionDao(datasource.InstanceDbMaster()),
+		treeDao:           dao.NewTreeDao(datasource.InstanceDbMaster()),
+		bidAccountDao:     dao.NewBidAccountDao(datasource.InstanceDbMaster()),
+		permissionDao:     dao.NewPermissionAccountDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 登陆验证
+func (s *bidAccountService) ValidRule(ctx iris.Context) (viewmodels.BidAccount, error) {
+	bidAccountVaild := viewmodels.BidAccount{}
+	err := ctx.ReadJSON(&bidAccountVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return bidAccountVaild, err
+	}
+
+	err = bidAccountVaild.Validate()
+	if err != nil {
+		log.Println("登录验证, error=", err)
+		return bidAccountVaild, err
+	}
+	return bidAccountVaild, nil
+}
+
+// 删除标段关系用户验证
+func (s *bidAccountService) ValidRuleDelete(ctx iris.Context) (viewmodels.BidAccount, error) {
+	bidAccountVaild := viewmodels.BidAccount{}
+	err := ctx.ReadForm(&bidAccountVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return bidAccountVaild, err
+	}
+
+	err = bidAccountVaild.Validate()
+	if err != nil {
+		log.Println("登录验证, error=", err)
+		return bidAccountVaild, err
+	}
+	return bidAccountVaild, nil
+}
+
+// 获取当前标段的权限
+func (s *bidAccountService) GetPermission(accountId int, bidsectionId int, projectId int) (viewmodels.PermissionView, error) {
+	account := s.projectAccountDao.Get(accountId, projectId)
+	var isAdmin bool
+	if account.IsAdmin == 1 {
+		isAdmin = true
+	} else {
+		isAdmin = false
+	}
+	data, err := s.permissionDao.GetPermissionWithAccountId(accountId, bidsectionId, isAdmin)
+	return data, err
+}
+
+// 新增标段于账号的关系
+func (s *bidAccountService) Create(viewBidAccount viewmodels.BidAccount, projectId int, loginAccountId int) error {
+	// 写入关系表-标段的成员数量-账号表中标段ID
+	// 1.检查账号合法性
+	accountId, err := utils.GetDecryptId(viewBidAccount.AccountId)
+	if err != nil {
+		return err
+	}
+	if loginAccountId == accountId {
+		return errors.New("不能添加自己")
+	}
+	accountData := s.projectAccountDao.Get(accountId, projectId)
+	if accountData.Id == 0 {
+		return errors.New("添加的账号不合法")
+	}
+	// 2.检查标段合法性
+	bidsectionId, err := utils.GetDecryptId(viewBidAccount.BidsectionId)
+	if err != nil {
+		return err
+	}
+	bidsection := s.bidsectionDao.Get(bidsectionId, projectId)
+	if bidsection.Id == 0 {
+		return errors.New("标段不合法")
+	}
+	// 3.检查目录的合法性
+	// 3-1标段ID,,项目ID
+	treeData := s.treeDao.GetBidParentId(bidsectionId, projectId)
+	// 3-2获得目录ID
+	if treeData.Id == 0 {
+		return errors.New("目录不合法")
+	}
+	treeId := treeData.Id
+
+	// 4.检查账号是否已经添加过
+	bidAccountData := s.bidAccountDao.GetAccountId(projectId, bidsectionId, accountId)
+	if bidAccountData.Id != 0 {
+		return errors.New("已添加过该账号")
+	}
+
+	// 新增成员到标段
+	err = s.bidAccountDao.Create(bidsectionId, accountData, treeId, projectId)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+//移除标段成员
+func (s *bidAccountService) Delete(viewBidAccount viewmodels.BidAccount, projectId int) error {
+	// 1.检查账号合法性
+	accountId, err := utils.GetDecryptId(viewBidAccount.AccountId)
+	if err != nil {
+		return err
+	}
+	accountData := s.projectAccountDao.Get(accountId, projectId)
+	if accountData.Id == 0 {
+		return errors.New("添加的账号不合法")
+	}
+	// 1-2 标段关系中是否有改账号 TODO
+	// 2.检查标段合法性
+	bidsectionId, err := utils.GetDecryptId(viewBidAccount.BidsectionId)
+	if err != nil {
+		return err
+	}
+	bidsection := s.bidsectionDao.Get(bidsectionId, projectId)
+	if bidsection.Id == 0 {
+		return errors.New("标段不合法")
+	}
+	// 3.检查目录的合法性
+	// 3-1标段ID,,项目ID
+	treeData := s.treeDao.GetBidParentId(bidsectionId, projectId)
+	// 3-2获得目录ID
+	if treeData.Id == 0 {
+		return errors.New("目录不合法")
+	}
+	treeId := treeData.Id
+
+	// 删除成员到标段
+	err = s.bidAccountDao.Delete(bidsectionId, accountData, treeId, projectId)
+	if err != nil {
+		return err
+	}
+	return nil
+}

+ 116 - 0
services/bidsection_service.go

@@ -0,0 +1,116 @@
+/*
+ * @description: 标段相关数据操作相关
+ * @Author: CP
+ * @Date: 2020-09-28 10:31:31
+ * @FilePath: \construction_management\services\bidsection_service.go
+ */
+package services
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"strconv"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/models"
+	"go.mod/web/utils"
+	"go.mod/web/viewmodels"
+)
+
+//定义标段Service接口
+type BidsectionService interface {
+	ValidRule(iris.Context) (viewmodels.Bidsection, error)
+	Create(viewmodels.Bidsection) error
+}
+
+//返回service操作类
+type bidsectionService struct {
+	dao     *dao.BidsectionDao
+	treeDao *dao.TreeDao
+}
+
+//创建标段service
+func NewBidsectionService() BidsectionService {
+	return &bidsectionService{
+		dao:     dao.NewBidsectionDao(datasource.InstanceDbMaster()),
+		treeDao: dao.NewTreeDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 文件夹规则验证
+func (s *bidsectionService) ValidRule(ctx iris.Context) (viewmodels.Bidsection, error) {
+	bidsectionVaild := viewmodels.Bidsection{}
+	err := ctx.ReadJSON(&bidsectionVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return bidsectionVaild, err
+	}
+
+	err = bidsectionVaild.Validate()
+	if err != nil {
+		log.Println("标段验证, error=", err)
+		return bidsectionVaild, err
+	}
+
+	return bidsectionVaild, nil
+}
+
+// 新增一个标段
+func (s *bidsectionService) Create(data viewmodels.Bidsection) error {
+	// 类型校验
+	folder := models.CmTree{}
+	folder.Name = data.Name
+	ProjectId, err := strconv.Atoi(data.ProjectId)
+	if err != nil {
+		return err
+	}
+
+	// 获得该目录ID
+	Id, err := utils.GetDecryptId(data.FolderId)
+	if err != nil {
+		return err
+	}
+
+	// 该目录中是否有目录 -判断是否是叶子节点--TODO
+	folderList := s.treeDao.GetChildFolder(Id)
+	if len(folderList) > 0 {
+		return errors.New("该目录中存在其他目录,不能新增标段")
+	}
+
+	// 创建在树中的标段
+	// 获得该深度的文件夹最大序号
+	serial := 0
+	treeNode := s.treeDao.Get(Id, ProjectId)
+	if treeNode.Id == 0 {
+		return errors.New("上级目录不正确")
+	}
+	depth := treeNode.Depth + 1
+	attribution := fmt.Sprintf("%s%d-", treeNode.Attribution, treeNode.Serial)
+
+	datalist := s.treeDao.GetALLDepthByAttribution(depth, ProjectId, attribution)
+	maxIndex := len(datalist)
+	if maxIndex != 0 {
+		serial = datalist[maxIndex-1].Serial + 1
+	}
+	// 设置归属
+	folder.Attribution = attribution //treeNode.Attribution + strconv.Itoa(treeNode.Serial) + "-"
+	folder.ParentId = Id
+
+	folder.ProjectId = ProjectId
+	folder.Serial = serial
+	folder.Depth = depth
+	folder.Isfolder = 0
+	folder.CreateTime = time.Now()
+	folder.UpdateTime = time.Now()
+
+	// 创建标段和标段在树中的联系
+	err = s.dao.Create(&folder)
+	if err != nil {
+		return err
+	}
+	return nil
+}

+ 156 - 0
services/contract_expenditure_service.go

@@ -0,0 +1,156 @@
+/*
+ * @description: 合同支出业务相关
+ * @Author: CP
+ * @Date: 2020-12-21 15:35:03
+ * @FilePath: \construction_management\services\contract_expenditure_service.go
+ */
+
+package services
+
+import (
+	"errors"
+	"time"
+
+	"go.mod/conf"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+// 新增支出合同
+func (s *contractService) AddExpenditure(contractData *viewmodels.Contracts, projectId int, bidsectionId int, treeId int) error {
+	// 1. 项目节存在
+	contracts := s.treeContractDao.Get(treeId, bidsectionId, projectId, 1)
+	if contracts.Id == 0 {
+		return errors.New("未找到项目节")
+	}
+	// k := int32(projectId)
+	// 2.项目节是没有合同
+	if contracts.ContractId != 0 {
+		return errors.New("该项目节上已经存在合同")
+	}
+
+	// 2-1.查找合同编号是否存在
+	codeData := s.contractDao.GetByCode(projectId, bidsectionId, contractData.Code, 2)
+	if len(codeData) != 0 {
+		return errors.New("该合同编号已经存在")
+	}
+
+	// 3.新增合同 --合计标段上的金额
+	contractsCm := &models.CmContracts{}
+	contractsCm.Code = contractData.Code
+	contractsCm.Name = contractData.Name
+	contractsCm.ContractsType = 2
+	contractsCm.Price = contractData.Price
+	contractsCm.Returned = "0"
+	contractsCm.Paid = "0"
+	contractsCm.TreeId = treeId
+	contractsCm.ProjectId = projectId
+	contractsCm.BidsectionId = bidsectionId
+	contractsCm.Status = 0
+	contractsCm.CreateTime = time.Now()
+	contractsCm.UpdateTime = time.Now()
+
+	err := s.contractDao.Add(contractsCm)
+	if err != nil {
+		return err
+	}
+
+	// 3.获得该标段下合同总数 - 总收入金额
+	contractTotal, priceTotal := s.getContractTotalAndPrice(bidsectionId, projectId, 1)
+	// 更新标段目录上合同金额和总数
+	err = s.treeDao.UpdateContractsAndPayPrice(projectId, bidsectionId, contractTotal, priceTotal)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// 更新支出合同
+func (s *contractService) UpdateExpenditure(contractData *viewmodels.Contracts, projectId int, bidsectionId int, treeId int) error {
+	// 1. 项目节存在
+	contractsTree := s.treeContractDao.Get(treeId, bidsectionId, projectId, 1)
+	if contractsTree.Id == 0 {
+		return errors.New("未找到项目节")
+	}
+	// 2.项目节是没有合同
+	if contractsTree.ContractId == 0 {
+		return errors.New("该项目节上没有找到合同")
+	}
+
+	// 3.合同锁定 不能删除
+	if contractsTree.ContractLocking == 1 {
+		return errors.New("该合同已锁定")
+	}
+
+	contractsCm := &models.CmContracts{}
+	contractsCm.Id = contractsTree.ContractId
+	contractsCm.Content = contractData.Content
+	contractsCm.Name = contractData.Name
+	contractsCm.Price = contractData.Price
+	contractsCm.PartyA = contractData.PartyA
+	contractsCm.PartyASigner = contractData.PartyASigner
+	contractsCm.PartyB = contractData.PartyB
+	contractsCm.PartyBSigner = contractData.PartyBSigner
+
+	loc, _ := time.LoadLocation("Local")
+	SignerTime, err := time.ParseInLocation(conf.SysTimeform, contractData.SignerTime, loc)
+	if err != nil {
+		return errors.New("签约时间填写异常")
+	}
+	contractsCm.SignerTime = SignerTime
+	contractsCm.Remarks = contractData.Remarks
+
+	columns := []string{"Content", "Name", "Price", "PartyA", "PartyASigner", "PartyB", "PartyBSigner"}
+	err = s.contractDao.Update(contractsCm, columns, projectId, bidsectionId, treeId)
+	if err != nil {
+		return err
+	}
+	// 3.获得该标段下合同总数 - 总收入金额
+	contractTotal, priceTotal := s.getContractTotalAndPrice(bidsectionId, projectId, 1)
+	// 更新标段目录上合同金额和总数
+	err = s.treeDao.UpdateContractsAndPayPrice(projectId, bidsectionId, contractTotal, priceTotal)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 删除支出合同
+func (s *contractService) DeleteExpenditure(projectId int, bidsectionId int, treeId int, id int) error {
+	// 1. 项目节存在
+	contractsTree := s.treeContractDao.Get(treeId, bidsectionId, projectId, 1)
+	if contractsTree.Id == 0 {
+		return errors.New("未找到项目节")
+	}
+	// 2.项目节是没有合同
+	if contractsTree.ContractId == 0 {
+		return errors.New("该项目节上没有找到合同")
+	}
+
+	// 3.合同锁定 不能删除
+	if contractsTree.ContractLocking == 1 {
+		return errors.New("该合同已锁定")
+	}
+
+	// 删除支出合同
+	err := s.contractDao.DeleteExpenditure(projectId, bidsectionId, treeId, id)
+	if err != nil {
+		return err
+	}
+	// 3.获得该标段下合同总数 - 总收入金额
+	contractTotal, priceTotal := s.getContractTotalAndPrice(bidsectionId, projectId, 1)
+	// 更新标段目录上合同金额和总数
+	err = s.treeDao.UpdateContractsAndPayPrice(projectId, bidsectionId, contractTotal, priceTotal)
+	if err != nil {
+		return err
+	}
+
+	// 4.更新回款总金额
+	err = s.contractPaidDao.UpdatePaidTotalPrice(projectId, bidsectionId, id)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

+ 267 - 0
services/contract_paid_service.go

@@ -0,0 +1,267 @@
+/*
+ * @description: 合同已支付 相关业务操作
+ * @Author: CP
+ * @Date: 2020-12-22 14:33:43
+ * @FilePath: \construction_management\services\contract_paid_service.go
+ */
+
+package services
+
+import (
+	"errors"
+	"log"
+	"strconv"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+// 获得合同下已支付列表
+func (s *contractService) PaidAll(projectId int, bidsectionId int, contractsId int, page int) []*viewmodels.ContractsPaid {
+	// 1.获得合同回款列表
+	// data := s.contractReturnDao.GetPage(projectId, bidsectionId, contractsId, page)
+	data := s.contractPaidDao.GetAll(projectId, bidsectionId, contractsId)
+
+	contractsReturnVM := make([]*viewmodels.ContractsPaid, 0)
+	for _, item := range data {
+		cr := s.makeContractPaidVM(&item)
+		contractsReturnVM = append(contractsReturnVM, cr)
+	}
+
+	return contractsReturnVM
+}
+
+// 创建已支付信息
+func (s *contractService) PaidCreate(returnData *viewmodels.ContractsPaid, projectId int, bidsectionId int, contractsId int, projectAccountId int) error {
+	// 1.合同存在
+	contract := s.contractDao.GetInProjectAndBidsection(contractsId, projectId, bidsectionId)
+	if contract.Id == 0 {
+		return errors.New("未找到合同")
+	}
+	// 1-2 合同关闭 不能操作
+	if contract.Status == 2 {
+		return errors.New("合同已关闭")
+	}
+	// 1-3已支付的中金额不能超过 合同金额
+	price, err := strconv.ParseFloat(returnData.Price, 64)
+	if err != nil {
+		return errors.New("金额填写有误")
+	}
+	paidPrice, _ := strconv.ParseFloat(contract.Paid, 64)
+	contractPrice, _ := strconv.ParseFloat(contract.Price, 64)
+	resultPrice := contractPrice - paidPrice
+	if price > resultPrice {
+		return errors.New("支付金额不能超过合同金额")
+	}
+
+	// 2.已支付信息
+	contractsReturnCm := &models.CmContractsPaid{}
+	contractsReturnCm.ContractsId = contractsId
+	contractsReturnCm.ProjectId = projectId
+	contractsReturnCm.BidsectionId = bidsectionId
+	contractsReturnCm.Way = returnData.Way
+	contractsReturnCm.Remarks = returnData.Remarks
+	contractsReturnCm.CreateTime = time.Now()
+	contractsReturnCm.UpdateTime = time.Now()
+
+	loc, _ := time.LoadLocation("Local")
+	time, err := time.ParseInLocation(conf.SysTimeform, returnData.Time, loc)
+	if err != nil {
+		return errors.New("签约时间填写异常")
+	}
+	contractsReturnCm.Time = time
+	contractsReturnCm.CreateUser = returnData.CreateUser
+	contractsReturnCm.AccountId = projectAccountId
+
+	contractsReturnCm.Price = returnData.Price
+
+	// 3.新增回款
+	err = s.contractPaidDao.Add(contractsReturnCm)
+	if err != nil {
+		return err
+	}
+
+	// 4. 更新已支付总金额 -项目节树 标段树 合同表
+	err = s.contractPaidDao.UpdatePaidTotalPrice(projectId, bidsectionId, contractsId)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 编辑已支付信息
+func (s *contractService) PaidUpdate(returnData *viewmodels.ContractsPaid, projectId int, bidsectionId int, contractsId int, id int) error {
+
+	// 1.合同存在
+	contract := s.contractDao.GetInProjectAndBidsection(contractsId, projectId, bidsectionId)
+	if contract.Id == 0 {
+		return errors.New("未找到合同")
+	}
+	// 1-1 已支付是否存在
+	contractPaid := s.contractPaidDao.Get(id, contractsId, bidsectionId)
+	if contractPaid.Id == 0 {
+		return errors.New("未找到已支付")
+	}
+	// 1-2 合同关闭 不能操作
+	if contract.Status == 2 {
+		return errors.New("合同已关闭")
+	}
+
+	// 2.已支付信息
+	contractsReturnCm := &models.CmContractsPaid{}
+	contractsReturnCm.Id = id
+	contractsReturnCm.Way = returnData.Way
+	contractsReturnCm.Remarks = returnData.Remarks
+
+	loc, _ := time.LoadLocation("Local")
+	time, err := time.ParseInLocation("2006-01-02", returnData.Time, loc)
+	if err != nil {
+		return errors.New("已支付时间填写异常")
+	}
+	contractsReturnCm.Time = time
+
+	_, err = strconv.ParseFloat(returnData.Price, 64)
+	if err != nil {
+		return errors.New("金额填写有误")
+	}
+	contractsReturnCm.Price = returnData.Price
+
+	// 3.更新已支付信息
+	err = s.contractPaidDao.Update(contractsReturnCm, contractsId, bidsectionId)
+	if err != nil {
+		return err
+	}
+
+	// 4. 更新已支付总金额 -项目节树 标段树 合同表
+	err = s.contractPaidDao.UpdatePaidTotalPrice(projectId, bidsectionId, contractsId)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// 删除已支付
+func (s *contractService) PaidDelete(projectId int, bidsectionId int, contractsId int, id int) error {
+	// 1.合同存在
+	contract := s.contractDao.GetInProjectAndBidsection(contractsId, projectId, bidsectionId)
+	if contract.Id == 0 {
+		return errors.New("未找到合同")
+	}
+	// 1-1 已支付是否存在
+	contractPaid := s.contractPaidDao.Get(id, contractsId, bidsectionId)
+	if contractPaid.Id == 0 {
+		return errors.New("未找到已支付")
+	}
+	// 1-2 合同关闭 不能操作
+	if contract.Status == 2 {
+		return errors.New("合同已关闭")
+	}
+	// 3.合同锁定 不能删除
+	if contract.Locking == 1 {
+		return errors.New("该合同已锁定")
+	}
+
+	// 1-2. 删除已支付
+	err := s.contractPaidDao.Delete(id, contractsId, bidsectionId, projectId)
+	if err != nil {
+		return err
+	}
+
+	// 2. 更新回款总金额 -项目节树 标段树 合同表
+	err = s.contractPaidDao.UpdatePaidTotalPrice(projectId, bidsectionId, contractsId)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (s *contractService) makeContractPaidVM(data *models.CmContractsPaid) *viewmodels.ContractsPaid {
+	viewContractsReturn := &viewmodels.ContractsPaid{}
+	id, _ := comm.AesEncrypt(strconv.Itoa(data.Id), conf.SignSecret)
+	contractsId, _ := comm.AesEncrypt(strconv.Itoa(data.ContractsId), conf.SignSecret)
+	projectId, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret)
+	bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret)
+
+	viewContractsReturn.Id = id
+	viewContractsReturn.ContractsId = contractsId
+	viewContractsReturn.ProjectId = projectId
+	viewContractsReturn.BidsectionId = bidsectionId
+	viewContractsReturn.Time = data.Time.Format(conf.SysTimeform)
+	viewContractsReturn.Price = data.Price
+
+	viewContractsReturn.Way = data.Way
+	viewContractsReturn.CreateUser = data.CreateUser
+	viewContractsReturn.Remarks = data.Remarks
+	viewContractsReturn.CreateTime = data.CreateTime.Format(conf.SysTimeform)
+
+	counts, _ := s.annexDao.GetCount(1, data.Id)
+	viewContractsReturn.FileCounts = counts
+
+	return viewContractsReturn
+}
+
+// 校验回款参数
+func (s *contractService) ValidRuleContractPaidAdd(ctx iris.Context) (*viewmodels.ContractsPaid, error) {
+
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.ContractsPaid{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadJSON(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.ValidateAdd()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	return contractsVaild, nil
+}
+
+func (s *contractService) ValidRuleContractPaid(ctx iris.Context) (*viewmodels.ContractsPaid, error) {
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.ContractsPaid{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadForm(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.Validate()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	return contractsVaild, nil
+}
+
+//
+func (s *contractService) ValidRuleContractPaidDel(ctx iris.Context) (*viewmodels.ContractsPaid, error) {
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.ContractsPaid{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadForm(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.ValidateDel()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	return contractsVaild, nil
+}

+ 273 - 0
services/contract_return_service.go

@@ -0,0 +1,273 @@
+/*
+ * @description: 合同回款 相关业务操作
+ * @Author: CP
+ * @Date: 2020-12-01 10:21:30
+ * @FilePath: \construction_management\services\contract_return_service.go
+ */
+
+package services
+
+import (
+	"errors"
+	"log"
+	"strconv"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+func (s *contractService) makeContractRetrunVM(data *models.CmContractsReturn) *viewmodels.ContractsReturn {
+	viewContractsReturn := &viewmodels.ContractsReturn{}
+	id, _ := comm.AesEncrypt(strconv.Itoa(data.Id), conf.SignSecret)
+	contractsId, _ := comm.AesEncrypt(strconv.Itoa(data.ContractsId), conf.SignSecret)
+	projectId, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret)
+	bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret)
+
+	viewContractsReturn.Id = id
+	viewContractsReturn.ContractsId = contractsId
+	viewContractsReturn.ProjectId = projectId
+	viewContractsReturn.BidsectionId = bidsectionId
+	viewContractsReturn.Time = data.Time.Format(conf.SysTimeform)
+	viewContractsReturn.Price = data.Price
+
+	viewContractsReturn.Way = data.Way
+	viewContractsReturn.CreateUser = data.CreateUser
+	viewContractsReturn.Remarks = data.Remarks
+	viewContractsReturn.CreateTime = data.CreateTime.Format(conf.SysTimeform)
+
+	counts, _ := s.annexDao.GetCount(1, data.Id)
+	viewContractsReturn.FileCounts = counts
+
+	return viewContractsReturn
+}
+
+// 校验回款参数
+func (s *contractService) ValidRuleContractRetrunAdd(ctx iris.Context) (*viewmodels.ContractsReturn, error) {
+
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.ContractsReturn{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadJSON(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.ValidateAdd()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	return contractsVaild, nil
+}
+
+func (s *contractService) ValidRuleContractRetrun(ctx iris.Context) (*viewmodels.ContractsReturn, error) {
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.ContractsReturn{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadForm(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.Validate()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	return contractsVaild, nil
+}
+
+//
+func (s *contractService) ValidRuleContractRetrunDel(ctx iris.Context) (*viewmodels.ContractsReturn, error) {
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.ContractsReturn{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadForm(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.ValidateDel()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	return contractsVaild, nil
+}
+
+// 获得合同下回款列表
+func (s *contractService) ReturnAll(projectId int, bidsectionId int, contractsId int, page int) []*viewmodels.ContractsReturn {
+	// 1.获得合同回款列表
+	// data := s.contractReturnDao.GetPage(projectId, bidsectionId, contractsId, page)
+	data := s.contractReturnDao.GetAll(projectId, bidsectionId, contractsId)
+
+	contractsReturnVM := make([]*viewmodels.ContractsReturn, 0)
+	for _, item := range data {
+		cr := s.makeContractRetrunVM(&item)
+		contractsReturnVM = append(contractsReturnVM, cr)
+	}
+
+	return contractsReturnVM
+}
+
+// 创建回款信息
+func (s *contractService) ReturnCreate(returnData *viewmodels.ContractsReturn, projectId int, bidsectionId int, contractsId int, projectAccountId int) error {
+	// 1.合同存在
+	contract := s.contractDao.GetInProjectAndBidsection(contractsId, projectId, bidsectionId)
+	if contract.Id == 0 {
+		return errors.New("未找到合同")
+	}
+	// 1-2 合同关闭 不能操作回款
+	if contract.Status == 2 {
+		return errors.New("合同已关闭")
+	}
+
+	// 1-3已支付的中金额不能超过 合同金额
+	price, err := strconv.ParseFloat(returnData.Price, 64)
+	if err != nil {
+		return errors.New("金额填写有误")
+	}
+	returnedPrice, _ := strconv.ParseFloat(contract.Returned, 64)
+	contractPrice, _ := strconv.ParseFloat(contract.Price, 64)
+	resultPrice := contractPrice - returnedPrice
+
+	if price > resultPrice {
+		return errors.New("回款金额不能超过合同金额")
+	}
+
+	// 2.回款信息
+	contractsReturnCm := &models.CmContractsReturn{}
+	contractsReturnCm.ContractsId = contractsId
+	contractsReturnCm.ProjectId = projectId
+	contractsReturnCm.BidsectionId = bidsectionId
+	contractsReturnCm.Way = returnData.Way
+	contractsReturnCm.Remarks = returnData.Remarks
+	contractsReturnCm.CreateTime = time.Now()
+	contractsReturnCm.UpdateTime = time.Now()
+
+	loc, _ := time.LoadLocation("Local")
+	time, err := time.ParseInLocation(conf.SysTimeform, returnData.Time, loc)
+	if err != nil {
+		return errors.New("签约时间填写异常")
+	}
+	contractsReturnCm.Time = time
+	contractsReturnCm.CreateUser = returnData.CreateUser
+	contractsReturnCm.AccountId = projectAccountId
+
+	contractsReturnCm.Price = returnData.Price
+
+	// 3.新增回款
+	err = s.contractReturnDao.Add(contractsReturnCm)
+	if err != nil {
+		return err
+	}
+
+	// 4. 更新回款总金额 -项目节树 标段树 合同表
+	err = s.contractReturnDao.UpdateTotalPrice(projectId, bidsectionId, contractsId)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 编辑回款信息
+func (s *contractService) ReturnUpdate(returnData *viewmodels.ContractsReturn, projectId int, bidsectionId int, contractsId int, id int) error {
+
+	// 1.合同存在
+	contract := s.contractDao.GetInProjectAndBidsection(contractsId, projectId, bidsectionId)
+	if contract.Id == 0 {
+		return errors.New("未找到合同")
+	}
+	// 1-1 回款是否存在
+	contractReturn := s.contractReturnDao.Get(id, contractsId, bidsectionId)
+	if contractReturn.Id == 0 {
+		return errors.New("未找到回款")
+	}
+	// 1-2 合同关闭 不能操作回款
+	if contract.Status == 2 {
+		return errors.New("合同已关闭")
+	}
+
+	// 2.回款信息
+	contractsReturnCm := &models.CmContractsReturn{}
+	contractsReturnCm.Id = id
+	contractsReturnCm.Way = returnData.Way
+	contractsReturnCm.Remarks = returnData.Remarks
+
+	loc, _ := time.LoadLocation("Local")
+	time, err := time.ParseInLocation("2006-01-02", returnData.Time, loc)
+	if err != nil {
+		return errors.New("回款时间填写异常")
+	}
+	contractsReturnCm.Time = time
+
+	_, err = strconv.ParseFloat(returnData.Price, 64)
+	if err != nil {
+		return errors.New("金额填写有误")
+	}
+	contractsReturnCm.Price = returnData.Price
+
+	columns := []string{"Way", "Remarks", "Time", "Price"}
+
+	// 3.更新回款信息
+	err = s.contractReturnDao.Update(contractsReturnCm, contractsId, bidsectionId, columns)
+	if err != nil {
+		return err
+	}
+
+	// 4. 更新回款总金额 -项目节树 标段树 合同表
+	err = s.contractReturnDao.UpdateTotalPrice(projectId, bidsectionId, contractsId)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// 删除回款
+func (s *contractService) ReturnDelete(projectId int, bidsectionId int, contractsId int, id int) error {
+	// 1.合同存在
+	contract := s.contractDao.GetInProjectAndBidsection(contractsId, projectId, bidsectionId)
+	if contract.Id == 0 {
+		return errors.New("未找到合同")
+	}
+	// 1-2 合同关闭 不能操作
+	if contract.Status == 2 {
+		return errors.New("合同已关闭")
+	}
+
+	// 1-1 回款是否存在
+	contractReturn := s.contractReturnDao.Get(id, contractsId, bidsectionId)
+	if contractReturn.Id == 0 {
+		return errors.New("未找到回款")
+	}
+
+	// 3.合同锁定 不能删除
+	if contract.Locking == 1 {
+		return errors.New("该合同已锁定")
+	}
+
+	// 1-2. 删除回款
+	err := s.contractReturnDao.Delete(id, contractsId, bidsectionId, projectId)
+	if err != nil {
+		return err
+	}
+
+	// 2. 更新回款总金额 -项目节树 标段树 合同表
+	err = s.contractReturnDao.UpdateTotalPrice(projectId, bidsectionId, contractsId)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

+ 471 - 0
services/contract_section_tree_service.go

@@ -0,0 +1,471 @@
+package services
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"strconv"
+	"time"
+
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/lib"
+	"go.mod/models"
+	"go.mod/web/utils"
+	"go.mod/web/viewmodels"
+)
+
+// 获得合同项目节
+func (s *contractService) GetSecionTree(bidsectionId int, projectId int, treeType int) *viewmodels.TreeSectionContract {
+	dataList := s.treeContractDao.GetAll(bidsectionId, projectId, treeType)
+	sectionList := s.makeSectionTreeView(dataList)
+
+	// Node := sectionRoot //父节点
+	Node := sectionList[0] //父节点
+	comm.MakeSectionContract(sectionList, Node)
+	return Node
+}
+
+// 获得合同项目节-不包含合同
+func (s *contractService) GetSecionTreeNotContract(bidsectionId int, projectId int, treeType int) *viewmodels.TreeSectionContract {
+	dataList := s.treeContractDao.GetAllNotContract(bidsectionId, projectId, treeType)
+	sectionList := s.makeSectionTreeView(dataList)
+
+	// Node := sectionRoot //父节点
+	Node := sectionList[0] //父节点
+	comm.MakeSectionContract(sectionList, Node)
+	return Node
+}
+
+// 获得项目节树和孩子们下的合同数据-未使用
+func (s *contractService) GetSectionTreeContract(attribution string, bidsectionId int, projectId int, treeType int) []*viewmodels.Contracts {
+	s.treeContractDao.GetAttribution(attribution, bidsectionId, projectId, treeType)
+
+	return nil
+}
+
+// 设置合同项目节初始数据-根据模板导入
+func (s *contractService) SetSection(templateNumber int, bidsectionId int, projectId int, treeType int) error {
+	// 获得模板数据
+	templateTree := make([]*lib.ItemSectionTemplateTree, 0)
+	if templateNumber == 1 {
+		templateTree = lib.NewItemSectionData().TemplateList1
+	} else if templateNumber == 2 {
+		templateTree = lib.NewItemSectionData().TemplateList2
+	} else {
+		return errors.New("找不到合同项目节模板")
+	}
+
+	// 1.组合数据-写入库中
+	sectionTreeList := make([]*models.CmTreeContracts, 0)
+	for _, item := range templateTree {
+		section := &models.CmTreeContracts{}
+		section.TreeId = item.Id
+		section.TreeType = treeType
+		section.ParentId = item.ParentId
+		section.ProjectId = projectId
+		section.BidsectionId = bidsectionId
+		section.Name = item.Name
+		section.Depth = item.Depth
+		section.Serial = item.Serial
+		section.Attribution = item.Attribution
+		section.Code = fmt.Sprintf("%s%d", item.Attribution, item.Serial)
+		section.CreateTime = time.Now()
+
+		section.ContractPrice = "0"
+		section.ContractReturned = "0"
+		section.ContractsPaid = "0"
+
+		// err := s.treeContractDao.Create(section)
+		// if err != nil {
+		// 	log.Println("设置合同项目节模板错误 err=", err)
+		// }
+
+		sectionTreeList = append(sectionTreeList, section)
+	}
+
+	err := s.treeContractDao.CreateAll(sectionTreeList)
+	if err != nil {
+		log.Println("设置合同项目节模板错误 err=", err)
+		return errors.New("设置合同项目节模板错误")
+	}
+	return nil
+}
+
+// 新增项目节
+func (s *contractService) ContractSectionAdd(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) (*models.CmTreeContracts, error) {
+	// 1.验证项目节ID
+	treeId, err := utils.GetDecryptId(sectionData.Id)
+	if err != nil {
+		return nil, err
+	}
+	sectionFather := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+
+	if sectionFather.Id == 0 {
+		return nil, errors.New("未找到项目节")
+	}
+
+	// 1-1 深度为>=2才能新增项目节
+	// if sectionFather.Depth < 3 {
+	// 	return errors.New("请在项目节第三层开始编辑")
+	// }
+	// 1-2 项目节是否有合同
+	if sectionFather.ContractId != 0 {
+		return nil, errors.New("合同项禁止添加子项")
+	}
+
+	// 2 获得最大序号
+	// 2-1 孩子节点
+	childrenList := s.treeContractDao.GetChildren(treeId, bidsectionId, projectId, treeType)
+
+	// 2-2.检查是否可以添加项目节
+	// 新建合同,项目层级必须在第二层以下,当第一层没有孩子可以添加合同
+	if sectionFather.Depth == 0 {
+		if len(childrenList) != 0 {
+			return nil, errors.New("该项目节不允许添加合同,请在下一层级新建合同")
+		}
+	}
+
+	// 2-1 最大序号
+	serial := 1
+	if len(childrenList) != 0 {
+		serial = childrenList[len(childrenList)-1].Serial + 1
+	}
+	// 2-2 归属
+	attribution := fmt.Sprintf("%s%d-", sectionFather.Attribution, sectionFather.Serial)
+	code := fmt.Sprintf("%s%d", attribution, serial)
+	// 2-3获得新增ID
+	lastId := s.treeContractDao.GetLastId()
+	// 新增项目节
+	sectionCM := &models.CmTreeContracts{}
+	sectionCM.Id = lastId.Id + 1
+	sectionCM.TreeId = lastId.Id + 1
+	sectionCM.TreeType = treeType
+	sectionCM.ParentId = sectionFather.TreeId
+	sectionCM.Name = sectionData.Name
+	sectionCM.Depth = sectionFather.Depth + 1
+	sectionCM.Serial = serial
+	sectionCM.Attribution = attribution
+	sectionCM.Code = code
+
+	sectionCM.ProjectId = projectId
+	sectionCM.BidsectionId = bidsectionId
+	sectionCM.ContractPrice = "0"
+	sectionCM.ContractReturned = "0"
+	sectionCM.ContractsPaid = "0"
+
+	data, err := s.treeContractDao.Create(sectionCM)
+	if err != nil {
+		return nil, err
+	}
+	return data, nil
+}
+
+// 新增项目节
+func (s *contractService) SectionAdd(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) (*models.CmTreeContracts, error) {
+	// 1.验证项目节ID
+	treeId, err := utils.GetDecryptId(sectionData.Id)
+	if err != nil {
+		return nil, err
+	}
+	sectionFather := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	if sectionFather.Id == 0 {
+		return nil, errors.New("未找到合同项目节")
+	}
+	// 1-1 深度为>=2才能新增项目节
+	// if sectionFather.Depth < 3 {
+	// 	return errors.New("请在项目节第三层开始编辑")
+	// }
+	// 1-2 项目节是否有合同
+	if sectionFather.ContractId != 0 {
+		return nil, errors.New("合同项禁止添加子项")
+	}
+
+	// 2 获得最大序号
+	// 2-1 孩子节点
+	childrenList := s.treeContractDao.GetChildren(treeId, bidsectionId, projectId, treeType)
+	// 2-1 最大序号
+	serial := 1
+	if len(childrenList) != 0 {
+		serial = childrenList[len(childrenList)-1].Serial + 1
+	}
+	// 2-2 归属
+	attribution := fmt.Sprintf("%s%d-", sectionFather.Attribution, sectionFather.Serial)
+	code := fmt.Sprintf("%s%d", attribution, serial)
+	// 2-3获得新增ID
+	lastId := s.treeContractDao.GetLastId()
+	// 新增项目节
+	sectionCM := &models.CmTreeContracts{}
+	sectionCM.Id = lastId.Id + 1
+	sectionCM.TreeId = lastId.Id + 1
+	sectionCM.TreeType = treeType
+	sectionCM.ParentId = sectionFather.TreeId
+	sectionCM.Name = sectionData.Name
+	sectionCM.Depth = sectionFather.Depth + 1
+	sectionCM.Serial = serial
+	sectionCM.Attribution = attribution
+	sectionCM.Code = code
+
+	sectionCM.ProjectId = projectId
+	sectionCM.BidsectionId = bidsectionId
+	sectionCM.ContractPrice = "0"
+	sectionCM.ContractReturned = "0"
+	sectionCM.ContractsPaid = "0"
+
+	data, err := s.treeContractDao.Create(sectionCM)
+	if err != nil {
+		return nil, err
+	}
+	return data, nil
+}
+
+// 保存名称
+func (s *contractService) SectionSave(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
+	// 1.验证项目节ID
+	treeId, err := utils.GetDecryptId(sectionData.Id)
+	if err != nil {
+		return err
+	}
+	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	if section.Id == 0 {
+		return errors.New("未找到合同项目节")
+	}
+
+	if section.Name == sectionData.Name {
+		return nil
+	}
+
+	// 1-1 深度为>=2才能新增项目节
+	// if section.Depth < 2 {
+	// 	return errors.New("请在项目节第三层开始编辑")
+	// }
+
+	// 2.保存
+	sectionCM := &models.CmTreeContracts{}
+	sectionCM.Name = sectionData.Name
+	sectionCM.Id = section.Id
+
+	err = s.treeContractDao.Save(sectionCM, []string{"Name"})
+	if err != nil {
+		return errors.New("保存失败")
+	}
+	return nil
+}
+
+// 更新序号
+func (s *contractService) UpdateSerial(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
+	// 1.验证项目节ID
+	treeId, err := utils.GetDecryptId(sectionData.Id)
+	if err != nil {
+		return err
+	}
+	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	if section.Id == 0 {
+		return errors.New("未找到合同项目节")
+	}
+
+	if section.Serial == sectionData.Serial {
+		return nil
+	}
+
+	// 1-1 深度为>=2才能新增项目节
+	// if section.Depth < 2 {
+	// 	return errors.New("请在项目节第三层开始编辑")
+	// }
+
+	err = s.treeContractDao.UpdateSerial(section, sectionData.Serial, treeType)
+	if err != nil {
+		return errors.New("更新失败")
+	}
+	return nil
+}
+
+// 项目节删除
+func (s *contractService) SectionDelete(treeId int, bidsectionId int, projectId int, treeType int) error {
+	// 1.验证项目节ID
+	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	if section.Id == 0 {
+		return errors.New("未找到合同项目节")
+	}
+
+	// 1-1 深度为>=1才能新增项目节
+	if section.Depth < 1 {
+		return errors.New("请在项目节第三层开始编辑")
+	}
+	// 1-2 有合同的不能编辑(包含孩子节点)
+	contractList := s.treeContractDao.GetAttributionContract(section, treeType)
+	if len(contractList) != 0 {
+		return errors.New("该项目节存在合同")
+	}
+
+	err := s.treeContractDao.Delete(section)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 项目节的层级移动
+func (s *contractService) MoveDepth(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
+	// 1.验证项目节ID
+	treeId, err := utils.GetDecryptId(sectionData.Id)
+	if err != nil {
+		return err
+	}
+	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	if section.Id == 0 {
+		return errors.New("未找到合同项目节")
+	}
+	// 1-1 深度为>=2才能新增项目节
+	// if section.Depth < 2 {
+	// 	return errors.New("请在项目节第三层开始编辑")
+	// }
+	// 1-2 有合同的不能编辑(包含孩子节点)
+	contractList := s.GetSectionTreeContract(section.Attribution, section.BidsectionId, section.ProjectId, treeType)
+	if len(contractList) != 0 {
+		return errors.New("该项目节已存在合同")
+	}
+
+	// 2.层级降级-同级有前一个兄弟节点
+	elderBrother := &models.CmTreeContracts{}
+	if sectionData.Operation == "downDepth" {
+		// 获得前一个兄弟节点
+		elderBrotherList := s.treeContractDao.GetElderBrother(section.Serial, section.Depth, section.ParentId, bidsectionId, projectId, treeType)
+		if len(elderBrotherList) == 0 {
+			return errors.New("项目节不能降级")
+		}
+		elderBrother = &elderBrotherList[0]
+		// 前一个兄弟节点 不能有合同
+		if elderBrother.ContractId != 0 {
+			return errors.New(elderBrother.Code + "已存在合同,不能降级")
+		}
+	} else if sectionData.Operation == "upDepth" { // 3.层级升级-只要有父亲都能升级
+		// 2-1 父节点深度为2不能升级
+		// if (section.Depth - 1) < 2 {
+		// 	return errors.New("请在项目节第三层开始编辑")
+		// }
+		// 获得父亲节点
+		if section.ParentId == 0 {
+			return errors.New("项目节不能升级")
+		}
+
+	} else {
+		return errors.New("参数错误")
+	}
+
+	// 4.执行升降级
+	err = s.treeContractDao.MoveDepth(section, elderBrother, sectionData.Operation, bidsectionId, projectId, treeType)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// 项目节的排序移动
+func (s *contractService) MoveSerial(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
+	// 1.验证项目节ID
+	treeId, err := utils.GetDecryptId(sectionData.Id)
+	if err != nil {
+		return err
+	}
+	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	if section.Id == 0 {
+		return errors.New("未找到合同项目节")
+	}
+	// 1-1 深度为>=2才能新增项目节
+	// if section.Depth < 2 {
+	// 	return errors.New("请在项目节第三层开始编辑")
+	// }
+	// 1-2 有合同的不能编辑(包含孩子节点)
+	contractList := s.GetSectionTreeContract(section.Attribution, section.BidsectionId, section.ProjectId, treeType)
+	if len(contractList) != 0 {
+		return errors.New("该项目节已存在合同")
+	}
+
+	// 2.下移
+	brother := &models.CmTreeContracts{}
+	if sectionData.Operation == "downSerial" {
+		// 获得下一个兄弟
+		youngerBrotherList := s.treeContractDao.GetYoungerBrother(section.Serial, section.Depth, section.ParentId, bidsectionId, projectId, treeType)
+		if len(youngerBrotherList) == 0 {
+			return errors.New("项目节不能下移")
+		}
+		brother = &youngerBrotherList[0]
+	} else if sectionData.Operation == "upSerial" {
+		// 获得上一个兄弟
+		elderBrotherList := s.treeContractDao.GetElderBrother(section.Serial, section.Depth, section.ParentId, bidsectionId, projectId, treeType)
+		if len(elderBrotherList) == 0 {
+			return errors.New("项目节不能上移")
+		}
+		brother = &elderBrotherList[0]
+	} else {
+		return errors.New("参数错误")
+	}
+
+	// 4.执行升降级
+	err = s.treeContractDao.MoveSerial(section, brother, sectionData.Operation, bidsectionId, projectId, treeType)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 构造项目节树
+func (s *contractService) makeSectionTreeView(dataList []models.CmTreeContracts) []*viewmodels.TreeSectionContract {
+	sectionList := make([]*viewmodels.TreeSectionContract, 0)
+	// 生成根
+	sectionRoot := &viewmodels.TreeSectionContract{}
+	id, _ := comm.AesEncrypt(strconv.Itoa(0), conf.SignSecret)
+	parentId, _ := comm.AesEncrypt(strconv.Itoa(-1), conf.SignSecret)
+	sectionRoot.Id = id
+	sectionRoot.Name = "root"
+	sectionRoot.ParentId = parentId
+	// sectionRoot.Children = make([]*viewmodels.TreeSectionContract, 0)
+	sectionList = append(sectionList, sectionRoot)
+	for _, data := range dataList {
+		section := s.makeSectionView(&data)
+		sectionList = append(sectionList, section)
+	}
+	return sectionList
+}
+
+// 构造一个项目节View
+func (s *contractService) makeSectionView(data *models.CmTreeContracts) *viewmodels.TreeSectionContract {
+	section := &viewmodels.TreeSectionContract{}
+	id, _ := comm.AesEncrypt(strconv.Itoa(data.TreeId), conf.SignSecret)
+	parentId, _ := comm.AesEncrypt(strconv.Itoa(data.ParentId), conf.SignSecret)
+	projectId, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret)
+	contractId, _ := comm.AesEncrypt(strconv.Itoa(data.ContractId), conf.SignSecret)
+	bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret)
+	section.Id = id
+	section.Name = data.Name
+	section.ParentId = parentId
+	section.Depth = data.Depth + 1
+	section.Serial = data.Serial
+	section.Attribution = data.Attribution
+	section.Code = data.Code
+	section.ProjectId = projectId
+	section.BidsectionId = bidsectionId
+	section.ContractId = contractId
+	// section.Children = make([]*viewmodels.TreeSectionContract, 0)
+	section.ElderBrother = true
+	section.IsEnd = false
+
+	section.Name = data.Name
+	section.ContractName = data.ContractName
+	section.ContractCode = data.ContractCode
+	section.ContractPrice = data.ContractPrice
+	section.ContractReturned = data.ContractReturned
+	section.ContractsPaid = data.ContractsPaid
+	section.ContractStatus = data.ContractStatus
+	section.ContractLocking = data.ContractLocking
+
+	section.CreateTime = data.CreateTime.Format(conf.SysTimeform)
+
+	//
+	section.Title = fmt.Sprintf("%s%d ", data.Attribution, data.Serial) + data.Name
+	section.Key = id
+	section.Value = id
+	return section
+}

+ 677 - 0
services/contract_service.go

@@ -0,0 +1,677 @@
+/*
+ * @description: 合同数据相关操作
+ * @Author: CP
+ * @Date: 2020-10-27 11:28:24
+ * @FilePath: \construction_management\services\contract_service.go
+ */
+package services
+
+import (
+	"errors"
+	"fmt"
+	"html"
+	"log"
+	"strconv"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//定义项目用户Service接口
+type ContractService interface {
+	ValidRuleDepth(ctx iris.Context) (*viewmodels.TreeSectionContract, error)
+	ValidRuleTemplate(ctx iris.Context) (*viewmodels.TreeSectionContract, error)
+	ValidRuleSectionAdd(ctx iris.Context) (*viewmodels.TreeSectionContract, error)
+	ValidRuleSectionDelete(ctx iris.Context) (*viewmodels.TreeSectionContract, error)
+	ValidRuleSectionNot(ctx iris.Context) (*viewmodels.TreeSectionContract, error)
+	ValidRuleGet(ctx iris.Context) (*viewmodels.TreeSectionContract, error)
+	ValidRuleSerial(ctx iris.Context) (*viewmodels.TreeSectionContract, error)
+	ValidRuleContractAdd(ctx iris.Context) (*viewmodels.Contracts, error)
+	ValidRuleContractEdi(ctx iris.Context) (*viewmodels.Contracts, error)
+	ValidRuleContractDel(ctx iris.Context) (*viewmodels.Contracts, error)
+	ValidRuleContractClose(ctx iris.Context) (*viewmodels.Contracts, error)
+
+	ValidRuleContractRetrunAdd(ctx iris.Context) (*viewmodels.ContractsReturn, error)
+	ValidRuleContractRetrun(ctx iris.Context) (*viewmodels.ContractsReturn, error)
+	ValidRuleContractRetrunDel(ctx iris.Context) (*viewmodels.ContractsReturn, error)
+
+	ValidRuleContractPaidAdd(ctx iris.Context) (*viewmodels.ContractsPaid, error)
+	ValidRuleContractPaid(ctx iris.Context) (*viewmodels.ContractsPaid, error)
+	ValidRuleContractPaidDel(ctx iris.Context) (*viewmodels.ContractsPaid, error)
+
+	// 项目节
+	Get(treeId int, bidsectionId int, projectId int, treeType int) *viewmodels.TreeSectionContract
+	GetSectionTreeContract(attribution string, bidsectionId int, projectId int, treeType int) []*viewmodels.Contracts
+	GetSecionTree(bidsectionId int, projectId int, treeType int) *viewmodels.TreeSectionContract
+	SetSection(templateNumber int, bidsectionId int, projectIdInt int, treeType int) error
+	SectionAdd(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) (*models.CmTreeContracts, error)
+	ContractSectionAdd(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) (*models.CmTreeContracts, error)
+	SectionSave(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error
+	UpdateSerial(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error
+	SectionDelete(treeId int, bidsectionId int, projectId int, treeType int) error
+	MoveDepth(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error
+	MoveSerial(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error
+	GetSecionTreeNotContract(bidsectionId int, projectId int, treeType int) *viewmodels.TreeSectionContract
+
+	GetContract(contractId int) *viewmodels.Contracts
+	Add(contractData *viewmodels.Contracts, projectId int, bidsectionId int, treeId int) error
+	Update(contractData *viewmodels.Contracts, projectId int, bidsectionId int, treeId int) error
+	Delete(projectId int, bidsectionId int, treeId int, id int) error
+	Close(projectId int, bidsectionId int, treeId int, id int, treeType int) error
+	Unlock(projectId int, bidsectionId int, treeId int, id int, treeType int) error
+	GetSurvey(bidsectionId int, projectId int, contractsType int) map[string]interface{}
+
+	ReturnCreate(returnData *viewmodels.ContractsReturn, projectId int, bidsectionId int, contractsId int, projectAccountId int) error
+	ReturnUpdate(returnData *viewmodels.ContractsReturn, projectId int, bidsectionId int, contractsId int, id int) error
+	ReturnAll(projectId int, bidsectionId int, contractsId int, page int) []*viewmodels.ContractsReturn
+	ReturnDelete(projectId int, bidsectionId int, contractsId int, id int) error
+
+	//支出合同
+	AddExpenditure(contractData *viewmodels.Contracts, projectId int, bidsectionId int, treeId int) error
+	UpdateExpenditure(contractData *viewmodels.Contracts, projectId int, bidsectionId int, treeId int) error
+	DeleteExpenditure(projectId int, bidsectionId int, treeId int, id int) error
+
+	// 已支付
+	PaidAll(projectId int, bidsectionId int, contractsId int, page int) []*viewmodels.ContractsPaid
+	PaidCreate(returnData *viewmodels.ContractsPaid, projectId int, bidsectionId int, contractsId int, projectAccountId int) error
+	PaidUpdate(returnData *viewmodels.ContractsPaid, projectId int, bidsectionId int, contractsId int, id int) error
+	PaidDelete(projectId int, bidsectionId int, contractsId int, id int) error
+}
+
+//返回service操作类
+type contractService struct {
+	treeContractDao   *dao.TreeContractDao
+	contractDao       *dao.ContractDao
+	contractReturnDao *dao.ContractReturnDao
+	contractPaidDao   *dao.ContractPaidDao
+	treeDao           *dao.TreeDao
+	annexDao          *dao.AnnexDao
+}
+
+//创建项目用户service
+func NewContractService() ContractService {
+	return &contractService{
+		treeContractDao:   dao.NewTreeContractDao(datasource.InstanceDbMaster()),
+		contractDao:       dao.NewContractDao(datasource.InstanceDbMaster()),
+		contractReturnDao: dao.NewContractReturnDao(datasource.InstanceDbMaster()),
+		contractPaidDao:   dao.NewContractPaidDao(datasource.InstanceDbMaster()),
+		treeDao:           dao.NewTreeDao(datasource.InstanceDbMaster()),
+		annexDao:          dao.NewAnnexDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 升级降级规则验证
+func (s *contractService) ValidRuleDepth(ctx iris.Context) (*viewmodels.TreeSectionContract, error) {
+	treeSectionVaild := &viewmodels.TreeSectionContract{}
+	err := ctx.ReadJSON(treeSectionVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return treeSectionVaild, err
+	}
+
+	err = treeSectionVaild.ValidateDepth()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return treeSectionVaild, err
+	}
+
+	return treeSectionVaild, nil
+}
+
+// 模板规则验证
+func (s *contractService) ValidRuleTemplate(ctx iris.Context) (*viewmodels.TreeSectionContract, error) {
+	treeSectionVaild := &viewmodels.TreeSectionContract{}
+	err := ctx.ReadJSON(treeSectionVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return treeSectionVaild, err
+	}
+
+	err = treeSectionVaild.ValidateTemplate()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return treeSectionVaild, err
+	}
+
+	return treeSectionVaild, nil
+}
+
+// 模板规则新增项目节
+func (s *contractService) ValidRuleSectionAdd(ctx iris.Context) (*viewmodels.TreeSectionContract, error) {
+	treeSectionVaild := &viewmodels.TreeSectionContract{}
+	err := ctx.ReadJSON(treeSectionVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return treeSectionVaild, err
+	}
+
+	err = treeSectionVaild.ValidateSectionAdd()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return treeSectionVaild, err
+	}
+
+	return treeSectionVaild, nil
+}
+
+// 模板规则新增项目节
+func (s *contractService) ValidRuleSectionDelete(ctx iris.Context) (*viewmodels.TreeSectionContract, error) {
+	treeSectionVaild := &viewmodels.TreeSectionContract{}
+	err := ctx.ReadForm(treeSectionVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return treeSectionVaild, err
+	}
+
+	err = treeSectionVaild.ValidateSectionDelete()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return treeSectionVaild, err
+	}
+
+	return treeSectionVaild, nil
+}
+
+func (s *contractService) ValidRuleSectionNot(ctx iris.Context) (*viewmodels.TreeSectionContract, error) {
+	treeSectionVaild := &viewmodels.TreeSectionContract{}
+	err := ctx.ReadForm(treeSectionVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return treeSectionVaild, err
+	}
+
+	err = treeSectionVaild.ValidateSectionNot()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return treeSectionVaild, err
+	}
+
+	return treeSectionVaild, nil
+}
+
+func (s *contractService) ValidRuleGet(ctx iris.Context) (*viewmodels.TreeSectionContract, error) {
+	treeSectionVaild := &viewmodels.TreeSectionContract{}
+	err := ctx.ReadForm(treeSectionVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return treeSectionVaild, err
+	}
+
+	err = treeSectionVaild.ValidateSectionDelete()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return treeSectionVaild, err
+	}
+	return treeSectionVaild, nil
+}
+
+// 验证序号相关
+func (s *contractService) ValidRuleSerial(ctx iris.Context) (*viewmodels.TreeSectionContract, error) {
+	treeSectionVaild := &viewmodels.TreeSectionContract{}
+	err := ctx.ReadJSON(treeSectionVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return treeSectionVaild, err
+	}
+
+	err = treeSectionVaild.ValidateSectionSerial()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return treeSectionVaild, err
+	}
+	return treeSectionVaild, nil
+}
+
+// 新增合同参数验证
+func (s *contractService) ValidRuleContractAdd(ctx iris.Context) (*viewmodels.Contracts, error) {
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.Contracts{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadJSON(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.ValidateAdd()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	// xss
+	contractsVaild.Code = html.EscapeString(contractsVaild.Code)
+	contractsVaild.Name = html.EscapeString(contractsVaild.Name)
+	contractsVaild.Price = html.EscapeString(contractsVaild.Price)
+
+	return contractsVaild, nil
+}
+
+// 校验编辑接口
+func (s *contractService) ValidRuleContractEdi(ctx iris.Context) (*viewmodels.Contracts, error) {
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.Contracts{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadJSON(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.ValidateEdi()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	contractsVaild.Content = html.EscapeString(contractsVaild.Content)
+	contractsVaild.Name = html.EscapeString(contractsVaild.Name)
+	contractsVaild.Price = html.EscapeString(contractsVaild.Price)
+
+	contractsVaild.PartyA = html.EscapeString(contractsVaild.PartyA)
+	contractsVaild.PartyASigner = html.EscapeString(contractsVaild.PartyASigner)
+	contractsVaild.PartyB = html.EscapeString(contractsVaild.PartyB)
+	contractsVaild.PartyBSigner = html.EscapeString(contractsVaild.PartyBSigner)
+
+	return contractsVaild, nil
+}
+
+// 校验删除合同参数
+func (s *contractService) ValidRuleContractDel(ctx iris.Context) (*viewmodels.Contracts, error) {
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.Contracts{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadForm(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.ValidateDel()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	return contractsVaild, nil
+}
+
+// 校验关闭合同参数
+func (s *contractService) ValidRuleContractClose(ctx iris.Context) (*viewmodels.Contracts, error) {
+	// 创建一个存放前端传过来参数
+	contractsVaild := &viewmodels.Contracts{}
+	// 存放raw的值,放入到contractsVaild
+	err := ctx.ReadJSON(contractsVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return contractsVaild, err
+	}
+	// 验证合同传参
+	err = contractsVaild.ValidateDel()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return contractsVaild, err
+	}
+
+	return contractsVaild, nil
+}
+
+//------------------------------------------------------------
+// 获得项目节
+func (s *contractService) Get(treeId int, bidsectionId int, projectId int, treeType int) *viewmodels.TreeSectionContract {
+	// 1.获得项目节
+	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	// 2.构造数据
+	sectionVM := s.makeSectionView(section)
+	// 3.更新 上移和下一的限制
+	youngerBrotherList := s.treeContractDao.GetYoungerBrother(section.Serial, section.Depth, section.ParentId, bidsectionId, projectId, treeType)
+	if len(youngerBrotherList) == 0 {
+		sectionVM.IsEnd = true
+	}
+	sectionVM.ElderBrother = true
+	elderBrotherList := s.treeContractDao.GetElderBrother(section.Serial, section.Depth, section.ParentId, bidsectionId, projectId, treeType)
+	if len(elderBrotherList) == 0 {
+		sectionVM.ElderBrother = false
+	}
+	return sectionVM
+}
+
+// 获得合同详情
+func (s *contractService) GetContract(contractId int) *viewmodels.Contracts {
+	contract := s.contractDao.Get(contractId)
+
+	contractsVM := s.makeContractVM(contract)
+	return &contractsVM
+}
+
+// 新增合同
+func (s *contractService) Add(contractData *viewmodels.Contracts, projectId int, bidsectionId int, treeId int) error {
+	// 1. 项目节存在
+	contracts := s.treeContractDao.Get(treeId, bidsectionId, projectId, 0)
+	if contracts.Id == 0 {
+		return errors.New("未找到项目节")
+	}
+
+	// 2.项目节是没有合同
+	if contracts.ContractId != 0 {
+		return errors.New("该项目节上已经存在合同")
+	}
+
+	// 2-1.查找合同编号是否存在
+	codeData := s.contractDao.GetByCode(projectId, bidsectionId, contractData.Code, 1)
+	if len(codeData) != 0 {
+		return errors.New("该合同编号已经存在")
+	}
+
+	// 3.新增合同 --合计标段上的金额
+	contractsCm := &models.CmContracts{}
+	contractsCm.Code = contractData.Code
+	contractsCm.Name = contractData.Name
+	contractsCm.ContractsType = 1
+	contractsCm.Price = contractData.Price
+	contractsCm.Returned = "0"
+	contractsCm.Paid = "0"
+	contractsCm.TreeId = treeId
+	contractsCm.ProjectId = projectId
+	contractsCm.BidsectionId = bidsectionId
+	contractsCm.Status = 0
+	contractsCm.CreateTime = time.Now()
+	contractsCm.UpdateTime = time.Now()
+
+	err := s.contractDao.Add(contractsCm)
+	if err != nil {
+		return err
+	}
+
+	// 3.获得该标段下合同总数 - 总收入金额
+	contractTotal, priceTotal := s.getContractTotalAndPrice(bidsectionId, projectId, 0)
+	// 更新标段目录上合同金额和总数
+	err = s.treeDao.UpdateContractsAndIncomePrice(projectId, bidsectionId, contractTotal, priceTotal)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// 更新合同
+func (s *contractService) Update(contractData *viewmodels.Contracts, projectId int, bidsectionId int, treeId int) error {
+	// 1. 项目节存在
+	contractsTree := s.treeContractDao.Get(treeId, bidsectionId, projectId, 0)
+	if contractsTree.Id == 0 {
+		return errors.New("未找到项目节")
+	}
+	// 2.项目节是没有合同
+	if contractsTree.ContractId == 0 {
+		return errors.New("该项目节上没有找到合同")
+	}
+
+	// 3.合同锁定 不能删除
+	if contractsTree.ContractLocking == 1 {
+		return errors.New("该合同已锁定")
+	}
+
+	contractsCm := &models.CmContracts{}
+	contractsCm.Id = contractsTree.ContractId
+	contractsCm.Content = contractData.Content
+	contractsCm.Name = contractData.Name
+	contractsCm.Price = contractData.Price
+	contractsCm.PartyA = contractData.PartyA
+	contractsCm.PartyASigner = contractData.PartyASigner
+	contractsCm.PartyB = contractData.PartyB
+	contractsCm.PartyBSigner = contractData.PartyBSigner
+
+	loc, _ := time.LoadLocation("Local")
+	SignerTime, err := time.ParseInLocation(conf.SysTimeform, contractData.SignerTime, loc)
+	if err != nil {
+		return errors.New("签约时间填写异常")
+	}
+	contractsCm.SignerTime = SignerTime
+	contractsCm.Remarks = contractData.Remarks
+
+	columns := []string{"Content", "Name", "Price", "PartyA", "PartyASigner", "PartyB", "PartyBSigner"}
+	err = s.contractDao.Update(contractsCm, columns, projectId, bidsectionId, treeId)
+	if err != nil {
+		return err
+	}
+	// 3.获得该标段下合同总数 - 总收入金额
+	contractTotal, priceTotal := s.getContractTotalAndPrice(bidsectionId, projectId, 0)
+	// 更新标段目录上合同金额和总数
+	err = s.treeDao.UpdateContractsAndIncomePrice(projectId, bidsectionId, contractTotal, priceTotal)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 删除合同
+func (s *contractService) Delete(projectId int, bidsectionId int, treeId int, id int) error {
+	// 1. 项目节存在
+	contractsTree := s.treeContractDao.Get(treeId, bidsectionId, projectId, 0)
+	if contractsTree.Id == 0 {
+		return errors.New("未找到项目节")
+	}
+	// 2.项目节是没有合同
+	if contractsTree.ContractId == 0 {
+		return errors.New("该项目节上没有找到合同")
+	}
+
+	// 3.合同锁定 不能删除
+	if contractsTree.ContractLocking == 1 {
+		return errors.New("该合同已锁定")
+	}
+
+	// 删除合同
+	err := s.contractDao.Delete(projectId, bidsectionId, treeId, id)
+	if err != nil {
+		return err
+	}
+	// 3.获得该标段下合同总数 - 总收入金额
+	contractTotal, priceTotal := s.getContractTotalAndPrice(bidsectionId, projectId, 0)
+	// 更新标段目录上合同金额和总数
+	err = s.treeDao.UpdateContractsAndIncomePrice(projectId, bidsectionId, contractTotal, priceTotal)
+	if err != nil {
+		return err
+	}
+
+	// 4.更新回款总金额
+	err = s.contractReturnDao.UpdateTotalPrice(projectId, bidsectionId, id)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// 关闭合同
+func (s *contractService) Close(projectId int, bidsectionId int, treeId int, id int, treeType int) error {
+	// 1. 项目节存在
+	contractsTree := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	if contractsTree.Id == 0 {
+		return errors.New("未找到项目节")
+	}
+	// 2.项目节是没有合同
+	if contractsTree.ContractId == 0 {
+		return errors.New("该项目节上没有找到合同")
+	}
+
+	// 3.合同锁定 不能删除
+	if contractsTree.ContractLocking == 1 {
+		return errors.New("该合同已锁定")
+	}
+
+	// 关闭合同
+	err := s.contractDao.Close(projectId, bidsectionId, treeId, id)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// 解锁合同
+func (s *contractService) Unlock(projectId int, bidsectionId int, treeId int, id int, treeType int) error {
+	// 1. 项目节存在
+	contractsTree := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
+	if contractsTree.Id == 0 {
+		return errors.New("未找到项目节")
+	}
+	// 2.项目节是没有合同
+	if contractsTree.ContractId == 0 {
+		return errors.New("该项目节上没有找到合同")
+	}
+
+	// 解锁合同
+	err := s.contractDao.Unlock(projectId, bidsectionId, treeId, id)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+//获得合同收入概况
+func (s *contractService) GetSurvey(bidsectionId int, projectId int, contractsType int) map[string]interface{} {
+	// 1.获得收入合同
+	year := time.Now().Year()
+	incomeList := s.contractDao.GetTypeYear(bidsectionId, projectId, contractsType, year)
+
+	// 2.初始化
+	totalContractPrice := 0.00
+	totalTypePrice := 0.00
+	performNumber := 0
+	closeNumber := 0
+	uncloseNumber := 0
+	// 3.当年数据初始化
+	returnDate := map[string]float64{
+		fmt.Sprintf("%d-01", year): 0.00,
+		fmt.Sprintf("%d-02", year): 0.00,
+		fmt.Sprintf("%d-03", year): 0.00,
+		fmt.Sprintf("%d-04", year): 0.00,
+		fmt.Sprintf("%d-05", year): 0.00,
+		fmt.Sprintf("%d-06", year): 0.00,
+		fmt.Sprintf("%d-07", year): 0.00,
+		fmt.Sprintf("%d-08", year): 0.00,
+		fmt.Sprintf("%d-09", year): 0.00,
+		fmt.Sprintf("%d-10", year): 0.00,
+		fmt.Sprintf("%d-11", year): 0.00,
+		fmt.Sprintf("%d-12", year): 0.00,
+	}
+
+	for _, item := range incomeList {
+		contractPrice, _ := strconv.ParseFloat(item.Price, 64)
+		totalContractPrice = totalContractPrice + contractPrice
+		typePrice := 0.00
+		if contractsType == 1 {
+			typePrice, _ = strconv.ParseFloat(item.Returned, 64)
+			totalTypePrice = totalTypePrice + typePrice
+		} else {
+			typePrice, _ = strconv.ParseFloat(item.Paid, 64)
+			totalTypePrice = totalTypePrice + typePrice
+		}
+
+		if item.Status == 0 {
+			performNumber = performNumber + 1
+		} else if item.Status == 1 {
+			uncloseNumber = uncloseNumber + 1
+		} else if item.Status == 2 {
+			closeNumber = closeNumber + 1
+		}
+
+		returnDate[item.CreateTime.Format(conf.SysTimeformMonth)] = returnDate[item.CreateTime.Format(conf.SysTimeformMonth)] + typePrice
+	}
+	totalContractPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", totalContractPrice), 64)
+	totalTypePrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", totalTypePrice), 64)
+
+	// ac := accounting.Accounting{Symbol: "", Precision: 2}
+
+	surveryData := map[string]interface{}{
+		"totalContractPrice":     totalContractPrice,
+		"totalContractPriceShow": totalContractPrice,
+		// "totalReturnPrice":   ac.FormatMoney(totalReturnPrice),
+		"performNumber": performNumber,
+		"closeNumber":   closeNumber,
+		"uncloseNumber": uncloseNumber,
+		"returnDate":    returnDate,
+	}
+
+	if contractsType == 1 {
+		surveryData["totalReturnPriceShow"] = totalTypePrice
+	} else {
+		surveryData["totalPaidPriceShow"] = totalTypePrice
+	}
+
+	return surveryData
+}
+
+// 获得合同总数量和总金额
+func (s *contractService) getContractTotalAndPrice(bidsectionId int, projectId int, treeType int) (contractTotal int, priceTotal float64) {
+
+	contractListAll := s.treeContractDao.GetContractAll(bidsectionId, projectId)
+
+	// 获得收入合同
+	contractList := s.treeContractDao.GetContract(bidsectionId, projectId, treeType)
+	priceTotal = 0.00
+	for _, item := range contractList {
+		contractPrice, _ := strconv.ParseFloat(item.ContractPrice, 64)
+		priceTotal = priceTotal + contractPrice
+	}
+	// 合同总数
+	// contractTotal = len(contractList) + 1
+	contractTotal = len(contractListAll)
+	// 合同收入总金额
+	// price, _ := strconv.ParseFloat(priceString, 64)
+	// priceTotal = priceTotal + price
+	// 保留2位小数
+	priceTotal, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", priceTotal), 64)
+
+	return contractTotal, priceTotal
+}
+
+// 构建合同详情视图
+func (s *contractService) makeContractVM(contract *models.CmContracts) viewmodels.Contracts {
+	contractsVM := viewmodels.Contracts{}
+	if contract.Id == 0 {
+		return contractsVM
+	}
+
+	id, _ := comm.AesEncrypt(strconv.Itoa(contract.Id), conf.SignSecret)
+	treeId, _ := comm.AesEncrypt(strconv.Itoa(contract.TreeId), conf.SignSecret)
+	bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(contract.BidsectionId), conf.SignSecret)
+
+	contractsVM.Id = id
+	contractsVM.TreeId = treeId
+	contractsVM.ContractsType = contract.ContractsType
+	contractsVM.BidsectionId = bidsectionId
+
+	contractsVM.Name = contract.Name
+	contractsVM.Content = contract.Content
+	contractsVM.Code = contract.Code
+	contractsVM.PartyA = contract.PartyA
+	contractsVM.PartyASigner = contract.PartyASigner
+	contractsVM.PartyB = contract.PartyB
+	contractsVM.PartyBSigner = contract.PartyBSigner
+	contractsVM.Remarks = contract.Remarks
+	contractsVM.Price = contract.Price
+	contractsVM.Returned = contract.Returned
+	contractsVM.Paid = contract.Paid
+	contractsVM.Status = contract.Status
+	contractsVM.Locking = contract.Locking
+
+	contractsVM.CreateTime = contract.CreateTime.Format(conf.SysTimeform)
+	contractsVM.UpdateTime = contract.UpdateTime.Format(conf.SysTimeform)
+	// nilTime := time.Time{}
+	// contract.SignerTime != nilTime
+
+	if !contract.SignerTime.IsZero() {
+		contractsVM.SignerTime = contract.SignerTime.Format(conf.SysTimeform)
+	}
+
+	return contractsVM
+}

+ 248 - 0
services/login_service.go

@@ -0,0 +1,248 @@
+/*
+ * @description:登陆相关数据操作
+ * @Author: CP
+ * @Date: 2020-09-02 09:56:28
+ * @FilePath: \construction_management\services\login_service.go
+ */
+package services
+
+import (
+	"errors"
+	"log"
+	"net/http"
+	"net/url"
+	"strconv"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/lib"
+	"go.mod/web/viewmodels"
+)
+
+//定义项目用户Service接口
+type LoginService interface {
+	ValidRule(ctx iris.Context) (viewmodels.Login, error)
+	ValidProjectAccount(viewmodels.Login, http.ResponseWriter) (*viewmodels.ProjectAccount, error)
+	Out(ctx iris.Context) error
+}
+
+//返回service操作类
+type loginService struct {
+	projectAccountDao *dao.ProjectAccountDao
+	projectDao        *dao.ProjectDao
+}
+
+//创建项目用户service
+func NewLoginService() LoginService {
+	return &loginService{
+		projectAccountDao: dao.NewProjectAccountDao(datasource.InstanceDbMaster()),
+		projectDao:        dao.NewProjectDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 登陆验证
+func (s *loginService) ValidRule(ctx iris.Context) (viewmodels.Login, error) {
+	loginVaild := viewmodels.Login{}
+	err := ctx.ReadJSON(&loginVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return loginVaild, err
+	}
+
+	err = loginVaild.Validate()
+	if err != nil {
+		log.Println("登录验证, error=", err)
+		return loginVaild, err
+	}
+	return loginVaild, nil
+}
+
+// 验证项目用户登陆相关
+func (s *loginService) ValidProjectAccount(loginData viewmodels.Login, writer http.ResponseWriter) (*viewmodels.ProjectAccount, error) {
+
+	// 1-1.工程项目是否存在
+	projectInfo := s.projectDao.GetCode(loginData.Code)
+	if projectInfo.Id == 0 {
+		return nil, errors.New("工程建设管理员还未创建项目,禁止登录")
+	}
+	// 1-2.获得项目管理员
+	projectAdminInfo := s.projectAccountDao.Get(projectInfo.UserId, projectInfo.Id)
+
+	if projectAdminInfo.Id == 0 {
+		return nil, errors.New("工程建设管理员不存在,禁止登录")
+	}
+
+	// 2.验证登陆-临时
+	projectAccountInfo := s.projectAccountDao.GetAccount(loginData.Account)
+	if projectAccountInfo.Id == 0 {
+		return nil, errors.New("未找到该账号")
+	}
+	// 2.账号停用
+	if projectAccountInfo.Enable == 0 {
+		return nil, errors.New("该账号已被停用")
+	}
+
+	password := comm.CreatePasswordSign(loginData.Password, loginData.Account)
+
+	if projectAccountInfo.Password != password {
+		return nil, errors.New("密码不正确")
+	}
+
+	// 验证密码-TODO
+	Jlzf := lib.NewJlzf()
+	err := Jlzf.LoginValid(loginData)
+	if err != nil {
+		return nil, err
+	}
+
+	// 加密用户标识
+	identity, err := comm.AesEncrypt(strconv.Itoa(projectAccountInfo.Id), conf.CookieSecret)
+	if err != nil {
+		return nil, err
+	}
+	// 加密项目标识
+	projectId, err := comm.AesEncrypt(strconv.Itoa(projectAccountInfo.ProjectId), conf.CookieSecret)
+	if err != nil {
+		return nil, err
+	}
+
+	digitalToken := comm.CreateSign(conf.CookieSecret + strconv.Itoa(projectAccountInfo.Id))
+
+	// 设置cookie
+	maxAge := 60 * 60 * 24 * 7
+	params := url.Values{}
+	params.Add("identity", identity)
+	params.Add("attachedIdentity", projectId)
+	params.Add("digitalToken", digitalToken)
+	c := &http.Cookie{
+		Name:     "cm",
+		Value:    params.Encode(),
+		Path:     "/",
+		MaxAge:   maxAge,
+		HttpOnly: true,
+	}
+	http.SetCookie(writer, c)
+
+	// TODO--分布式会话--后续需要在加入
+
+	viewAccountData := comm.MakeProjectAccountVM(projectAccountInfo)
+	return &viewAccountData, nil
+}
+
+// TODO -替换jwt
+// 验证项目用户登陆相关
+// func (s *loginService) ValidProjectAccount(loginData viewmodels.Login, writer http.ResponseWriter) error {
+// 	projectInfo := models.CmProject{}
+// 	// 工程项目是否存在
+// 	projectInfo.Code = loginData.Code
+// 	s.projectDao.Get(&projectInfo)
+// 	if projectInfo.Id == 0 {
+// 		return errors.New("工程建设管理员还未创建项目,禁止登录")
+// 	}
+// 	// 获得项目用户
+// 	projectAccountInfo := s.projectAccountDao.Get(projectInfo.UserId, projectInfo.Id)
+// 	if projectAccountInfo.Id == 0 {
+// 		return errors.New("工程建设管理员不存在,禁止登录")
+// 	}
+// 	// 验证密码-TODO
+// 	Jlzf := lib.NewJlzf()
+// 	err := Jlzf.LoginValid(loginData)
+// 	if err != nil {
+// 		return err
+// 	}
+
+// 	// 加密用户标识
+// 	identity, err := comm.AesEncrypt(strconv.Itoa(projectAccountInfo.Id), conf.CookieSecret)
+// 	if err != nil {
+// 		return err
+// 	}
+// 	// 加密项目标识
+// 	projectId, err := comm.AesEncrypt(strconv.Itoa(projectAccountInfo.ProjectId), conf.CookieSecret)
+// 	if err != nil {
+// 		return err
+// 	}
+// 	// jwt token
+// 	token := jwt.NewTokenWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
+// 		// 根据需求,可以存一些必要的数据
+// 		"identity": identity,
+// 		"project":  projectId,
+// 		// 签发人
+// 		"iss": "cm",
+// 		// 签发时间
+// 		"iat": time.Now().Unix(),
+// 		// 设定过期时间,便于测试,设置7天过期
+// 		"exp": time.Now().Add(72 * time.Hour * time.Duration(1)).Unix(),
+// 	})
+
+// 	// 使用设置的秘钥,签名生成jwt字符串
+// 	tokenString, _ := token.SignedString([]byte(conf.SignSecret))
+// 	fmt.Println(tokenString)
+// 	maxAge := 60 * 60 * 24 * 7
+// 	// params := url.Values{}
+// 	// params.Add("token", tokenString)
+// 	c := &http.Cookie{
+// 		Name:   "cm",
+// 		Value:  tokenString, //params.Encode(),
+// 		Path:   "/",
+// 		MaxAge: maxAge,
+// 		//HttpOnly: true,
+// 	}
+// 	http.SetCookie(writer, c)
+
+// 	// TODO--分布式会话--后续需要在加入
+
+// 	return nil
+// }
+
+// 登出
+func (s *loginService) Out(ctx iris.Context) error {
+	// 作废jwt token
+
+	// 移除cookie
+	ctx.RemoveCookie("cm")
+	return nil
+}
+
+//fmt.Println(ctx.FormValues())
+
+// list := ctx.FormValues()
+// loginVaild := viewmodels.Login{}
+// v := reflect.ValueOf(&loginVaild).Elem()
+// for path, values := range list {
+// 	//fmt.Println(path)
+// 	//fmt.Println(values)
+// 	if path != "csrf.Token" {
+
+// 		v.FieldByName(Ucfirst(path)).Set(reflect.ValueOf(values[0]))
+
+// 	}
+// }
+//fmt.Println(loginVaild)
+// loginVaild := viewmodels.Login{
+// 	Code:     ctx.FormValue("code"),
+// 	Account:  ctx.FormValue("account"),
+// 	Password: ctx.FormValue("password"),
+// }
+
+// // 加密用户标识 生成数字证书
+// identity, err := comm.AesEncrypt(strconv.Itoa(projectAccountInfo.Id), conf.CookieSecret)
+// if err != nil {
+// 	return err
+// }
+// digitalToken := comm.CreateSign(conf.CookieSecret + strconv.Itoa(projectAccountInfo.Id))
+
+// // 设置cookie
+// maxAge := 60 * 60 * 24 * 7
+// params := url.Values{}
+// params.Add("identity", identity)
+// params.Add("digitalToken", digitalToken)
+// c := &http.Cookie{
+// 	Name:   "cm",
+// 	Value:  params.Encode(),
+// 	Path:   "/",
+// 	MaxAge: maxAge,
+// }
+// http.SetCookie(writer, c)

+ 53 - 0
services/manager_service.go

@@ -0,0 +1,53 @@
+/*
+ * @description: 管理员数据处理
+ * @Author: CP
+ * @Date: 2020-08-20 17:08:38
+ * @FilePath: \construction_management\services\manager_service.go
+ */
+package services
+
+import (
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/models"
+)
+
+//定义管理员Service接口
+type ManagerService interface {
+	GetAll() []models.CmManager
+	CountAll() int64
+	Get(id int) *models.CmManager
+	Update(data *models.CmManager, columns []string) error
+	Create(data *models.CmManager) error
+}
+
+//返回service操作类
+type managerService struct {
+	dao *dao.ManagerDao
+}
+
+//创建管理员service
+func NewManagerService() ManagerService {
+	return &managerService{
+		dao: dao.NewManagerDao(datasource.InstanceDbMaster()),
+	}
+}
+
+//实现getall接口
+func (s *managerService) GetAll() []models.CmManager {
+	return s.dao.GetAll()
+}
+
+func (s *managerService) CountAll() int64 {
+	return s.dao.CountAll()
+}
+
+func (s *managerService) Get(id int) *models.CmManager {
+	return s.dao.Get(id)
+}
+func (s *managerService) Update(data *models.CmManager, columns []string) error {
+	return s.dao.Update(data, columns)
+}
+func (s *managerService) Create(data *models.CmManager) error {
+	return s.dao.Create(data)
+}

+ 522 - 0
services/project_account_service.go

@@ -0,0 +1,522 @@
+/*
+ * @description:项目用户相关数据处理
+ * @Author: CP
+ * @Date: 2020-08-27 17:23:58
+ * @FilePath: \construction_management\services\project_account_service.go
+ */
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"html"
+	"log"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/comm"
+	"go.mod/models"
+	"go.mod/web/utils"
+	"go.mod/web/viewmodels"
+
+	"go.mod/dao"
+	"go.mod/datasource"
+)
+
+//定义项目用户Service接口
+type ProjectAccountService interface {
+	ValidRule(ctx iris.Context) (viewmodels.ProjectAccount, error)
+	ValidRuleChangePassword(ctx iris.Context) (viewmodels.AccountPassword, error)
+	ValidRulePermission(ctx iris.Context) (viewmodels.Permission, error)
+	ValidRuleAccount(ctx iris.Context) (viewmodels.ProjectAccount, error)
+	ValidGetPermission(ctx iris.Context) (viewmodels.Permission, error)
+	ValidRuleProjectId(ctx iris.Context) (viewmodels.ProjectAccount, error)
+	Get(accountId int, projectId int) *viewmodels.ProjectAccount
+	GetAll(projectId int) []viewmodels.ProjectAccount
+	GetBidAccount(bidsectionId int, projectId int, projectAccountId int, name string) []viewmodels.ProjectAccount
+	Search(name string, projectId int) []viewmodels.ProjectAccount
+	AddBs(viewAccount viewmodels.ProjectAccount, projectId int) error
+	Add(viewAccount viewmodels.ProjectAccount, projectId int) error
+	Save(viewAccount viewmodels.ProjectAccount, id int, projectId int) error
+	SaveAccount(viewAccount viewmodels.ProjectAccount, id int, projectId int) error
+	Enable(id int, projectId int, enable int) error
+	ChangeAccount(id int, projectId int, viewAccount viewmodels.ProjectAccount) error
+	ChangeAccountBS(id int, projectId int, viewAccount viewmodels.ProjectAccount) error
+	GetProjectInfo(id int) (viewmodels.ProjectInfo, error)
+	Delete(id int, projectId int) error
+
+	ChangePassword(AccountData viewmodels.AccountPassword, projectId int, projectAccountId int) error
+
+	SaveAuth(permission viewmodels.Permission, projectId int, bidsectionId int, accountId int) error
+}
+
+//返回service操作类
+type projectAccountService struct {
+	dao                  *dao.ProjectAccountDao
+	bidAccountDao        *dao.BidAccountDao
+	permissionAccountDao *dao.PermissionAccountDao
+	validSave            string
+	validAdd             string
+	validPassword        string
+}
+
+//创建项目用户service
+func NewProjectAccountService() ProjectAccountService {
+	return &projectAccountService{
+		dao:                  dao.NewProjectAccountDao(datasource.InstanceDbMaster()),
+		bidAccountDao:        dao.NewBidAccountDao(datasource.InstanceDbMaster()),
+		permissionAccountDao: dao.NewPermissionAccountDao(datasource.InstanceDbMaster()),
+		validSave:            "/api/projectSetting/account/save",
+		validAdd:             "/api/projectSetting/account/create",
+		validPassword:        "/api/projectSetting/account/change",
+	}
+}
+
+// 用户规则验证
+func (s *projectAccountService) ValidRule(ctx iris.Context) (viewmodels.ProjectAccount, error) {
+	accountVaild := viewmodels.ProjectAccount{}
+	err := ctx.ReadJSON(&accountVaild)
+	if err != nil {
+		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
+		return accountVaild, err
+	}
+
+	if ctx.Path() == s.validAdd {
+		err = accountVaild.Validate()
+	} else if ctx.Path() == s.validSave {
+		err = accountVaild.ValidateUpdate()
+	} else if ctx.Path() == s.validPassword {
+		err = accountVaild.ValidatePassword()
+	} else {
+		log.Println("请求路径找不到对应的验证规则")
+		return accountVaild, errors.New("验证错误-未找到验证规则")
+	}
+
+	if err != nil {
+		log.Println("用户验证, error=", err)
+		return accountVaild, err
+	}
+
+	// 验证账号组
+	if ctx.Path() != s.validPassword {
+		accountGroup := comm.NewAccountGroup()
+		err = accountGroup.ValidRule(accountVaild.AccountGroup)
+		if err != nil {
+			log.Println("用户验证, error=", err)
+			return accountVaild, err
+		}
+	}
+	// xss
+	accountVaild.Account = html.EscapeString(accountVaild.Account)
+	accountVaild.Password = html.EscapeString(accountVaild.Password)
+	accountVaild.Name = html.EscapeString(accountVaild.Name)
+	accountVaild.Company = html.EscapeString(accountVaild.Company)
+	accountVaild.Position = html.EscapeString(accountVaild.Position)
+	accountVaild.Mobile = html.EscapeString(accountVaild.Mobile)
+	accountVaild.Telephone = html.EscapeString(accountVaild.Telephone)
+
+	return accountVaild, nil
+}
+
+// 验证密码
+func (s *projectAccountService) ValidRuleChangePassword(ctx iris.Context) (viewmodels.AccountPassword, error) {
+	accountVaild := viewmodels.AccountPassword{}
+	err := ctx.ReadJSON(&accountVaild)
+	if err != nil {
+		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
+		return accountVaild, err
+	}
+
+	err = accountVaild.ValidateChangePassword()
+
+	if err != nil {
+		log.Println("权限验证, error=", err)
+		return accountVaild, err
+	}
+
+	return accountVaild, nil
+}
+
+// 用户规则验证
+func (s *projectAccountService) ValidRulePermission(ctx iris.Context) (viewmodels.Permission, error) {
+	accountVaild := viewmodels.Permission{}
+	err := ctx.ReadJSON(&accountVaild)
+	if err != nil {
+		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
+		return accountVaild, err
+	}
+
+	err = accountVaild.Validate()
+
+	if err != nil {
+		log.Println("权限验证, error=", err)
+		return accountVaild, err
+	}
+
+	return accountVaild, nil
+}
+
+// 用户规则验证
+func (s *projectAccountService) ValidGetPermission(ctx iris.Context) (viewmodels.Permission, error) {
+	accountVaild := viewmodels.Permission{}
+	err := ctx.ReadForm(&accountVaild)
+	if err != nil {
+		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
+		return accountVaild, err
+	}
+
+	err = accountVaild.ValidateSinglePermission()
+
+	if err != nil {
+		log.Println("权限验证, error=", err)
+		return accountVaild, err
+	}
+
+	return accountVaild, nil
+}
+
+// 验证编辑用户
+func (s *projectAccountService) ValidRuleAccount(ctx iris.Context) (viewmodels.ProjectAccount, error) {
+	accountVaild := viewmodels.ProjectAccount{}
+	err := ctx.ReadJSON(&accountVaild)
+	if err != nil {
+		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
+		return accountVaild, err
+	}
+
+	err = accountVaild.ValidateAccount()
+
+	if err != nil {
+		log.Println("权限验证, error=", err)
+		return accountVaild, err
+	}
+
+	return accountVaild, nil
+}
+
+// 验证用户项目ID
+func (s *projectAccountService) ValidRuleProjectId(ctx iris.Context) (viewmodels.ProjectAccount, error) {
+	accountVaild := viewmodels.ProjectAccount{}
+	err := ctx.ReadForm(&accountVaild)
+	if err != nil {
+		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
+		return accountVaild, err
+	}
+
+	err = accountVaild.ValidateProjectId()
+
+	if err != nil {
+		log.Println("权限验证, error=", err)
+		return accountVaild, err
+	}
+
+	return accountVaild, nil
+}
+
+// 获得一个项目用户
+func (s *projectAccountService) Get(id int, projectId int) *viewmodels.ProjectAccount {
+	modelsAccount := s.dao.Get(id, projectId)
+	viewAccountData := viewmodels.ProjectAccount{}
+	if modelsAccount.Id == 0 {
+		viewAccountData.Id = "0"
+		return &viewAccountData
+	}
+
+	viewAccountData = comm.MakeProjectAccountVM(modelsAccount)
+	return &viewAccountData
+}
+
+// 获得项目下所有账号信息
+func (s *projectAccountService) GetAll(projectId int) []viewmodels.ProjectAccount {
+	accountList := s.dao.GetAll(projectId)
+	accountListVM := make([]viewmodels.ProjectAccount, 0)
+	for _, data := range accountList {
+		//if data.IsAdmin != 1 {
+		account := comm.MakeProjectAccountVM(&data)
+		accountListVM = append(accountListVM, account)
+		//}
+	}
+	return accountListVM
+}
+
+// 获得标段下的账号
+func (s *projectAccountService) GetBidAccount(bidsectionId int, projectId int, projectAccountId int, name string) []viewmodels.ProjectAccount {
+	// 1.获得标段账号ID
+	bidAccountData := s.bidAccountDao.GetBidAccount(bidsectionId, projectId)
+
+	// 组合账号ID集合
+	idList := []string{}
+	// 管理员账号-可能不必要
+	// idList = append(idList, strconv.Itoa(projectAccountId))
+	for _, item := range bidAccountData {
+		idList = append(idList, strconv.Itoa(item.AccountId))
+	}
+	inId := strings.Join(idList, ",")
+
+	// 获得账号信息
+	accountData := s.dao.GetInId(inId, name)
+
+	// 2.获得账号权限
+	permissionData := s.permissionAccountDao.GetBidsectionId(bidsectionId)
+
+	// 格式化账号数据
+	accountListVM := make([]viewmodels.ProjectAccount, 0)
+	for _, data := range accountData {
+		account := comm.MakeProjectAccountVM(&data)
+		for _, item := range permissionData {
+			if data.Id == item.AccountId {
+				account.ContractPermission = item.ContractPermission
+				account.QualityPermission = item.QualityPermission
+				account.SafePermission = item.SafePermission
+				break
+			}
+		}
+		accountListVM = append(accountListVM, account)
+	}
+
+	return accountListVM
+}
+
+// 检索 账号姓名单位手机
+func (s *projectAccountService) Search(name string, projectId int) []viewmodels.ProjectAccount {
+	accountList := s.dao.Search(name, projectId)
+	accountListVM := make([]viewmodels.ProjectAccount, 0)
+	for _, data := range accountList {
+		account := comm.MakeProjectAccountVM(&data)
+		accountListVM = append(accountListVM, account)
+	}
+	return accountListVM
+}
+
+// 新增账号-后台
+func (s *projectAccountService) AddBs(viewAccount viewmodels.ProjectAccount, projectId int) error {
+
+	// 验证该项目下是否有同名账号
+	accountValid := s.dao.GetAccount(viewAccount.Account)
+	if accountValid.Id != 0 {
+		return errors.New("已存在相同的账号")
+	}
+
+	account := models.CmProjectAccount{}
+	account.ProjectId = projectId
+	account.Account = viewAccount.Account
+	account.Password = comm.CreatePasswordSign(viewAccount.Password, viewAccount.Account)
+	account.Name = viewAccount.Name
+	account.Company = viewAccount.Company
+	account.Position = viewAccount.Position
+	account.Mobile = viewAccount.Mobile
+	account.Telephone = viewAccount.Telephone
+	account.Enable = 1
+	// account.IsAdmin = viewAccount.IsAdmin
+	account.CreateTime = time.Now()
+	err := s.dao.Add(&account)
+	return err
+}
+
+// 新增账号
+func (s *projectAccountService) Add(viewAccount viewmodels.ProjectAccount, projectId int) error {
+
+	// 验证该项目下是否有同名账号
+	accountValid := s.dao.GetAccount(viewAccount.Account)
+	if accountValid.Id != 0 {
+		return errors.New("已存在相同的账号")
+	}
+
+	account := models.CmProjectAccount{}
+	account.ProjectId = projectId
+	account.Account = viewAccount.Account
+	account.Password = comm.CreatePasswordSign(viewAccount.Password, viewAccount.Account)
+	account.Name = viewAccount.Name
+	account.Company = viewAccount.Company
+	account.Position = viewAccount.Position
+	account.Mobile = viewAccount.Mobile
+	account.Telephone = viewAccount.Telephone
+	account.AccountGroup = viewAccount.AccountGroup
+	account.Enable = 1
+	account.CreateTime = time.Now()
+	err := s.dao.Add(&account)
+	return err
+}
+
+// 保存用户信息
+func (s *projectAccountService) Save(viewAccount viewmodels.ProjectAccount, id int, projectId int) error {
+
+	account := models.CmProjectAccount{}
+	account.Id = id
+	account.ProjectId = projectId
+	account.Name = viewAccount.Name
+	account.Company = viewAccount.Company
+	account.Position = viewAccount.Position
+	account.Mobile = viewAccount.Mobile
+	account.Telephone = viewAccount.Telephone
+	account.AccountGroup = viewAccount.AccountGroup
+
+	err := s.dao.Update(&account, []string{"Name", "Company", "Position", "Telephone", "AccountGroup"})
+
+	return err
+}
+
+func (s *projectAccountService) SaveAccount(viewAccount viewmodels.ProjectAccount, id int, projectId int) error {
+	account := models.CmProjectAccount{}
+	account.Id = id
+	account.ProjectId = projectId
+	account.Name = viewAccount.Name
+	account.Company = viewAccount.Company
+	account.Position = viewAccount.Position
+	account.Telephone = viewAccount.Telephone
+	err := s.dao.Update(&account, []string{"Name", "Company", "Position", "Telephone"})
+
+	return err
+}
+
+// 设置启用/禁止
+func (s *projectAccountService) Enable(id int, projectId int, enable int) error {
+
+	account := models.CmProjectAccount{}
+	account.Id = id
+	account.ProjectId = projectId
+	account.Enable = enable
+	err := s.dao.Update(&account, []string{"Enable"})
+
+	return err
+}
+
+// 删除账号
+func (s *projectAccountService) Delete(id int, projectId int) error {
+	account := models.CmProjectAccount{}
+	account.Id = id
+	account.ProjectId = projectId
+	err := s.dao.Delete(&account)
+
+	return err
+}
+
+// 更改账号或者密码
+func (s *projectAccountService) ChangeAccount(id int, projectId int, viewAccount viewmodels.ProjectAccount) error {
+	// 1.是否修改账号
+	field := []string{"Password"}
+	account := models.CmProjectAccount{}
+	account.Id = id
+	account.ProjectId = projectId
+
+	// 2.修改密码
+	account.Password = comm.CreatePasswordSign(viewAccount.Password, viewAccount.Account)
+
+	accountData := s.dao.Get(id, projectId)
+	if accountData.Account != viewAccount.Account {
+		account.Account = viewAccount.Account
+		field = append(field, "Account")
+	}
+
+	// 3.发送短信-TODO
+	utils.SendSMS()
+
+	s.dao.Update(&account, field)
+
+	return nil
+}
+
+// 更改账号或者密码-后台
+func (s *projectAccountService) ChangeAccountBS(id int, projectId int, viewAccount viewmodels.ProjectAccount) error {
+	// 1.是否修改账号
+	field := []string{"Password"}
+	account := models.CmProjectAccount{}
+	account.Id = id
+	account.ProjectId = projectId
+
+	// 2.修改密码
+	account.Password = comm.CreatePasswordSign(viewAccount.Password, viewAccount.Account)
+
+	accountData := s.dao.Get(id, projectId)
+	if accountData.Account != viewAccount.Account {
+		account.Account = viewAccount.Account
+		field = append(field, "Account")
+	}
+
+	s.dao.Update(&account, field)
+
+	return nil
+}
+
+// 更换密码
+func (s *projectAccountService) ChangePassword(AccountData viewmodels.AccountPassword, projectId int, projectAccountId int) error {
+	// 1.获得账号
+	accountData := s.dao.Get(projectAccountId, projectId)
+	// 2.比对密码
+	password := comm.CreatePasswordSign(AccountData.Password, accountData.Account)
+
+	if accountData.Password != password {
+		return errors.New("原密码输入不正确")
+	}
+
+	// 3修改密码
+	field := []string{"Password"}
+	account := models.CmProjectAccount{}
+	account.Id = projectAccountId
+	account.ProjectId = projectId
+	account.Password = comm.CreatePasswordSign(AccountData.NewPassword, accountData.Account)
+
+	err := s.dao.Update(&account, field)
+	if err != nil {
+		return errors.New("密码更新失败")
+	}
+	return nil
+}
+
+func (s *projectAccountService) GetProjectInfo(id int) (viewmodels.ProjectInfo, error) {
+	projectInfo, err := s.dao.FindById(id)
+
+	return projectInfo, err
+}
+
+// 保存权限设置
+func (s *projectAccountService) SaveAuth(permission viewmodels.Permission, projectId int, bidsectionId int, accountId int) error {
+	// 1.构造权限字符串
+	// 1-1.合同权限
+	contractPermission := map[string]int{
+		"add":    permission.ContractAdd,
+		"delete": permission.ContractDelete,
+		"access": permission.ContractAccess,
+	}
+	contractPermissionByte, err := json.Marshal(contractPermission)
+	if err != nil {
+		return errors.New("合同权限解析失败")
+	}
+	contractPermissionStr := string(contractPermissionByte)
+	// 1.2 安全巡检权限
+	safePermission := map[string]int{
+		"add":    permission.SafeAdd,
+		"delete": permission.SafeDelete,
+		"access": permission.SafeAccess,
+	}
+	safePermissionByte, err := json.Marshal(safePermission)
+	if err != nil {
+		return errors.New("合同权限解析失败")
+	}
+	safePermissionStr := string(safePermissionByte)
+	// 1.3 质量巡检权限
+	qualityPermission := map[string]int{
+		"add":    permission.QualityAdd,
+		"delete": permission.QualityDelete,
+		"access": permission.QualityAccess,
+	}
+	qualityPermissionByte, err := json.Marshal(qualityPermission)
+	if err != nil {
+		return errors.New("合同权限解析失败")
+	}
+	qualityPermissionStr := string(qualityPermissionByte)
+
+	// 2.保存权限
+	permissionAccount := models.CmPermissionAccount{}
+	permissionAccount.ProjectId = projectId
+	permissionAccount.BidsectionId = bidsectionId
+	permissionAccount.AccountId = accountId
+	permissionAccount.ContractPermission = contractPermissionStr
+	permissionAccount.SafePermission = safePermissionStr
+	permissionAccount.QualityPermission = qualityPermissionStr
+
+	err = s.permissionAccountDao.Update(&permissionAccount, []string{"ContractPermission", "SafePermission", "QualityPermission"})
+	return err
+}

+ 63 - 0
services/project_message_service.go

@@ -0,0 +1,63 @@
+/*
+ * @description: 项目相关数据处理
+ * @Author: CP
+ * @Date: 2020-09-04 14:42:27
+ * @FilePath: \construction_management\services\project_message_service.go
+ */
+package services
+
+import (
+	"strconv"
+
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/web/viewmodels"
+)
+
+//定义项目Service接口
+type ProjectMessageService interface {
+	GetAll(projectId int, accountId int) []*viewmodels.ProjectMessage
+}
+
+//返回service操作类
+type projectMessageService struct {
+	projectMessagedao *dao.ProjectMessageDao
+}
+
+//创建项目service
+func NewProjectMessageService() ProjectMessageService {
+	return &projectMessageService{
+		projectMessagedao: dao.NewProjectMessageDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 获得需要关注人
+func (s *projectMessageService) GetAll(projectId int, accountId int) []*viewmodels.ProjectMessage {
+	dataList := s.projectMessagedao.GetAll(projectId, accountId)
+
+	projectMessageVM := make([]*viewmodels.ProjectMessage, 0)
+	for _, item := range dataList {
+		viewProjectMessage := &viewmodels.ProjectMessage{}
+		id, _ := comm.AesEncrypt(strconv.Itoa(item.Id), conf.SignSecret)
+		projectId, _ := comm.AesEncrypt(strconv.Itoa(item.ProjectId), conf.SignSecret)
+		bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(item.BidsectionId), conf.SignSecret)
+		accountId, _ := comm.AesEncrypt(strconv.Itoa(item.AccountId), conf.SignSecret)
+		dataId, _ := comm.AesEncrypt(strconv.Itoa(item.DataId), conf.SignSecret)
+
+		viewProjectMessage.Id = id
+		viewProjectMessage.ProjectId = projectId
+		viewProjectMessage.BidsectionId = bidsectionId
+		viewProjectMessage.AccountId = accountId
+		viewProjectMessage.DataType = item.DataType
+		viewProjectMessage.DataId = dataId
+		viewProjectMessage.Title = item.Title
+		viewProjectMessage.Content = item.Content
+		viewProjectMessage.CreateTime = item.CreateTime.Format(conf.SysTimeform)
+
+		projectMessageVM = append(projectMessageVM, viewProjectMessage)
+	}
+	// data, err := s.permissionDao.GetPermissionWithAccountId(accountId, bidsectionId)
+	return projectMessageVM
+}

+ 280 - 0
services/project_service.go

@@ -0,0 +1,280 @@
+/*
+ * @description: 项目相关数据处理
+ * @Author: CP
+ * @Date: 2020-09-04 14:42:27
+ * @FilePath: \construction_management\services\project_service.go
+ */
+package services
+
+import (
+	"errors"
+	"html"
+	"log"
+	"strconv"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//定义项目Service接口
+type ProjectService interface {
+	//ValidManager(code string, account string, password string) error
+	ValidRule(iris.Context) (viewmodels.Project, error)
+	ValidRulePage(iris.Context) (viewmodels.ProjectPage, error)
+	ValidRuleId(ctx iris.Context) (viewmodels.Project, error)
+
+	Get(projectId int) (*viewmodels.Project, error)
+	GetList(page int, size int) []viewmodels.Project
+	GetName(code string) []viewmodels.Project
+	Save(projectId int, projectVM viewmodels.Project) error
+	Add(projectVM viewmodels.Project) error
+	SaveBs(projectVM viewmodels.Project, id int) error
+}
+
+//返回service操作类
+type projectService struct {
+	dao       *dao.ProjectDao
+	validSave string
+}
+
+//创建项目service
+func NewProjectService() ProjectService {
+	return &projectService{
+		dao:       dao.NewProjectDao(datasource.InstanceDbMaster()),
+		validSave: "/api/projectSetting/project/save",
+	}
+}
+
+func (s *projectService) ValidRulePage(ctx iris.Context) (viewmodels.ProjectPage, error) {
+	projectVaild := viewmodels.ProjectPage{}
+	err := ctx.ReadForm(&projectVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return projectVaild, err
+	}
+
+	err = projectVaild.ValidatePage()
+	if err != nil {
+		log.Println("参数验证错误, error=", err)
+		return projectVaild, err
+	}
+
+	return projectVaild, nil
+}
+
+// 验证项目
+func (s *projectService) ValidRuleId(ctx iris.Context) (viewmodels.Project, error) {
+	projectVaild := viewmodels.Project{}
+	err := ctx.ReadForm(&projectVaild)
+	if err != nil {
+		log.Println("ReadForm转换异常, error=", err)
+		return projectVaild, err
+	}
+
+	err = projectVaild.ValidateId()
+	if err != nil {
+		log.Println("验证项目, error=", err)
+		return projectVaild, err
+	}
+	return projectVaild, nil
+}
+
+// 验证项目项的内容
+func (s *projectService) ValidRule(ctx iris.Context) (viewmodels.Project, error) {
+	projectVaild := viewmodels.Project{}
+	var err error
+	if ctx.Method() == "POST" {
+		err = ctx.ReadJSON(&projectVaild)
+		if err != nil {
+			log.Println("project-ValidRule-ReadForm转换异常, error=", err)
+			return projectVaild, err
+		}
+	} else {
+		err = ctx.ReadForm(&projectVaild)
+		if err != nil {
+			log.Println("project-ValidRule-ReadForm转换异常, error=", err)
+			return projectVaild, err
+		}
+	}
+
+	if ctx.Path() == s.validSave {
+		err = projectVaild.ValidateName()
+	} else {
+		err = projectVaild.Validate()
+	}
+
+	if err != nil {
+		log.Println("项目信息验证, error=", err)
+		return projectVaild, err
+	}
+
+	projectVaild.Code = html.EscapeString(projectVaild.Code)
+	projectVaild.Name = html.EscapeString(projectVaild.Name)
+
+	return projectVaild, nil
+}
+
+// ID获得项目信息-TODO
+func (s *projectService) Get(projectId int) (*viewmodels.Project, error) {
+	data, err := s.dao.FindById(projectId)
+	if err != nil {
+		return nil, errors.New("获得项目详情出错")
+	}
+	project := makeProjectVM(data)
+
+	return &project, nil
+}
+
+// 获得一组项目信息 -项目编号
+func (s *projectService) GetList(page int, size int) []viewmodels.Project {
+	if size > 100 {
+		size = 100
+	}
+	datalist := make([]viewmodels.Project, 0)
+	projectData := s.dao.GetPage(page, size)
+	for _, data := range projectData {
+		projectVM := makeProjectVM(&data)
+		datalist = append(datalist, projectVM)
+	}
+	return datalist
+}
+
+// 获得项目名称
+func (s *projectService) GetName(code string) []viewmodels.Project {
+	datalist := make([]viewmodels.Project, 0)
+	if code != "" {
+		projectData := s.dao.GetListByCode(code)
+		for _, data := range projectData {
+			projectVM := makeProjectNameVM(&data)
+			datalist = append(datalist, projectVM)
+		}
+		return datalist
+	}
+	return datalist
+}
+
+// 保存项目信息
+func (s *projectService) Save(id int, projectVM viewmodels.Project) error {
+	project := models.CmProject{}
+	project.Id = id
+	project.Name = projectVM.Name
+
+	err := s.dao.Update(&project, []string{"Name"})
+
+	return err
+}
+
+// 新增项目
+func (s *projectService) Add(projectVM viewmodels.Project) error {
+	project := &models.CmProject{}
+	project.Name = projectVM.Name
+	project.Code = projectVM.Code
+	project.CategoryId = projectVM.CategoryId
+	project.Category = projectVM.Category
+	project.StaffId = projectVM.StaffId
+	project.StaffName = projectVM.StaffName
+	project.CreateTime = time.Now()
+	project.CreateName = projectVM.CreateName
+	project.CreateCategory = projectVM.CreateCategory
+	project.Remark = projectVM.Remark
+
+	err := s.dao.Add(project)
+	return err
+}
+
+// 更新项目-后台
+func (s *projectService) SaveBs(projectVM viewmodels.Project, id int) error {
+	project := &models.CmProject{}
+	project.Id = id
+	project.Name = projectVM.Name
+	project.InsideCategoryid = projectVM.InsideCategoryId
+	project.InsideCategory = projectVM.InsideCategory
+
+	project.CategoryId = projectVM.CategoryId
+	project.Category = projectVM.Category
+
+	project.StaffId = projectVM.StaffId
+	project.StaffName = projectVM.StaffName
+
+	project.Remark = projectVM.Remark
+
+	err := s.dao.Update(project, []string{"Name", "InsideCategoryid", "InsideCategory", "CategoryId", "Category", "StaffId", "StaffName", "Remark"})
+
+	return err
+}
+
+// 构造视图层models
+func makeProjectVM(projectCM *models.CmProject) viewmodels.Project {
+	projectVM := viewmodels.Project{}
+	id, _ := comm.AesEncrypt(strconv.Itoa(projectCM.Id), conf.SignSecret)
+	userId, _ := comm.AesEncrypt(strconv.Itoa(projectCM.UserId), conf.SignSecret)
+
+	projectVM.Id = id
+	projectVM.Code = projectCM.Code
+	projectVM.Name = projectCM.Name
+	projectVM.Category = projectCM.Category
+	projectVM.StaffName = projectCM.StaffName
+	projectVM.UserId = userId
+	projectVM.UserAccount = projectCM.UserAccount
+	if !projectCM.CreateTime.IsZero() {
+		projectVM.CreateTime = projectCM.CreateTime.Format(conf.SysTimeform)
+	}
+
+	return projectVM
+}
+
+func makeProjectNameVM(projectCM *models.CmProject) viewmodels.Project {
+	projectVM := viewmodels.Project{}
+	projectVM.Code = projectCM.Code
+	projectVM.Name = projectCM.Name
+	return projectVM
+}
+
+// 获得单个项目信息-ID 编号
+// func (s *projectService) Get(projectVM *viewmodels.Project) {
+// 	projectCM := models.CmProject{}
+
+// 	// 项目ID或编号
+// 	if projectVM.Id == "" && projectVM.Code == "" {
+// 		projectVM.Id = "0"
+// 		return
+// 		//return errors.New("项目ID或者项目编号不存在")
+// 	}
+
+// 	if projectVM.Id != "" {
+// 		projectId, err := comm.AesDecrypt(projectVM.Id, conf.SignSecret)
+// 		if err != nil {
+// 			projectVM.Id = "0"
+// 			return
+// 		}
+// 		projectIdInt, err := strconv.Atoi(projectId)
+// 		if err != nil {
+// 			projectVM.Id = "0"
+// 			return
+// 		}
+// 		if projectIdInt != 0 {
+// 			projectCM.Id = projectIdInt
+// 		}
+// 	} else if projectVM.Code != "" {
+// 		projectCM.Code = projectVM.Code
+// 	} else {
+// 		projectVM.Id = "0"
+// 		return
+// 	}
+
+// 	s.dao.Get(&projectCM)
+// 	if projectCM.Id != 0 {
+// 		// 项目信息补充完整
+// 		projectB := makeProjectVM(&projectCM)
+// 		projectVM = &projectB
+// 	} else {
+// 		projectVM.Id = "0"
+// 		return
+// 	}
+// }

+ 150 - 0
services/quality_audit.service.go

@@ -0,0 +1,150 @@
+/*
+ * @description: 安全巡检审批相关
+ * @Author: LanJianRong
+ * @Date: 2020-12-18
+ * @FilePath: \construction_management\web\api\safe_rpc_api.go
+ */
+package services
+
+import (
+	"errors"
+	"log"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/web/viewmodels"
+)
+
+type QualityAuditService interface {
+	ValidRule(ctx iris.Context) (viewmodels.QualityAudit, error)
+	ValidStart(ctx iris.Context) (viewmodels.QualityAuditStart, error)
+	// AddAuditor(safeId int, bId int, auditId int, times int) error
+	CloseAudit(id int, opinion string, curUid int, saveId int) error
+	BackAudit(id int, opinion string, curUid int, saveId int, auditId int) error
+	PassAudit(id int, uid int, auditId int, opinion string, rectifiedInfo string) error
+	StartAudit(safeId int, bidsectionId int, auditors []int, reAuditors []int, uid int, pid int, inspection string, inspectionDetail string, demand string, createTime time.Time) error
+}
+
+type qualityAuditService struct {
+	validAdd        string
+	validPass       string
+	validClose      string
+	validBack       string
+	daoQualityAudit *dao.QualityAuditDao
+	daoQuality      *dao.QualityDao
+	daoApprover     *dao.ApproverDao
+}
+
+//创建项目用户service
+func NewQualityAuditService() QualityAuditService {
+	return &qualityAuditService{
+		validBack:       "/api/quality_audit/back",
+		validAdd:        "/api/quality_audit/add",
+		validClose:      "/api/quality_audit/close",
+		validPass:       "/api/quality_audit/pass",
+		daoQualityAudit: dao.NewQualityAuditDao(datasource.InstanceDbMaster()),
+		daoQuality:      dao.NewQualityDao(datasource.InstanceDbMaster()),
+		daoApprover:     dao.NewApproverDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 关闭审批流程
+func (s *qualityAuditService) CloseAudit(id int, opinion string, curUid int, saveId int) error {
+	err := s.daoApprover.CloseHandler("quality", id, opinion, curUid, saveId)
+	return err
+}
+
+// 审批退回
+func (s *qualityAuditService) BackAudit(id int, opinion string, curUid int, saveId int, auditId int) error {
+	auditor, err := s.daoApprover.FindApproverById(id)
+	if auditor.AuditId != curUid {
+		return errors.New("该用户没有审批权限")
+	}
+	safe := s.daoQuality.FindById(saveId)
+
+	// 退回到了检查人
+	if auditId == 0 {
+		// 初始化审批流程
+		err = s.daoApprover.InitStatus("quality", auditor.BidsectionId, auditor.DataType, auditor.DataId, auditor.AuditId, safe.Times, auditor.Progress+1, opinion)
+	} else {
+		// 退回到审批流程中的某一个人
+		err = s.daoApprover.BackHandlerWithId("quality", auditId, auditor.AuditId, safe.Times, auditor.Progress+1, opinion)
+	}
+	return err
+
+}
+
+// 审批通过
+func (s *qualityAuditService) PassAudit(id int, uid int, auditId int, opinion string, rectifiedInfo string) error {
+	err := s.daoApprover.PassHandler("quality", id, uid, auditId, opinion, rectifiedInfo)
+	return err
+}
+
+func (s *qualityAuditService) StartAudit(qualityId int, bidsectionId int, auditors []int, reAuditors []int, uid int, pid int, inspection string, inspectionDetail string, demand string, createTime time.Time) error {
+	quality := s.daoQuality.FindById(qualityId)
+	if quality.Uid != uid {
+		return errors.New("该用户没有操作权限")
+	}
+	// 清除可能有的旧的审批流程
+	err := s.daoApprover.DeleteOldAuditors(bidsectionId, 1, qualityId)
+	if err != nil {
+		return err
+	}
+	// 增加审批日志
+	err = s.daoQualityAudit.AddAuditRecord(qualityId, bidsectionId, uid, quality.Times, 0, 0, "", "")
+	if err != nil {
+		return err
+	}
+	// 改变安全巡检表的状态
+	err = s.daoQuality.ChangeStatus(qualityId, 1, inspection, inspectionDetail, demand, createTime)
+	if err != nil {
+		return err
+	}
+	// 创建审批流程
+	err = s.daoApprover.InsertData(uid, bidsectionId, pid, 1, qualityId, auditors, reAuditors)
+	if err != nil {
+		return err
+	}
+	return err
+}
+
+// 规则校验
+func (s *qualityAuditService) ValidRule(ctx iris.Context) (viewmodels.QualityAudit, error) {
+	qualityAuditVaild := viewmodels.QualityAudit{}
+	if ctx.Method() == "POST" {
+		err := ctx.ReadJSON(&qualityAuditVaild)
+		if err != nil {
+			log.Println("quality-ValidRule-ReadJson转换异常, error=", err)
+			return qualityAuditVaild, err
+		}
+		if ctx.Path() == s.validAdd {
+			err = qualityAuditVaild.ValidateQualityAddAuditor()
+			return qualityAuditVaild, err
+		} else if ctx.Path() == s.validClose {
+			err = qualityAuditVaild.ValidateQualityClose()
+			return qualityAuditVaild, err
+		} else if ctx.Path() == s.validBack {
+			err = qualityAuditVaild.ValidateQualityBack()
+			return qualityAuditVaild, err
+		} else if ctx.Path() == s.validPass {
+			err = qualityAuditVaild.ValidateQualityPass()
+			return qualityAuditVaild, err
+		}
+		return qualityAuditVaild, err
+	}
+	return qualityAuditVaild, nil
+}
+
+// 校验审批开始
+func (s *qualityAuditService) ValidStart(ctx iris.Context) (viewmodels.QualityAuditStart, error) {
+	startAuditValid := viewmodels.QualityAuditStart{}
+	err := ctx.ReadJSON(&startAuditValid)
+	if err != nil {
+		log.Println("safe-ValidRule-ReadJson转换异常, error=", err)
+		return startAuditValid, err
+	}
+	err = startAuditValid.ValidateQualityStart()
+	return startAuditValid, err
+}

+ 374 - 0
services/quality_service.go

@@ -0,0 +1,374 @@
+package services
+
+import (
+	"fmt"
+	"log"
+	"strconv"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"github.com/shopspring/decimal"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+type QualityService interface {
+	Get(id int, pid int, pageNo int, pageSize int) ([]viewmodels.QualityList, int64)
+	Post(data models.CmQuality) error
+	Del(id int) error
+	GetDetail(id int, pid int) viewmodels.QualityDetail
+	GetSurvey(projectId int, bidsectionId int) map[string]interface{}
+	GetPending(projectId int, projectAccountId int) []viewmodels.Quality
+	ValidRule(ctx iris.Context) (viewmodels.Quality, error)
+}
+
+// //返回service操作类
+type qualityService struct {
+	daoQuality        *dao.QualityDao
+	daoQualityAudit   *dao.QualityAuditDao
+	daoProjectAccount *dao.ProjectAccountDao
+	daoAnnex          *dao.AnnexDao
+	daoRule           *dao.RuleDao
+	daoApprover       *dao.ApproverDao
+	validDetail       string
+}
+
+//创建项目用户service
+func NewQualityService() QualityService {
+	return &qualityService{
+		validDetail:       "/api/quality/detail",
+		daoQuality:        dao.NewQualityDao(datasource.InstanceDbMaster()),
+		daoAnnex:          dao.NewAnnexDao(datasource.InstanceDbMaster()),
+		daoQualityAudit:   dao.NewQualityAuditDao(datasource.InstanceDbMaster()),
+		daoProjectAccount: dao.NewProjectAccountDao(datasource.InstanceDbMaster()),
+		daoApprover:       dao.NewApproverDao(datasource.InstanceDbMaster()),
+	}
+}
+func (s *qualityService) Get(id int, pid int, pageNo int, pageSize int) ([]viewmodels.QualityList, int64) {
+	datalist, total := s.daoQuality.GetListByBid(id, pageNo, pageSize)
+	qualityList := make([]viewmodels.QualityList, 0)
+	for _, item := range datalist {
+		qualityVM := viewmodels.QualityList{}
+		qualityVM.Code = item.Code
+		account := s.daoProjectAccount.Get(item.Uid, pid)
+		qualityVM.AuditName = account.Name
+		qualityVM.CreateTime = item.CreateTime.Format(conf.SysTimeform)
+		qualityVM.Demand = item.Demand
+		id, _ := comm.AesEncrypt(strconv.Itoa(item.Id), conf.SignSecret)
+		qualityVM.Id = id
+		qualityVM.Inspection = item.Inspection
+		qualityVM.InspectionDetail = item.InspectionDetail
+		qualityVM.Position = item.Position
+		qualityVM.Status = item.Status
+		counts, _ := s.daoAnnex.GetCount(3, item.Id)
+		qualityVM.FileCounts = counts
+		qualityList = append(qualityList, qualityVM)
+	}
+	return qualityList, total
+}
+
+// post请求,插入单条数据
+func (s *qualityService) Post(data models.CmQuality) error {
+	// has := s.daoQuality.FindByCode(data.Code)
+	// if has {
+	// 	return errors.New("该编号已存在!")
+	// }
+	// Inserted, err := s.daoQuality.InsertRecord(data)
+	// if Inserted == true {
+	// 	return nil
+	// }
+	err := s.daoQuality.CreateQuality(data)
+	return err
+}
+
+// delete请求,删除数据
+func (s *qualityService) Del(id int) error {
+	err := s.daoQuality.DeleteRecord(id)
+	return err
+}
+
+// 详情页数据拼装
+func (s *qualityService) GetDetail(id int, pid int) viewmodels.QualityDetail {
+
+	qualityData := s.daoQuality.FindById(id)
+	qualityId, _ := comm.AesEncrypt(strconv.Itoa(qualityData.Id), conf.SignSecret)
+	bid, _ := comm.AesEncrypt(strconv.Itoa(qualityData.BidsectionId), conf.SignSecret)
+	uid, _ := comm.AesEncrypt(strconv.Itoa(qualityData.Uid), conf.SignSecret)
+	data := viewmodels.QualityDetail{}
+	data.Id = qualityId
+	data.BidsectionId = bid
+	data.Uid = uid
+	data.Code = qualityData.Code
+	data.Inspection = qualityData.Inspection
+	data.InspectionDetail = qualityData.InspectionDetail
+	data.Demand = qualityData.Demand
+	account := s.daoProjectAccount.Get(qualityData.Uid, pid)
+	data.AuditName = account.Name
+	data.CreateTime = qualityData.CreateTime
+	data.Times = qualityData.Times
+	data.Status = qualityData.Status
+	fileList, total := s.daoAnnex.GetList(2, qualityData.Id, 1, conf.PageSize)
+	// 加密id
+	fileArr := make([]viewmodels.AnnexListView, 0)
+	for _, item := range fileList {
+		fileListVM := viewmodels.AnnexListView{}
+		fileId, _ := comm.AesEncrypt(item.Id, conf.SignSecret)
+		fileListVM.Id = fileId
+		uid, _ := comm.AesEncrypt(item.AccountId, conf.SignSecret)
+		fileListVM.AccountId = uid
+		fileListVM.AccountName = item.AccountName
+		fileListVM.CreateTime = item.CreateTime
+		fileListVM.FileName = item.FileName
+		fileListVM.FilePath = item.FilePath
+		fileArr = append(fileArr, fileListVM)
+	}
+	fileVM := viewmodels.FileStruct{}
+	fileVM.FileList = fileArr
+	fileVM.Total = total
+	data.File = fileVM
+	auditors := s.daoApprover.GetAuditorsWithOwner(qualityData.BidsectionId, int(1), qualityData.Id, account.Id)
+	encryptAuditors := make([]viewmodels.Auditors, 0)
+	for _, item := range auditors {
+		auditorVM := viewmodels.Auditors{}
+		if item.Id != "" {
+			id, _ := comm.AesEncrypt(item.Id, conf.SignSecret)
+			auditorVM.Id = id
+		}
+		auditId, _ := comm.AesEncrypt(item.AuditId, conf.SignSecret)
+		auditorVM.AuditId = auditId
+		auditorVM.Name = item.Name
+		auditorVM.Position = item.Position
+		auditorVM.Mobile = item.Mobile
+		auditorVM.AuditOrder = item.AuditOrder
+		auditorVM.AccountGroup = item.AccountGroup
+		auditorVM.Progress = item.Progress
+		auditorVM.Company = item.Company
+		auditorVM.Status = item.Status
+		encryptAuditors = append(encryptAuditors, auditorVM)
+	}
+	auditHistory := s.daoQualityAudit.GetAuditHistory(qualityData.Id, qualityData.Times)
+	data.AuditHistory = auditHistory
+	// 整改单
+	rectifiedInfo, _ := s.daoQualityAudit.GetLastedOrder(qualityData.Id)
+	data.RectifiedInfo = rectifiedInfo
+
+	// 最新审批人信息
+	latestAuditor := s.daoApprover.GetLastedAuditor(qualityData.BidsectionId, 1, qualityData.Id)
+	data.LatestdAuditor = latestAuditor
+	data.Auditors = encryptAuditors
+
+	return data
+}
+
+// 质量概况
+func (s *qualityService) GetSurvey(projectId int, bidsectionId int) map[string]interface{} {
+	// 1.获得安全巡检
+	year := time.Now().Year()
+	qualityList := s.daoQuality.GetTypeYear(bidsectionId, year)
+	// 2.初始化
+	rectifylist := make([]viewmodels.QualitySurveyList, 0)
+	rectifyTotal := 0
+	approvalTotal := 0
+	rectifyedTotal := 0
+
+	columnarData := make([]map[string]interface{}, 0)
+	lineData := columnarData
+	for i := 1; i <= 12; i++ {
+		item := map[string]interface{}{
+			"name":  "rectifyed",
+			"month": fmt.Sprintf("%d-%02d", year, i),
+			"count": 0,
+		}
+		columnarData = append(columnarData, item)
+		item = map[string]interface{}{
+			"name":  "submit",
+			"month": fmt.Sprintf("%d-%02d", year, i),
+			"count": 0,
+		}
+		columnarData = append(columnarData, item)
+		item = map[string]interface{}{
+			"month":      fmt.Sprintf("%d-%02d", year, i),
+			"percentage": 0,
+		}
+		lineData = append(lineData, item)
+
+	}
+
+	// 3.当年数据初始化
+	submitData := map[string]int{
+		fmt.Sprintf("%d-01", year): 0,
+		fmt.Sprintf("%d-02", year): 0,
+		fmt.Sprintf("%d-03", year): 0,
+		fmt.Sprintf("%d-04", year): 0,
+		fmt.Sprintf("%d-05", year): 0,
+		fmt.Sprintf("%d-06", year): 0,
+		fmt.Sprintf("%d-07", year): 0,
+		fmt.Sprintf("%d-08", year): 0,
+		fmt.Sprintf("%d-09", year): 0,
+		fmt.Sprintf("%d-10", year): 0,
+		fmt.Sprintf("%d-11", year): 0,
+		fmt.Sprintf("%d-12", year): 0,
+	}
+	rectifyedData := map[string]int{
+		fmt.Sprintf("%d-01", year): 0,
+		fmt.Sprintf("%d-02", year): 0,
+		fmt.Sprintf("%d-03", year): 0,
+		fmt.Sprintf("%d-04", year): 0,
+		fmt.Sprintf("%d-05", year): 0,
+		fmt.Sprintf("%d-06", year): 0,
+		fmt.Sprintf("%d-07", year): 0,
+		fmt.Sprintf("%d-08", year): 0,
+		fmt.Sprintf("%d-09", year): 0,
+		fmt.Sprintf("%d-10", year): 0,
+		fmt.Sprintf("%d-11", year): 0,
+		fmt.Sprintf("%d-12", year): 0,
+	}
+	for _, item := range qualityList {
+		if item.Status == 2 {
+			id, _ := comm.AesEncrypt(item.Id, conf.SignSecret)
+			item.Id = id
+			rectifylist = append(rectifylist, item)
+			rectifyTotal++
+		}
+
+		approvalTotal++
+		if item.Status == 4 {
+			rectifyedTotal++
+		}
+
+		index := item.CreateTime.Format(conf.SysTimeformMonth)
+		submitData[index] = submitData[index] + 1
+
+		if item.Status == 4 {
+			rectifyedData[index] = rectifyedData[index] + 1
+		}
+
+	}
+
+	for index, columnar := range columnarData {
+
+		if columnar["name"] == "rectifyed" {
+			columnarData[index]["count"] = rectifyedData[columnar["month"].(string)]
+		}
+		if columnar["name"] == "submit" {
+			columnarData[index]["count"] = submitData[columnar["month"].(string)]
+		}
+	}
+
+	for index, line := range lineData {
+		rectifyedCount := 0
+		submitCount := 0
+		for _, columnar := range columnarData {
+			if line["month"] == columnar["month"] {
+				if columnar["name"] == "rectifyed" {
+					rectifyedCount = columnar["count"].(int)
+				}
+				if columnar["name"] == "submit" {
+					submitCount = columnar["count"].(int)
+				}
+			}
+		}
+		lineData[index]["percentage"] = 0.00
+		if rectifyedCount != 0 && submitCount != 0 {
+			decimal.DivisionPrecision = 2
+			percentage, _ := decimal.NewFromFloat(float64(rectifyedCount)).Div(decimal.NewFromFloat(float64(submitCount))).Float64()
+			lineData[index]["percentage"] = percentage * 100
+		}
+	}
+
+	// 整改占总数比例 - 完成整改/提交巡检
+	surveryData := map[string]interface{}{
+		"rectifylist":    rectifylist,
+		"rectifyTotal":   rectifyTotal,
+		"approvalTotal":  approvalTotal,
+		"rectifyedTotal": rectifyedTotal,
+		"columnarData":   columnarData,
+		"lineData":       lineData,
+	}
+
+	return surveryData
+}
+
+// 获得账号下需要审批的巡检
+func (s *qualityService) GetPending(projectId int, projectAccountId int) []viewmodels.Quality {
+
+	data := s.daoQuality.GetStatusByProjectAndAccount(projectId, projectAccountId, 1)
+
+	safeList := make([]viewmodels.Quality, 0)
+	for _, item := range data {
+		safeVM := viewmodels.Quality{}
+
+		Id, _ := comm.AesEncrypt(strconv.Itoa(item.Id), conf.SignSecret)
+		BidsectionId, _ := comm.AesEncrypt(strconv.Itoa(item.BidsectionId), conf.SignSecret)
+		// AuditId, _ := comm.AesEncrypt(item.AuditId, conf.SignSecret)
+		Uid, _ := comm.AesEncrypt(strconv.Itoa(item.Uid), conf.SignSecret)
+		// ProjectId, _ := comm.AesEncrypt(strconv.Itoa(item.ProjectId), conf.SignSecret)
+
+		safeVM.Id = Id
+		safeVM.BidsectionId = BidsectionId
+		safeVM.Uid = Uid
+		safeVM.Code = item.Code
+		safeVM.CreateTime = item.CreateTime.Format(conf.SysTimeform)
+		safeVM.EndTime = item.EndTime.Format(conf.SysTimeform)
+		safeVM.Position = item.Position
+		safeVM.Inspection = item.Inspection
+		safeVM.InspectionDetail = item.InspectionDetail
+		safeVM.Demand = item.Demand
+		safeVM.Status = item.Status
+		safeList = append(safeList, safeVM)
+	}
+
+	return safeList
+}
+
+// 规则校验
+func (s *qualityService) ValidRule(ctx iris.Context) (viewmodels.Quality, error) {
+	qualityVaild := viewmodels.Quality{}
+	// fmt.Println("---------------------------safeVaild", safeVaild)
+	if ctx.Method() == "GET" {
+		err := ctx.ReadForm(&qualityVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadForm转换异常, error=", err)
+			return qualityVaild, err
+		}
+		if ctx.Path() == s.validDetail {
+			// 一样要传id,所以用delete的方法判断
+			err = qualityVaild.ValidateQualityDelete()
+		} else {
+			err = qualityVaild.ValidateQualityList()
+		}
+		return qualityVaild, err
+	}
+
+	if ctx.Method() == "POST" {
+		err := ctx.ReadJSON(&qualityVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadJson转换异常, error=", err)
+			return qualityVaild, err
+		}
+		err = qualityVaild.ValidateQualityCreate()
+		return qualityVaild, err
+		// if ctx.Path() == s.validCreate {
+		// }
+		// if ctx.Path() == s.validFile {
+		// 	err = safeVaild.ValidateFile()
+		// 	return safeVaild, err
+		// }
+	}
+
+	if ctx.Method() == "PUT" {
+		err := ctx.ReadForm(&qualityVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadForm转换异常, error=", err)
+			return qualityVaild, err
+		}
+		err = qualityVaild.ValidateQualityDelete()
+		return qualityVaild, err
+	}
+	return qualityVaild, nil
+
+}

+ 65 - 0
services/rpc_service.go

@@ -0,0 +1,65 @@
+/*
+ * @description: rpc services 实例
+ * @Author: CP
+ * @Date: 2020-11-12 22:53:14
+ * @FilePath: \construction_management\services\rpc_service.go
+ */
+package services
+
+import (
+	"context"
+	"log"
+	"time"
+
+	safe "go.mod/proto"
+	"google.golang.org/grpc"
+)
+
+type RpcService interface {
+	Test(RpcConnect *grpc.ClientConn)
+}
+
+//返回service操作类
+type rpcService struct {
+	// address     string
+	// defaultName string
+	//Ctx iris.Context
+	//rpcClient *grpc.ClientConn
+	// 定义proto 接口文件- /proto/rpc.proto
+	// pb.UnimplementedGreeterServer
+}
+
+//创建项目用户service
+func NewRpcService() RpcService {
+	return &rpcService{
+		// address:     "192.168.1.26:5001",
+		//rpcClient: GetGrpcClient(ctx),
+	}
+}
+
+// func GetGrpcClient(ctx iris.Context) *grpc.ClientConn {
+// 	// // 启动grpc客户端,连接grpc服务端
+// 	// conn, err := grpc.Dial(address, grpc.WithInsecure())
+// 	// if err != nil {
+// 	// 	log.Fatalf("did not connect: %v", err)
+// 	// }
+// 	// // defer conn.Close()
+// 	// return conn
+// }
+
+// 具体的业务逻辑
+func (s *rpcService) Test(RpcConnect *grpc.ClientConn) {
+	// 1.结束后关闭
+	//defer s.rpcClient.Close()
+
+	rpcClient := safe.NewGreeterClient(RpcConnect)
+	// c := pb.NewGreeterClient(conn)
+
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	defer cancel()
+	r, err := rpcClient.SayHello(ctx, &safe.HelloRequest{Name: "caipin"})
+	if err != nil {
+		log.Fatalf("could not greet: %v", err)
+	}
+	log.Printf("Greeting: %s", r.GetMessage())
+}

+ 156 - 0
services/rule_service.go

@@ -0,0 +1,156 @@
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"strconv"
+
+	"go.mod/web/utils"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/web/viewmodels"
+)
+
+type RuleService interface {
+	Get(pid int, id int) viewmodels.ViewRule
+	Post(pid int, id int, key string, value string) error
+	AutoCode(bid int, pid int, codeType string) (string, string, error)
+	ValidRule(ctx iris.Context) (viewmodels.ValidField, error)
+}
+
+// //返回service操作类
+type ruleService struct {
+	daoRule         *dao.RuleDao
+	daoSafe         *dao.SafeDao
+	daoQuality      *dao.QualityDao
+	daoContract     *dao.ContractDao
+	daoContractPaid *dao.ContractPaidDao
+	validAutoPath   string
+}
+
+//创建项目用户service
+func NewRuleService() RuleService {
+	return &ruleService{
+		validAutoPath: "/api/rule/auto",
+		daoRule:       dao.NewRuleDao(datasource.InstanceDbMaster()),
+		daoSafe:       dao.NewSafeDao(datasource.InstanceDbMaster()),
+		daoQuality:    dao.NewQualityDao(datasource.InstanceDbMaster()),
+		daoContract:   dao.NewContractDao(datasource.InstanceDbMaster()),
+	}
+}
+
+func (s *ruleService) Get(pid int, id int) viewmodels.ViewRule {
+	data := s.daoRule.FindByPidWithBid(pid, id)
+	viewData := viewmodels.ViewRule{SafeRule: data.SafeRule, QualityRule: data.QualityRule, ContractPaidRule: data.ContractPaidRule, ContractReturnRule: data.ContractReturnRule}
+	return viewData
+}
+
+func (s *ruleService) Post(pid int, id int, key string, value string) error {
+	err := s.daoRule.UpdateOrCreate(pid, id, key, value)
+	return err
+}
+
+// 生成code
+func (s *ruleService) AutoCode(bid int, pid int, codeType string) (string, string, error) {
+	// 获取该标段的规则
+	rule := s.daoRule.FindByPidWithBid(pid, bid)
+	if codeType == "safeRule" {
+		if rule.SafeRule == "" {
+			return "", "", errors.New("该标段未设置编号规则")
+		}
+		var code viewmodels.RuleCode
+		err := json.Unmarshal([]byte(rule.SafeRule), &code)
+		total, err := s.daoSafe.CountRuleCode(bid)
+		k, _ := strconv.Atoi(code.Code)
+		newCode := utils.CreateRuleCode(int64(k), total, len(code.Code))
+		return rule.SafeRule, newCode, err
+
+	} else if codeType == "contractReturnRule" {
+		if rule.ContractReturnRule == "" {
+			return "", "", errors.New("该标段未设置编号规则")
+		}
+		var code viewmodels.RuleCode
+		err := json.Unmarshal([]byte(rule.ContractReturnRule), &code)
+		total, err := s.daoContract.CountRuleCode(bid, 1)
+		fmt.Printf("-----------------------", total)
+		k, _ := strconv.Atoi(code.Code)
+		newCode := utils.CreateRuleCode(int64(k), total, len(code.Code))
+		return rule.ContractReturnRule, newCode, err
+
+	} else if codeType == "contractPaidRule" {
+		if rule.ContractPaidRule == "" {
+			return "", "", errors.New("该标段未设置编号规则")
+		}
+		var code viewmodels.RuleCode
+		err := json.Unmarshal([]byte(rule.ContractPaidRule), &code)
+		total, err := s.daoContract.CountRuleCode(bid, 2)
+		k, _ := strconv.Atoi(code.Code)
+		newCode := utils.CreateRuleCode(int64(k), total, len(code.Code))
+		return rule.ContractPaidRule, newCode, err
+
+	} else if codeType == "contractPaidRule" {
+		if rule.ContractPaidRule == "" {
+			return "", "", errors.New("该标段未设置编号规则")
+		}
+		var code viewmodels.RuleCode
+		err := json.Unmarshal([]byte(rule.ContractPaidRule), &code)
+		total, err := s.daoContractPaid.CountPaidRuleCode(bid)
+		k, _ := strconv.Atoi(code.Code)
+		newCode := utils.CreateRuleCode(int64(k), total, len(code.Code))
+		return rule.ContractPaidRule, newCode, err
+
+	} else if codeType == "contractPaidRule" {
+		if rule.ContractPaidRule == "" {
+			return "", "", errors.New("该标段未设置编号规则")
+		}
+		var code viewmodels.RuleCode
+		err := json.Unmarshal([]byte(rule.ContractPaidRule), &code)
+		total, err := s.daoContractPaid.CountPaidRuleCode(bid)
+		k, _ := strconv.Atoi(code.Code)
+		newCode := utils.CreateRuleCode(int64(k), total, len(code.Code))
+		return rule.ContractPaidRule, newCode, err
+	} else {
+		if rule.QualityRule == "" {
+			return "", "", errors.New("该标段未设置编号规则")
+		}
+		var code viewmodels.RuleCode
+		err := json.Unmarshal([]byte(rule.QualityRule), &code)
+		total, err := s.daoQuality.CountRuleCode(bid)
+		k, _ := strconv.Atoi(code.Code)
+		newCode := utils.CreateRuleCode(int64(k), total, len(code.Code))
+		return rule.QualityRule, newCode, err
+	}
+}
+
+func (s *ruleService) ValidRule(ctx iris.Context) (viewmodels.ValidField, error) {
+	safeVaild := viewmodels.ValidField{}
+	if ctx.Method() == "GET" {
+		err := ctx.ReadForm(&safeVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadForm转换异常, error=", err)
+			return safeVaild, err
+		}
+		err = safeVaild.Validate()
+		return safeVaild, err
+	}
+
+	if ctx.Method() == "POST" {
+		err := ctx.ReadJSON(&safeVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadJson转换异常, error=", err)
+			return safeVaild, err
+		}
+		if ctx.Path() == s.validAutoPath {
+			err = safeVaild.ValidateAuto()
+		} else {
+			err = safeVaild.Validate()
+		}
+
+	}
+	return safeVaild, nil
+
+}

+ 149 - 0
services/safe_audit.service.go

@@ -0,0 +1,149 @@
+/*
+ * @description: 安全巡检审批相关
+ * @Author: LanJianRong
+ * @Date: 2020-12-18
+ * @FilePath: \construction_management\web\api\safe_rpc_api.go
+ */
+package services
+
+import (
+	"errors"
+	"log"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/web/viewmodels"
+)
+
+type SafeAuditService interface {
+	ValidRule(ctx iris.Context) (viewmodels.SafeAudit, error)
+	ValidStart(ctx iris.Context) (viewmodels.AuditStart, error)
+	// AddAuditor(safeId int, bId int, auditId int, times int) error
+	CloseAudit(id int, opinion string, curUid int, saveId int) error
+	BackAudit(id int, opinion string, curUid int, saveId int, auditId int) error
+	PassAudit(id int, uid int, auditId int, opinion string, rectifiedInfo string) error
+	StartAudit(safeId int, bidsectionId int, auditors []int, reAuditors []int, uid int, pid int, inspection string, inspectionDetail string, demand string, createTime time.Time) error
+}
+
+type safeAuditService struct {
+	validAdd     string
+	validPass    string
+	validClose   string
+	validBack    string
+	daoSafeAudit *dao.SafeAuditDao
+	daoSafe      *dao.SafeDao
+	daoApprover  *dao.ApproverDao
+	daoTree      *dao.TreeDao
+}
+
+//创建项目用户service
+func NewSafeAuditService() SafeAuditService {
+	return &safeAuditService{
+		validBack:    "/api/safe_audit/back",
+		validAdd:     "/api/safe_audit/add",
+		validClose:   "/api/safe_audit/close",
+		validPass:    "/api/safe_audit/pass",
+		daoSafeAudit: dao.NewSafeAuditDao(datasource.InstanceDbMaster()),
+		daoSafe:      dao.NewSafeDao(datasource.InstanceDbMaster()),
+		daoApprover:  dao.NewApproverDao(datasource.InstanceDbMaster()),
+		daoTree:      dao.NewTreeDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 关闭审批流程
+func (s *safeAuditService) CloseAudit(id int, opinion string, curUid int, saveId int) error {
+	err := s.daoApprover.CloseHandler("safe", id, opinion, curUid, saveId)
+	return err
+}
+
+// 审批退回
+func (s *safeAuditService) BackAudit(id int, opinion string, curUid int, saveId int, auditId int) error {
+	auditor, err := s.daoApprover.FindApproverById(id)
+	if auditor.AuditId != curUid {
+		return errors.New("该用户没有审批权限")
+	}
+	safe := s.daoSafe.FindById(saveId)
+
+	// 退回到了检查人
+	if auditId == 0 {
+		// 初始化审批流程
+		err = s.daoApprover.InitStatus("safe", auditor.BidsectionId, auditor.DataType, auditor.DataId, auditor.AuditId, safe.Times, auditor.Progress+1, opinion)
+	} else {
+		// 退回到审批流程中的某一个人
+		err = s.daoApprover.BackHandlerWithId("safe", auditId, auditor.AuditId, safe.Times, auditor.Progress+1, opinion)
+	}
+	return err
+
+}
+
+// 审批通过
+func (s *safeAuditService) PassAudit(id int, uid int, auditId int, opinion string, rectifiedInfo string) error {
+	err := s.daoApprover.PassHandler("safe", id, uid, auditId, opinion, rectifiedInfo)
+	return err
+}
+
+func (s *safeAuditService) StartAudit(safeId int, bidsectionId int, auditors []int, reAuditors []int, uid int, pid int, inspection string, inspectionDetail string, demand string, createTime time.Time) error {
+	safe := s.daoSafe.FindById(safeId)
+	if safe.Uid != uid {
+		return errors.New("该用户没有操作权限")
+	}
+	// 清除可能有的旧的审批流程
+	err := s.daoApprover.DeleteOldAuditors(bidsectionId, 1, safeId)
+	if err != nil {
+		return err
+	}
+	// 增加审批日志
+	err = s.daoSafeAudit.AddAuditRecord(safeId, bidsectionId, uid, safe.Times, 0, 0, "", "")
+	if err != nil {
+		return err
+	}
+	// 改变安全巡检表的状态
+	err = s.daoSafe.ChangeStatus(safeId, 1, inspection, inspectionDetail, demand, createTime)
+	if err != nil {
+		return err
+	}
+	// 创建审批流程, 同时添加推送消息
+	err = s.daoApprover.InsertData(uid, bidsectionId, pid, 1, safeId, auditors, reAuditors)
+	return err
+}
+
+// 规则校验
+func (s *safeAuditService) ValidRule(ctx iris.Context) (viewmodels.SafeAudit, error) {
+	safeAuditVaild := viewmodels.SafeAudit{}
+	if ctx.Method() == "POST" {
+		err := ctx.ReadJSON(&safeAuditVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadJson转换异常, error=", err)
+			return safeAuditVaild, err
+		}
+		if ctx.Path() == s.validAdd {
+			err = safeAuditVaild.ValidateAddAuditor()
+			return safeAuditVaild, err
+		} else if ctx.Path() == s.validClose {
+			err = safeAuditVaild.ValidateClose()
+			return safeAuditVaild, err
+		} else if ctx.Path() == s.validBack {
+			err = safeAuditVaild.ValidateBack()
+			return safeAuditVaild, err
+		} else if ctx.Path() == s.validPass {
+			err = safeAuditVaild.ValidatePass()
+			return safeAuditVaild, err
+		}
+		return safeAuditVaild, err
+	}
+	return safeAuditVaild, nil
+}
+
+// 校验审批开始
+func (s *safeAuditService) ValidStart(ctx iris.Context) (viewmodels.AuditStart, error) {
+	startAuditValid := viewmodels.AuditStart{}
+	err := ctx.ReadJSON(&startAuditValid)
+	if err != nil {
+		log.Println("safe-ValidRule-ReadJson转换异常, error=", err)
+		return startAuditValid, err
+	}
+	err = startAuditValid.ValidateStart()
+	return startAuditValid, err
+}

+ 456 - 0
services/safe_service.go

@@ -0,0 +1,456 @@
+package services
+
+import (
+	"fmt"
+	"log"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"github.com/shopspring/decimal"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+type SafeService interface {
+	Get(id int, pid int, pageNo int, pageSize int) ([]viewmodels.SafeList, int64)
+	Post(data models.CmSafe) error
+	Del(id int) error
+	GetDetail(id int, pid int) viewmodels.SafeDetail
+
+	GetSurvey(projectId int, bidsectionId int) map[string]interface{}
+	GetPending(projectId int, projectAccountId int) []viewmodels.ApproverMessage
+	ValidRule(ctx iris.Context) (viewmodels.Safe, error)
+}
+
+// //返回service操作类
+type safeService struct {
+	daoSafe           *dao.SafeDao
+	daoQuality        *dao.QualityDao
+	daoSafeAudit      *dao.SafeAuditDao
+	daoProjectAccount *dao.ProjectAccountDao
+	daoAnnex          *dao.AnnexDao
+	daoRule           *dao.RuleDao
+	daoApprover       *dao.ApproverDao
+	daoTree           *dao.TreeDao
+	validDetail       string
+}
+
+//创建项目用户service
+func NewSafeService() SafeService {
+	return &safeService{
+		validDetail:       "/api/safe/detail",
+		daoSafe:           dao.NewSafeDao(datasource.InstanceDbMaster()),
+		daoQuality:        dao.NewQualityDao(datasource.InstanceDbMaster()),
+		daoAnnex:          dao.NewAnnexDao(datasource.InstanceDbMaster()),
+		daoSafeAudit:      dao.NewSafeAuditDao(datasource.InstanceDbMaster()),
+		daoProjectAccount: dao.NewProjectAccountDao(datasource.InstanceDbMaster()),
+		daoApprover:       dao.NewApproverDao(datasource.InstanceDbMaster()),
+		daoTree:           dao.NewTreeDao(datasource.InstanceDbMaster()),
+	}
+}
+func (s *safeService) Get(id int, pid int, pageNo int, pageSize int) ([]viewmodels.SafeList, int64) {
+	datalist, total := s.daoSafe.GetListByBid(id, pageNo, pageSize)
+	safeList := make([]viewmodels.SafeList, 0)
+	for _, item := range datalist {
+		safeVM := viewmodels.SafeList{}
+		safeVM.Code = item.Code
+		account := s.daoProjectAccount.Get(item.Uid, pid)
+		safeVM.AuditName = account.Name
+		safeVM.CreateTime = item.CreateTime.Format(conf.SysTimeform)
+		safeVM.Demand = item.Demand
+		id, _ := comm.AesEncrypt(strconv.Itoa(item.Id), conf.SignSecret)
+		safeVM.Id = id
+		safeVM.Inspection = item.Inspection
+		safeVM.InspectionDetail = item.InspectionDetail
+		safeVM.Position = item.Position
+		safeVM.Status = item.Status
+		counts, _ := s.daoAnnex.GetCount(3, item.Id)
+		safeVM.FileCounts = counts
+		safeList = append(safeList, safeVM)
+	}
+	return safeList, total
+}
+
+// post请求,插入单条数据
+func (s *safeService) Post(data models.CmSafe) error {
+	// has, err := s.daoSafe.FindByCode(data.Code)
+	// if err != nil {
+	// 	return err
+	// }
+	// if has {
+	// 	return errors.New("该编号已存在!")
+	// }
+	// _, err = s.daoSafe.InsertRecord(data)
+	// if err != nil {
+	// 	return err
+	// }
+	// counts, err := s.daoSafe.GetCountsByBid(data.BidsectionId, data.Status, true)
+	// err = s.daoTree.UpdateCounts("safe_total", counts, data.BidsectionId)
+	// if err != nil {
+	// 	return err
+	// }
+	// return nil
+	err := s.daoSafe.CreateSafe(data)
+	return err
+}
+
+// delete请求,删除数据
+func (s *safeService) Del(id int) error {
+	err := s.daoSafe.DeleteRecord(id)
+	return err
+}
+
+// 详情页数据拼装
+func (s *safeService) GetDetail(id int, pid int) viewmodels.SafeDetail {
+
+	safeData := s.daoSafe.FindById(id)
+	// fmt.Println(safeData)
+	safeId, _ := comm.AesEncrypt(strconv.Itoa(safeData.Id), conf.SignSecret)
+	bid, _ := comm.AesEncrypt(strconv.Itoa(safeData.BidsectionId), conf.SignSecret)
+	uid, _ := comm.AesEncrypt(strconv.Itoa(safeData.Uid), conf.SignSecret)
+	data := viewmodels.SafeDetail{}
+	data.Id = safeId
+	data.BidsectionId = bid
+	data.Uid = uid
+	data.Code = safeData.Code
+	data.Inspection = safeData.Inspection
+	data.InspectionDetail = safeData.InspectionDetail
+	data.Demand = safeData.Demand
+	account := s.daoProjectAccount.Get(safeData.Uid, pid)
+	data.AuditName = account.Name
+	data.CreateTime = safeData.CreateTime
+	data.Times = safeData.Times
+	data.Status = safeData.Status
+	fileList, total := s.daoAnnex.GetList(3, safeData.Id, 1, conf.PageSize)
+	// 加密id
+	fileArr := make([]viewmodels.AnnexListView, 0)
+	for _, item := range fileList {
+		fileListVM := viewmodels.AnnexListView{}
+		fileId, _ := comm.AesEncrypt(item.Id, conf.SignSecret)
+		fileListVM.Id = fileId
+		uid, _ := comm.AesEncrypt(item.AccountId, conf.SignSecret)
+		fileListVM.AccountId = uid
+		fileListVM.AccountName = item.AccountName
+		fileListVM.CreateTime = item.CreateTime
+		fileListVM.FileName = item.FileName
+		fileListVM.FilePath = item.FilePath
+		fileArr = append(fileArr, fileListVM)
+	}
+	fileVM := viewmodels.FileStruct{}
+	fileVM.FileList = fileArr
+	fileVM.Total = total
+	data.File = fileVM
+	auditors := s.daoApprover.GetAuditorsWithOwner(safeData.BidsectionId, int(1), safeData.Id, account.Id)
+	encryptAuditors := make([]viewmodels.Auditors, 0)
+	for _, item := range auditors {
+		auditorVM := viewmodels.Auditors{}
+		if item.Id != "" {
+			id, _ := comm.AesEncrypt(item.Id, conf.SignSecret)
+			auditorVM.Id = id
+		}
+		auditId, _ := comm.AesEncrypt(item.AuditId, conf.SignSecret)
+		auditorVM.AuditId = auditId
+		auditorVM.Name = item.Name
+		auditorVM.Position = item.Position
+		auditorVM.Mobile = item.Mobile
+		auditorVM.AuditOrder = item.AuditOrder
+		auditorVM.AccountGroup = item.AccountGroup
+		auditorVM.Progress = item.Progress
+		auditorVM.Company = item.Company
+		auditorVM.Status = item.Status
+		encryptAuditors = append(encryptAuditors, auditorVM)
+	}
+	auditHistory := s.daoSafeAudit.GetAuditHistory(safeData.Id, safeData.Times)
+	data.AuditHistory = auditHistory
+	// 整改单
+	rectifiedInfo, _ := s.daoSafeAudit.GetLastedOrder(safeData.Id)
+	data.RectifiedInfo = rectifiedInfo
+
+	// 最新审批人信息
+	latestAuditor := s.daoApprover.GetLastedAuditor(safeData.BidsectionId, 1, safeData.Id)
+	data.LatestdAuditor = latestAuditor
+	data.Auditors = encryptAuditors
+
+	return data
+}
+
+// 安全概况
+func (s *safeService) GetSurvey(projectId int, bidsectionId int) map[string]interface{} {
+	// 1.获得安全巡检
+	year := time.Now().Year()
+	safeList := s.daoSafe.GetTypeYear(bidsectionId, year)
+	// 2.初始化
+	rectifylist := make([]viewmodels.SafeSurveyList, 0)
+	rectifyTotal := 0
+	approvalTotal := 0
+	rectifyedTotal := 0
+
+	columnarData := make([]map[string]interface{}, 0)
+	lineData := columnarData
+	for i := 1; i <= 12; i++ {
+		item := map[string]interface{}{
+			"name":  "rectifyed",
+			"month": fmt.Sprintf("%d-%02d", year, i),
+			"count": 0,
+		}
+		columnarData = append(columnarData, item)
+		item = map[string]interface{}{
+			"name":  "submit",
+			"month": fmt.Sprintf("%d-%02d", year, i),
+			"count": 0,
+		}
+		columnarData = append(columnarData, item)
+		item = map[string]interface{}{
+			"month":      fmt.Sprintf("%d-%02d", year, i),
+			"percentage": 0,
+		}
+		lineData = append(lineData, item)
+
+	}
+
+	// 3.当年数据初始化
+	submitData := map[string]int{
+		fmt.Sprintf("%d-01", year): 0,
+		fmt.Sprintf("%d-02", year): 0,
+		fmt.Sprintf("%d-03", year): 0,
+		fmt.Sprintf("%d-04", year): 0,
+		fmt.Sprintf("%d-05", year): 0,
+		fmt.Sprintf("%d-06", year): 0,
+		fmt.Sprintf("%d-07", year): 0,
+		fmt.Sprintf("%d-08", year): 0,
+		fmt.Sprintf("%d-09", year): 0,
+		fmt.Sprintf("%d-10", year): 0,
+		fmt.Sprintf("%d-11", year): 0,
+		fmt.Sprintf("%d-12", year): 0,
+	}
+	rectifyedData := map[string]int{
+		fmt.Sprintf("%d-01", year): 0,
+		fmt.Sprintf("%d-02", year): 0,
+		fmt.Sprintf("%d-03", year): 0,
+		fmt.Sprintf("%d-04", year): 0,
+		fmt.Sprintf("%d-05", year): 0,
+		fmt.Sprintf("%d-06", year): 0,
+		fmt.Sprintf("%d-07", year): 0,
+		fmt.Sprintf("%d-08", year): 0,
+		fmt.Sprintf("%d-09", year): 0,
+		fmt.Sprintf("%d-10", year): 0,
+		fmt.Sprintf("%d-11", year): 0,
+		fmt.Sprintf("%d-12", year): 0,
+	}
+	for _, item := range safeList {
+		if item.Status == 2 {
+			id, _ := comm.AesEncrypt(item.Id, conf.SignSecret)
+			item.Id = id
+			rectifylist = append(rectifylist, item)
+			rectifyTotal++
+		}
+		// if item.Status == 1 {
+		// 	approvalTotal++
+		// }
+		approvalTotal++
+		if item.Status == 4 {
+			rectifyedTotal++
+		}
+
+		// for index, columnar := range columnarData {
+		// 	rectifyedCount := 0
+		// 	if columnar["month"] == item.CreateTime.Format(conf.SysTimeformMonth) {
+		// 		if item.Status == 4 && columnar["name"] == "rectifyed" {
+		// 			rectifyedCount++
+		// 		}
+		// 		columnarData[index]["count"] = columnarData[index]["count"].(int) + 1
+		// 		columnarData[index]["count"] = rectifyedCount
+		// 		// if item.Status == 0 && columnar["name"] == "submit" {
+
+		// 		// }
+		// 	}
+		// }
+		index := item.CreateTime.Format(conf.SysTimeformMonth)
+		submitData[index] = submitData[index] + 1
+		// if item.Status == 0 {
+		// 	submitData[item.CreateTime.Format(conf.SysTimeformMonth)] = submitData[item.CreateTime.Format(conf.SysTimeformMonth)] + 1
+		// }
+		if item.Status == 4 {
+			rectifyedData[index] = rectifyedData[index] + 1
+		}
+
+	}
+
+	for index, columnar := range columnarData {
+
+		if columnar["name"] == "rectifyed" {
+			columnarData[index]["count"] = rectifyedData[columnar["month"].(string)]
+		}
+		if columnar["name"] == "submit" {
+			columnarData[index]["count"] = submitData[columnar["month"].(string)]
+		}
+	}
+
+	for index, line := range lineData {
+		rectifyedCount := 0
+		submitCount := 0
+		for _, columnar := range columnarData {
+			if line["month"] == columnar["month"] {
+				if columnar["name"] == "rectifyed" {
+					rectifyedCount = columnar["count"].(int)
+				}
+				if columnar["name"] == "submit" {
+					submitCount = columnar["count"].(int)
+				}
+			}
+		}
+		lineData[index]["percentage"] = 0.00
+		if rectifyedCount != 0 && submitCount != 0 {
+			decimal.DivisionPrecision = 2
+			percentage, _ := decimal.NewFromFloat(float64(rectifyedCount)).Div(decimal.NewFromFloat(float64(submitCount))).Float64()
+			lineData[index]["percentage"] = percentage * 100
+		}
+	}
+
+	// 整改占总数比例 - 完成整改/提交巡检
+	surveryData := map[string]interface{}{
+		"rectifylist":    rectifylist,
+		"rectifyTotal":   rectifyTotal,
+		"approvalTotal":  approvalTotal,
+		"rectifyedTotal": rectifyedTotal,
+		"columnarData":   columnarData,
+		"lineData":       lineData,
+		// "submitData":     submitData,
+		// "rectifyedData":  rectifyedData,
+	}
+
+	return surveryData
+}
+
+// 获得账号下需要审批的巡检
+func (s *safeService) GetPending(projectId int, projectAccountId int) []viewmodels.ApproverMessage {
+
+	// 1.获得审批列表
+	approverData := s.daoApprover.GetStatusByProjectAndAccount(projectId, projectAccountId, 1)
+	// 2.构建数据ID
+	safeIds := []string{}
+	qualityIds := []string{}
+	for _, item := range approverData {
+		if item.DataType == 1 {
+			safeIds = append(safeIds, strconv.Itoa(item.DataId))
+		} else if item.DataType == 2 {
+			qualityIds = append(qualityIds, strconv.Itoa(item.DataId))
+		}
+	}
+	safeInId := strings.Join(safeIds, ",")
+	qualityInId := strings.Join(qualityIds, ",")
+
+	safeList := make([]viewmodels.SafeList, 0)
+	qualityList := make([]viewmodels.QualityList, 0)
+	if safeInId != "" {
+		safeList = s.daoSafe.GetInIdJoinAccount(safeInId)
+	}
+	if qualityInId != "" {
+		qualityList = s.daoQuality.GetInIdJoinAccount(qualityInId)
+	}
+
+	// data := s.daoSafe.GetStatusByProjectAndAccount(projectId, projectAccountId, 1)
+
+	list := make([]viewmodels.ApproverMessage, 0)
+	for _, item := range approverData {
+		approverVM := viewmodels.ApproverMessage{}
+
+		Id, _ := comm.AesEncrypt(strconv.Itoa(item.Id), conf.SignSecret)
+		// BidsectionId, _ := comm.AesEncrypt(strconv.Itoa(item.BidsectionId), conf.SignSecret)
+		// AuditId, _ := comm.AesEncrypt(item.AuditId, conf.SignSecret)
+		// ProjectId, _ := comm.AesEncrypt(strconv.Itoa(item.ProjectId), conf.SignSecret)
+		DataId, _ := comm.AesEncrypt(strconv.Itoa(item.DataId), conf.SignSecret)
+		// ProjectId, _ := comm.AesEncrypt(strconv.Itoa(item.ProjectId), conf.SignSecret)
+
+		approverVM.Id = Id
+		// approverVM.ProjectId = ProjectId
+		// approverVM.BidsectionId = BidsectionId
+		approverVM.DataType = item.DataType
+		approverVM.DataId = DataId
+		approverVM.Status = item.Status
+
+		dataIdString := strconv.Itoa(item.DataId)
+		// 安全巡检相关
+		if item.DataType == 1 {
+			for _, data := range safeList {
+				if dataIdString == data.Id {
+					approverVM.Code = data.Code
+					approverVM.InspectionDetail = data.InspectionDetail
+					approverVM.Name = data.AuditName
+					approverVM.Position = data.Position
+					approverVM.CreateTime = data.CreateTime
+					break
+				}
+			}
+		} else if item.DataType == 2 { // 质量巡检
+			for _, data := range qualityList {
+				if dataIdString == data.Id {
+					approverVM.Code = data.Code
+					approverVM.InspectionDetail = data.InspectionDetail
+					approverVM.Name = data.AuditName
+					approverVM.Position = data.Position
+					approverVM.CreateTime = data.CreateTime
+					break
+				}
+			}
+		}
+
+		list = append(list, approverVM)
+	}
+
+	return list
+}
+
+// 规则校验
+func (s *safeService) ValidRule(ctx iris.Context) (viewmodels.Safe, error) {
+	safeVaild := viewmodels.Safe{}
+	// fmt.Println("---------------------------safeVaild", safeVaild)
+	if ctx.Method() == "GET" {
+		err := ctx.ReadForm(&safeVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadForm转换异常, error=", err)
+			return safeVaild, err
+		}
+		if ctx.Path() == s.validDetail {
+			// 一样要传id,所以用delete的方法判断
+			err = safeVaild.ValidateDelete()
+		} else {
+			err = safeVaild.ValidateList()
+		}
+		return safeVaild, err
+	}
+
+	if ctx.Method() == "POST" {
+		err := ctx.ReadJSON(&safeVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadJson转换异常, error=", err)
+			return safeVaild, err
+		}
+		err = safeVaild.ValidateCreate()
+		return safeVaild, err
+		// if ctx.Path() == s.validCreate {
+		// }
+		// if ctx.Path() == s.validFile {
+		// 	err = safeVaild.ValidateFile()
+		// 	return safeVaild, err
+		// }
+	}
+
+	if ctx.Method() == "PUT" {
+		err := ctx.ReadForm(&safeVaild)
+		if err != nil {
+			log.Println("safe-ValidRule-ReadForm转换异常, error=", err)
+			return safeVaild, err
+		}
+		err = safeVaild.ValidateDelete()
+		return safeVaild, err
+	}
+	return safeVaild, nil
+
+}

+ 672 - 0
services/tree_service.go

@@ -0,0 +1,672 @@
+/*
+ * @description:层级文件夹数据操作相关
+ * @Author: CP
+ * @Date: 2020-09-11 14:43:58
+ * @FilePath: \construction_management\services\tree_service.go
+ */
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"strconv"
+	"time"
+
+	"github.com/kataras/iris/v12"
+	"go.mod/comm"
+	"go.mod/conf"
+	"go.mod/dao"
+	"go.mod/datasource"
+	"go.mod/models"
+	"go.mod/web/viewmodels"
+)
+
+//定义项目Service接口
+type TreeService interface {
+	//ValidManager(code string, account string, password string) error
+	ValidRule(ctx iris.Context) (viewmodels.Tree, error)
+	ValidRuleBidsectionType(ctx iris.Context) (viewmodels.Permission, error)
+
+	Create(data viewmodels.Tree) error
+	GetAllProject(projectId int) *viewmodels.Tree
+	GetAllContract(projectId int, account *models.CmProjectAccount, bidsectionType int) *viewmodels.FolderContract
+	Rename(treevm viewmodels.Tree, projectId int) error
+	GetFolderAndBid(id int, projectId int) ([]models.CmTree, error)
+	DeleteFolderAndBid(id int, projectId int) error
+	Move(id int, moveId int, projectId int) error
+}
+
+//返回service操作类
+type treeService struct {
+	dao                  *dao.TreeDao
+	permissionAccountDao *dao.PermissionAccountDao
+}
+
+//创建项目service
+func NewTreeService() TreeService {
+	return &treeService{
+		dao:                  dao.NewTreeDao(datasource.InstanceDbMaster()),
+		permissionAccountDao: dao.NewPermissionAccountDao(datasource.InstanceDbMaster()),
+	}
+}
+
+// 文件夹规则验证
+func (s *treeService) ValidRule(ctx iris.Context) (viewmodels.Tree, error) {
+	folderVaild := viewmodels.Tree{}
+	err := ctx.ReadJSON(&folderVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return folderVaild, err
+	}
+
+	err = folderVaild.Validate()
+	if err != nil {
+		log.Println("文件夹验证, error=", err)
+		return folderVaild, err
+	}
+
+	return folderVaild, nil
+}
+
+// 文件夹规则验证
+func (s *treeService) ValidRuleBidsectionType(ctx iris.Context) (viewmodels.Permission, error) {
+	folderVaild := viewmodels.Permission{}
+	err := ctx.ReadForm(&folderVaild)
+	if err != nil {
+		log.Println("folder-ValidRule-ReadForm转换异常, error=", err)
+		return folderVaild, err
+	}
+
+	err = folderVaild.ValidateType()
+	if err != nil {
+		log.Println("请求标段类型验证, error=", err)
+		return folderVaild, err
+	}
+
+	return folderVaild, nil
+}
+
+// 获得项目下 相关文件夹-整个树结构
+func (s *treeService) GetAllProject(projectId int) *viewmodels.Tree {
+	datalist := s.dao.GetAllTree(projectId)
+	folderlist := make([]*viewmodels.Tree, 0)
+	// 生成根
+	folder := &viewmodels.Tree{}
+	id, _ := comm.AesEncrypt(strconv.Itoa(0), conf.SignSecret)
+	parentId, _ := comm.AesEncrypt(strconv.Itoa(-1), conf.SignSecret)
+	folder.Id = id
+	folder.Name = "根目录"
+	folder.Isfolder = 1
+	folder.ParentId = parentId
+	folder.Children = make([]*viewmodels.Tree, 0)
+	folderlist = append(folderlist, folder)
+	// 加入数据
+	for _, data := range datalist {
+		folder := &viewmodels.Tree{}
+		//folder.Id = comm.Encrypt([]byte(conf.SignSecret), []byte(strconv.Itoa(data.Id)))
+		id, _ := comm.AesEncrypt(strconv.Itoa(data.Id), conf.SignSecret)
+		parentId, _ := comm.AesEncrypt(strconv.Itoa(data.ParentId), conf.SignSecret)
+		projectId, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret)
+		serial, _ := comm.AesEncrypt(strconv.Itoa(data.Serial), conf.SignSecret)
+		bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret)
+		folder.Id = id
+		folder.Name = data.Name
+		folder.ParentId = parentId
+		folder.ProjectId = projectId
+		folder.BidsectionId = bidsectionId
+		folder.Depth = data.Depth + 1
+		folder.Serial = serial
+		folder.Accounts = data.Accounts
+		folder.Isfolder = data.Isfolder
+		folder.IsEnd = false
+		//folder.Leaf = true
+		folder.HasFolder = false
+		folder.IsBid = false
+		folder.CreateTime = data.CreateTime.Format(conf.SysTimeform)
+		folderlist = append(folderlist, folder)
+	}
+
+	//fmt.Println(folderlist)
+
+	//var data []*viewmodels.Tree
+	// data := make([]*viewmodels.Tree, 0)
+	// for i, _ := range folderlist {
+	// 	var a *viewmodels.Tree
+	// 	a = &folderlist[i]
+	// 	data = append(data, a)
+	// }
+
+	node := folderlist[0]      //父节点
+	maketree(folderlist, node) //调用生成tree
+	//transformjson(node)    //转化为json
+	return node
+}
+
+// 获得合同管理的目录
+func (s *treeService) GetAllContract(projectId int, account *models.CmProjectAccount, bidsectionType int) *viewmodels.FolderContract {
+	datalist := s.dao.GetAllTree(projectId)
+	folderlist := make([]viewmodels.FolderContract, 0)
+
+	// 2.获得该账号的权限
+	permissionData := s.permissionAccountDao.GetProjectIdAccountId(projectId, account.Id)
+
+	// 生成根
+	folder := viewmodels.FolderContract{}
+	id, _ := comm.AesEncrypt(strconv.Itoa(0), conf.SignSecret)
+	parentId, _ := comm.AesEncrypt(strconv.Itoa(-1), conf.SignSecret)
+	folder.Id = id
+	folder.Name = "root"
+	folder.ParentId = parentId
+	folder.Isfolder = 1
+	// folder.Children = make([]*viewmodels.FolderContract, 0)
+	folderlist = append(folderlist, folder)
+	// 加入数据
+	for _, data := range datalist {
+
+		flag := true
+		// 标段过滤开始
+		if data.BidsectionId != 0 && account.IsAdmin != 1 {
+			flag = false
+		}
+
+		// 过滤没有权限访问的标段-管理员不需要过滤
+		if data.BidsectionId != 0 && account.IsAdmin != 1 {
+			permission := map[string]int{}
+			for _, item := range permissionData {
+				if data.BidsectionId == item.BidsectionId {
+					// 区别合同,安全,质量
+					if bidsectionType == 1 {
+						json.Unmarshal([]byte(item.SafePermission), &permission)
+
+					} else if bidsectionType == 2 {
+						json.Unmarshal([]byte(item.QualityPermission), &permission)
+
+					} else if bidsectionType == 0 {
+						json.Unmarshal([]byte(item.ContractPermission), &permission)
+						// fmt.Println(permission)
+						// if permission["access"] == 1 {
+						// 	flag = true
+						// 	break
+						// }
+					} else {
+						return nil
+					}
+
+					if permission["access"] == 1 {
+						flag = true
+						break
+					}
+				}
+			}
+		}
+		// 标段过滤结束
+
+		if flag {
+			folder := viewmodels.FolderContract{}
+			id, _ := comm.AesEncrypt(strconv.Itoa(data.Id), conf.SignSecret)
+			parentId, _ := comm.AesEncrypt(strconv.Itoa(data.ParentId), conf.SignSecret)
+			projectId, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret)
+			bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret)
+			folder.Id = id
+			folder.Name = data.Name
+			folder.ParentId = parentId
+			folder.ProjectId = projectId
+			folder.BidsectionId = bidsectionId
+			// 合同数据
+			folder.Contracts = data.Contracts
+			folder.ContractsIncome = data.ContractsIncome
+			folder.ContractsReturned = data.ContractsReturned
+			// 汇款进度
+			ContractsIncome, err := strconv.ParseFloat(data.ContractsIncome, 64)
+			if err != nil {
+				ContractsIncome = 0
+			}
+			ContractsReturned, err := strconv.ParseFloat(data.ContractsReturned, 64)
+			if err != nil || ContractsReturned == 0 {
+				ContractsReturned = 0
+				folder.ContractsIncomeProgress = "0%"
+			} else {
+				folder.ContractsIncomeProgress = fmt.Sprintf("%.0f", (ContractsReturned/ContractsIncome)*100) + "%"
+			}
+
+			folder.ContractsPay = data.ContractsPay
+			folder.ContractsPaid = data.ContractsPaid
+			// 支付进度
+			ContractsPay, err := strconv.ParseFloat(data.ContractsPay, 64)
+			if err != nil {
+				ContractsPay = 0
+			}
+			ContractsPaid, err := strconv.ParseFloat(data.ContractsPaid, 64)
+			if err != nil || ContractsPaid == 0 {
+				ContractsPaid = 0
+				folder.ContractsPayProgress = "0%"
+			} else {
+				folder.ContractsPayProgress = fmt.Sprintf("%.0f", (ContractsPaid/ContractsPay)*100) + "%"
+			}
+
+			folder.Isfolder = data.Isfolder
+			folder.IsEnd = false
+
+			folder.HasFolder = false
+			folder.IsBid = false
+			folderlist = append(folderlist, folder)
+		}
+
+	}
+
+	// fmt.Println(folderlist)
+
+	var data []*viewmodels.FolderContract
+	data = make([]*viewmodels.FolderContract, 0)
+	for i, _ := range folderlist {
+		var a *viewmodels.FolderContract
+		a = &folderlist[i]
+		data = append(data, a)
+	}
+
+	node := &folderlist[0] //父节点
+	comm.MakeFolderContract(data, node)
+
+	// 求和
+	// dataLenght := len(data) + 4
+
+	s.filterFolder(node)
+
+	// 删除空目录
+	ChildrenShow := make([]*viewmodels.FolderContract, 0)
+	for _, item := range node.Children {
+		if item.IsHidden == 0 {
+			ChildrenShow = append(ChildrenShow, item)
+		}
+	}
+	node.Children = ChildrenShow
+
+	// node.Children = s.copyShowFolder(node.Children)
+	// fmt.Println(node)
+	return node
+}
+
+// 复制出需要展示的目录
+// func (s *treeService) copyShowFolder(children []*viewmodels.FolderContract) []*viewmodels.FolderContract {
+// 	ChildrenShow := make([]*viewmodels.FolderContract, 0)
+// 	for _, item := range children {
+// 		if item.IsHidden == 0 {
+// 			ChildrenShow = append(ChildrenShow, item)
+// 		}
+// 	}
+// 	return ChildrenShow
+// }
+
+func (s *treeService) filterFolder(node *viewmodels.FolderContract) {
+	if node == nil {
+		return
+	}
+
+	// 目录下是否为空目录  1空目录
+	isEmptyFolder := 1
+
+	length := len(node.Children)
+	// 如果length为0叶子节点---为目录才需要遍历
+	if length == 0 {
+		// 1.如果是目录-已经为叶子目录不需要遍历
+		// 2.是标段 目录不为空
+		if node.Isfolder == 0 {
+			isEmptyFolder = 0
+		}
+	} else {
+		// 1.遍历目录下
+		for i := 0; i < length; i++ {
+			// 2.该节点下子对象 从0-length 依次进入
+			s.filterFolder(node.Children[i])
+			// 后序-父节点逻辑 处理完0 ... -length
+			// 2-1 是标段 设置目录不为空
+			if node.Children[i].Isfolder == 0 {
+				// 有标段
+				isEmptyFolder = 0
+			} else {
+				// 2-2 是目录   ----后序遍历,最后一层下的孩子们是否能删除 走完三个点后返回到父亲
+				// 2-2-1 可展示目录 集合
+				ChildrenShow := make([]*viewmodels.FolderContract, 0)
+				// 2-2-2 目录下内容
+				if len(node.Children[i].Children) != 0 {
+					// 2-2-3 内容中是否有需要显示的目录
+					for _, item := range node.Children[i].Children {
+						// 2-2-4 有 设置为需要显示并拷贝显示内容
+						if item.IsHidden == 0 {
+							ChildrenShow = append(ChildrenShow, item)
+							node.Children[i].IsHidden = 0
+						}
+					}
+				}
+				// 2-2-5 覆盖父亲节点的显示内容
+				node.Children[i].Children = ChildrenShow
+
+				// s.copyShowFolder(node.Children[i].Children)
+				// fmt.Println("==========filterFolder执行完成")
+				// fmt.Println(node.Children[i].Name)
+				// fmt.Println(fmt.Sprintf("删除:%d", node.Children[i].IsHidden))
+				// fmt.Println(node.Children[i].Children)
+			}
+		}
+	}
+
+	// fmt.Println("=========================进入")
+	// fmt.Println(node.Name)
+	// fmt.Println(fmt.Sprintf("空目录:%d", isEmptyFolder))
+	// 后序的第一位叶子节点 如果目录为空,设置不显示
+	if isEmptyFolder == 1 {
+		node.IsHidden = 1
+	}
+}
+
+// 新增一个文件夹
+func (s *treeService) Create(data viewmodels.Tree) error {
+	// 类型校验
+	folder := models.CmTree{}
+	folder.Name = data.Name
+	// 项目ID
+	ProjectId, err := strconv.Atoi(data.ProjectId)
+	if err != nil {
+		return err
+	}
+
+	// 获得该目录ID
+	Id, err := comm.AesDecrypt(data.Id, conf.SignSecret)
+	if err != nil {
+		return err
+	}
+	IdInt, err1 := strconv.Atoi(Id)
+	if err1 != nil {
+		return err1
+	}
+
+	// 该目录中是否有标段
+	bidlist := s.dao.GetBidsection(IdInt)
+	if len(bidlist) > 0 {
+		return errors.New("该文件夹已存在标段,不能在新增目录")
+	}
+
+	// 获得该深度的文件夹最大序号
+	serial := 0
+	depth := data.Depth + 1
+	if data.Depth == -1 {
+		// 1-创建顶级目录--获得最大序号
+		datalist := s.dao.GetAllDepth(depth, ProjectId)
+		maxIndex := len(datalist)
+		if maxIndex != 0 {
+			serial = datalist[maxIndex-1].Serial + 1
+		}
+	} else {
+		// 1-创建次目录-获得次级目录最大序号
+		treeNode := s.dao.Get(IdInt, ProjectId)
+		// 去除前端depth作用-在这里获得下级目录的深度
+		depth = treeNode.Depth + 1
+		if treeNode.Id == 0 {
+			return errors.New("上级目录不正确")
+		}
+		attribution := fmt.Sprintf("%s%d-", treeNode.Attribution, treeNode.Serial)
+		datalist := s.dao.GetALLDepthByAttribution(depth, ProjectId, attribution)
+		maxIndex := len(datalist)
+		if maxIndex != 0 {
+			serial = datalist[maxIndex-1].Serial + 1
+		}
+
+		// 设置归属
+		folder.Attribution = attribution //treeNode.Attribution + strconv.Itoa(treeNode.Serial) + "-"
+		folder.ParentId = IdInt
+	}
+
+	folder.ProjectId = ProjectId
+	folder.Serial = serial
+	folder.Depth = depth
+	folder.Isfolder = 1
+	folder.CreateTime = time.Now()
+	folder.UpdateTime = time.Now()
+	folder.ContractsIncome = "0"
+	folder.ContractsPaid = "0"
+	folder.ContractsPay = "0"
+	folder.ContractsReturned = "0"
+	err = s.dao.Create(&folder)
+	if err != nil {
+		log.Println("添加目录出错, error=", err)
+		return errors.New("添加目录出错")
+	}
+	return nil
+}
+
+// 重命名
+func (s *treeService) Rename(data viewmodels.Tree, projectId int) error {
+	// 获得该目录ID
+	Id, err := comm.AesDecrypt(data.Id, conf.SignSecret)
+	if err != nil {
+		return err
+	}
+	IdInt, err1 := strconv.Atoi(Id)
+	if err1 != nil {
+		return err1
+	}
+
+	// 获得树信息
+	treeData := s.dao.Get(IdInt, projectId)
+	if treeData.Id == 0 {
+		return errors.New("修改的目录不合法")
+	}
+	treeNode := models.CmTree{}
+	treeNode.Id = IdInt
+	treeNode.Name = data.Name
+	if treeData.Isfolder == 1 {
+		// 目录
+		err = s.dao.Update(&treeNode, []string{"Name"})
+	} else {
+		// 标段
+		treeNode.BidsectionId = treeData.BidsectionId
+		err = s.dao.Rename(&treeNode, []string{"Name"})
+	}
+
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 获得该目录下所有的目录和标段
+func (s *treeService) GetFolderAndBid(id int, projectId int) ([]models.CmTree, error) {
+	// 获得该目录ID
+	// id, err := comm.AesDecrypt(id, conf.SignSecret)
+	// if err != nil {
+	// 	return nil, errors.New("目录解析错误")
+	// }
+	// IdInt, err := strconv.Atoi(id)
+	// if err != nil {
+	// 	return nil, errors.New("目录解析错误")
+	// }
+	// 获得该目录下所有数据
+	folder := s.dao.Get(id, projectId)
+	if folder.Id == 0 {
+		return nil, errors.New("目录不合法")
+	}
+	attribution := fmt.Sprintf("%s%d-", folder.Attribution, folder.Serial)
+	// 获得目录归属
+	dataList := s.dao.GetFolderAndBid(folder.ProjectId, attribution)
+	return dataList, nil
+}
+
+// 删除该目录和所属的目录和标段
+func (s *treeService) DeleteFolderAndBid(id int, projectId int) error {
+	// 获得该目录ID
+	// id, err := comm.AesDecrypt(id, conf.SignSecret)
+	// if err != nil {
+	// 	return errors.New("目录解析错误")
+	// }
+	// IdInt, err := strconv.Atoi(id)
+	// if err != nil {
+	// 	return errors.New("目录解析错误")
+	// }
+	// 获得该目录下 归属关系
+	folder := s.dao.Get(id, projectId)
+	if folder.Id == 0 {
+		return errors.New("目录不合法")
+	}
+	attribution := fmt.Sprintf("%s%d-", folder.Attribution, folder.Serial)
+	// --逻辑删除 目录和数据
+	err := s.dao.DeleteFolderAndBid(folder.Id, folder.ProjectId, attribution)
+	if err != nil {
+		return err
+	}
+	// TODO -加入堆栈 物理删除数据
+
+	return nil
+}
+
+// 移动目录
+func (s *treeService) Move(id int, moveId int, projectId int) error {
+	// 获得项目目录
+	treeNode := s.dao.Get(id, projectId)
+
+	if treeNode.Id == 0 {
+		return errors.New("目录或标段解析错误")
+	}
+
+	targetFolder := &models.CmTree{}
+	// id为0是跟目录
+	if moveId == 0 {
+		// id
+		targetFolder.Id = 0
+		// 1.获得最大序号
+		// seriallist := s.dao.GetALLDepthByAttribution(0, projectId, "")
+		// maxIndex := len(seriallist)
+		// serial := 0
+		// if maxIndex != 0 {
+		// 	serial = seriallist[maxIndex-1].Serial + 1
+		// }
+		// targetFolder.Serial = serial
+		targetFolder.Serial = 0
+		// 2.归属
+		targetFolder.Attribution = ""
+		// 3.深度depth-根目录为-1
+		targetFolder.Depth = -1
+		// 4.为目录
+		targetFolder.Isfolder = 1
+		// 5.项目ID
+		targetFolder.ProjectId = projectId
+
+		// fmt.Println(targetFolder)
+		// if targetFolder.Id == 0 {
+		// 	return errors.New("目录解析错误-测试")
+		// }
+	} else {
+		targetFolder = s.dao.Get(moveId, projectId)
+		if targetFolder.Id == 0 {
+			return errors.New("目录解析错误")
+		}
+	}
+
+	// 目录必须是目录
+	if targetFolder.Isfolder == 0 {
+		return errors.New("目标不是文件夹")
+	}
+
+	// 目录的目标不能是自己
+	if id == moveId {
+		return errors.New("目标目录是原目录-不能移动")
+	}
+
+	// 移动的是目录
+	if treeNode.Isfolder == 1 {
+		// 1.目录下不能有标段
+		// 被移动的目录存在标段
+		moveBidList := s.dao.GetBidsection(moveId)
+		if len(moveBidList) > 0 {
+			return errors.New("该目录中存在标段,不能移动")
+		}
+	} else {
+		// 标段
+		// 1.移动的目录是否为叶子节点
+		moveBidList := s.dao.GetChildFolder(moveId)
+		if len(moveBidList) > 0 {
+			return errors.New("该目录中存在其他目录,不能移动")
+		}
+	}
+
+	err := s.dao.Move(treeNode, targetFolder)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 创建一颗树...interface{}
+func maketree(Data []*viewmodels.Tree, node *viewmodels.Tree) { //参数为父节点,添加父节点的子节点指针切片
+	childs, _ := havechild(Data, node) //判断节点是否有子节点并返回
+	if childs != nil {
+		// fmt.Printf("\n")
+		// fmt.Println(*node)
+		// fmt.Println("子节点:")
+		// for _, v := range childs {
+		// 	fmt.Println(*v)
+		// } //打印
+
+		// 子节点总数
+		Total := len(childs)
+		node.ChildsTotal = Total
+		// 标记最后一个元素
+		end := Total - 1
+		childs[end].IsEnd = true
+
+		// 往父节点添加子节点
+		node.Children = append(node.Children, childs[0:]...) //添加子节点
+		for _, v := range childs {                           //查询子节点的子节点,并添加到子节点
+			_, has := havechild(Data, v)
+			if has {
+				// 递归添加节点
+				maketree(Data, v)
+			}
+			// else {
+			// 	// 叶子节点
+			// 	node.Leaf = false
+			// }
+			// 目录下是否包含标段
+			if v.Isfolder == 0 {
+				node.IsBid = true
+			} else {
+				node.HasFolder = true
+			}
+		}
+	}
+}
+
+// 是否有子树
+func havechild(Data []*viewmodels.Tree, node *viewmodels.Tree) (child []*viewmodels.Tree, yes bool) {
+	for _, v := range Data {
+		if v.ParentId == node.Id {
+			child = append(child, v)
+		}
+	}
+	if child != nil {
+		yes = true
+	}
+	return
+}
+
+func transformjson(Data *viewmodels.Tree) { //转为json
+
+	Jsondata, _ := json.Marshal(Data)
+
+	fmt.Println(string(Jsondata))
+}
+
+//now := comm.NowUnix()
+//comm.FormatFromUnixTime(now)
+// ParentIdInt := 0
+// if data.ParentId != "" {
+// 	ParentId, err := comm.AesDecrypt(data.ParentId, conf.SignSecret)
+// 	if err != nil {
+// 		return err
+// 	}
+// 	ParentIdInt, err = strconv.Atoi(ParentId)
+// 	if err != nil {
+// 		ParentIdInt = 0
+// 	}
+// }

+ 0 - 0
services/version_service.go


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini