Przeglądaj źródła

feature(项目): 项目管理更改字段、添加审批流,客户联系人添加字段

ZZH-wl 3 lat temu
rodzic
commit
9406c63879

+ 581 - 20
doc/订单全流程管理平台.pdma.json

@@ -2,9 +2,9 @@
   "name": "订单全流程管理平台",
   "describe": "订单全流程管理平台",
   "avatar": "",
-  "version": "4.2.0",
+  "version": "4.2.2",
   "createdTime": "2023-1-6 11:43:05",
-  "updatedTime": "2023-2-2 09:03:41",
+  "updatedTime": "2023-2-14 08:54:18",
   "dbConns": [],
   "profile": {
     "default": {
@@ -391,7 +391,7 @@
     "generatorDoc": {
       "docTemplate": ""
     },
-    "relationFieldSize": 50,
+    "relationFieldSize": 100,
     "uiHint": [
       {
         "defKey": "Input",
@@ -2736,8 +2736,8 @@
           "id": "47641087-AADF-447E-BE99-655044923F84"
         },
         {
-          "defKey": "postion",
-          "defName": "职位",
+          "defKey": "telephone",
+          "defName": "电话",
           "comment": "",
           "type": "",
           "len": "",
@@ -2750,11 +2750,11 @@
           "refDict": "",
           "extProps": {},
           "domain": "F22E7B6D-ADF0-4D4A-84EF-B7B9C0532DF2",
-          "id": "3E602D6C-EB66-46A0-8105-35E37C2918C7"
+          "id": "2C099ABC-4C1E-4CE6-9811-320206F18DDE"
         },
         {
-          "defKey": "telephone",
-          "defName": "电话",
+          "defKey": "wechat",
+          "defName": "微信",
           "comment": "",
           "type": "",
           "len": "",
@@ -2767,11 +2767,11 @@
           "refDict": "",
           "extProps": {},
           "domain": "F22E7B6D-ADF0-4D4A-84EF-B7B9C0532DF2",
-          "id": "2C099ABC-4C1E-4CE6-9811-320206F18DDE"
+          "id": "A139A4B5-A580-442D-8287-E19E939E1A74"
         },
         {
-          "defKey": "wechat",
-          "defName": "微信",
+          "defKey": "email",
+          "defName": "邮箱",
           "comment": "",
           "type": "",
           "len": "",
@@ -2784,11 +2784,11 @@
           "refDict": "",
           "extProps": {},
           "domain": "F22E7B6D-ADF0-4D4A-84EF-B7B9C0532DF2",
-          "id": "A139A4B5-A580-442D-8287-E19E939E1A74"
+          "id": "C7EBD0FC-14AE-4E80-8A25-2D9F0F7571A6"
         },
         {
-          "defKey": "email",
-          "defName": "邮箱",
+          "defKey": "dept",
+          "defName": "部门",
           "comment": "",
           "type": "",
           "len": "",
@@ -2801,7 +2801,41 @@
           "refDict": "",
           "extProps": {},
           "domain": "F22E7B6D-ADF0-4D4A-84EF-B7B9C0532DF2",
-          "id": "C7EBD0FC-14AE-4E80-8A25-2D9F0F7571A6"
+          "id": "DB571A07-8803-4FA5-833F-200BC2DA6072"
+        },
+        {
+          "defKey": "postion",
+          "defName": "岗位",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": true,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "F22E7B6D-ADF0-4D4A-84EF-B7B9C0532DF2",
+          "id": "3E602D6C-EB66-46A0-8105-35E37C2918C7"
+        },
+        {
+          "defKey": "office_location",
+          "defName": "办公地点",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573",
+          "id": "6B898B16-A0C2-4232-AC76-58A93BA88FAF"
         },
         {
           "defKey": "is_decision",
@@ -4019,6 +4053,23 @@
           "domain": "16120F75-6AA7-4483-868D-F07F511BB081",
           "id": "1FED89AE-896F-45C6-AE36-826C64AE2531"
         },
+        {
+          "defKey": "nbo_code",
+          "defName": "项目编码",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": true,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "5E66BDBA-BED9-4D9C-A364-3AE85B30D071",
+          "id": "C53FD9BB-F50A-4559-8474-4AB9BDEF4DF7"
+        },
         {
           "defKey": "nbo_name",
           "defName": "项目名称",
@@ -4036,6 +4087,23 @@
           "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
           "id": "DCCF7384-3A0D-4D1C-A206-2289320CD6D9"
         },
+        {
+          "defKey": "nbo_status",
+          "defName": "项目状态",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": true,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792",
+          "id": "6A161ED5-E984-4652-81BE-A4C4DB380ABA"
+        },
         {
           "defKey": "cust_id",
           "defName": "关联客户",
@@ -4070,9 +4138,128 @@
           "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
           "id": "98F0FE58-DB09-441B-98FD-C01E9D54C760"
         },
+        {
+          "defKey": "cust_province_id",
+          "defName": "所在省ID",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "16120F75-6AA7-4483-868D-F07F511BB081",
+          "id": "8B0135F2-F515-42F5-8FF6-8F4766875D71"
+        },
+        {
+          "defKey": "cust_province",
+          "defName": "所在省",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
+          "id": "62FA887C-89DA-44B4-8E8F-F0E9E97F86DE"
+        },
+        {
+          "defKey": "cust_city_id",
+          "defName": "所在市ID",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "16120F75-6AA7-4483-868D-F07F511BB081",
+          "id": "2DD07D63-9FA3-4980-9F42-3D4272B785B6"
+        },
+        {
+          "defKey": "cust_city",
+          "defName": "所在市",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
+          "id": "73CEC8D2-6F8B-4633-A9A6-662CB99CE216"
+        },
+        {
+          "defKey": "cust_region_id",
+          "defName": "所在区县ID",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "16120F75-6AA7-4483-868D-F07F511BB081",
+          "id": "6D1F65F7-D273-46DF-9430-77E22EE9D7EB"
+        },
+        {
+          "defKey": "cust_region",
+          "defName": "所在区县",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
+          "id": "08EFEAFB-2753-46EE-9CD9-19B63FAF1C65"
+        },
+        {
+          "defKey": "product_line",
+          "defName": "产品线",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": true,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792",
+          "id": "2AEF1323-F306-472B-8FE7-09BD2B665D56"
+        },
         {
           "defKey": "nbo_type",
-          "defName": "项目类别(A类B类C类)",
+          "defName": "项目级别(A 、B 、C 、成交、储备)",
           "comment": "",
           "type": "",
           "len": "",
@@ -4257,6 +4444,23 @@
           "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
           "id": "7D1332AD-0A26-44F2-89A1-991FA912183B"
         },
+        {
+          "defKey": "maker_dept",
+          "defName": "决策人部门",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573",
+          "id": "C2460E00-B52D-4DD7-AB3F-692FA1007B38"
+        },
         {
           "defKey": "maker_post",
           "defName": "决策人岗位",
@@ -4377,8 +4581,8 @@
           "id": "D5F6B035-7403-4482-B3A1-63A4D1BA2905"
         },
         {
-          "defKey": "obtain_time",
-          "defName": "获取时间",
+          "defKey": "filing_time",
+          "defName": "项目备案时间",
           "comment": "",
           "type": "",
           "len": "",
@@ -4393,6 +4597,40 @@
           "domain": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC",
           "id": "30FCF2FC-D42F-43CF-B810-6816468E5596"
         },
+        {
+          "defKey": "final_follow_id",
+          "defName": "最新跟进人",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "16120F75-6AA7-4483-868D-F07F511BB081",
+          "id": "7D2584AE-304F-4C83-8BB0-CC354F17FFA7"
+        },
+        {
+          "defKey": "final_follow_name",
+          "defName": "最新跟进人名称",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
+          "id": "CE4ECCF2-5516-4344-AA1C-410B54A42C1E"
+        },
         {
           "defKey": "final_follow_time",
           "defName": "最后跟进时间",
@@ -4582,6 +4820,312 @@
           "notes": {},
           "id": "C2AC638C-AE53-4A5E-B376-21BAC4D3B0BF"
         },
+        {
+          "defKey": "is_big",
+          "defName": "是否为大项目",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792",
+          "id": "6E3E93EF-5B49-4AC0-A18A-1C873BCE0E52"
+        },
+        {
+          "defKey": "technical_support_name",
+          "defName": "技术支持人员",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
+          "id": "E47A7980-669C-4B2F-9A89-1B78243B3E70"
+        },
+        {
+          "defKey": "technical_support_content",
+          "defName": "技术支持内容",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573",
+          "id": "CCD2CF0F-23B0-4387-9FE8-23DC3A39EC05"
+        },
+        {
+          "defKey": "technical_support_time",
+          "defName": "技术支持时间",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC",
+          "id": "BE079FD2-8C0D-4B7D-AB3E-82EBDC0D0978"
+        },
+        {
+          "defKey": "customer_satisfaction",
+          "defName": "客户满意度 (10很满意、20满意、30较满意、40一般、50不满意)",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792",
+          "id": "9C91D1EC-F612-448E-9ABF-B931D9F21857"
+        },
+        {
+          "defKey": "parent_receiver",
+          "defName": "总部对接人",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
+          "id": "B035F6D8-7ED2-46D6-83F1-7B9F5193FB7E"
+        },
+        {
+          "defKey": "nbo_budget_time",
+          "defName": "项目预算期限",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC",
+          "id": "BE3E2413-1264-4360-9BC3-4244F06A534E"
+        },
+        {
+          "defKey": "capital_source",
+          "defName": "资金来源",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573",
+          "id": "58DE27B1-5A28-4A03-9493-AED3D17742F4"
+        },
+        {
+          "defKey": "product_satisfaction",
+          "defName": "产品/方案满足情况",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573",
+          "id": "0799B8E9-11B1-4F15-A7D6-68E6805015E0"
+        },
+        {
+          "defKey": "purchasing_way",
+          "defName": "采购方式",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792",
+          "id": "55CC7DE1-E3C7-4549-B1F9-00AB866FF2F3"
+        },
+        {
+          "defKey": "purchasing_time",
+          "defName": "采购时间",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC",
+          "id": "67365F57-848A-41F0-8837-A974B095CC0B"
+        },
+        {
+          "defKey": "is_adopt_dashoo",
+          "defName": "是否采纳大数技术参数(上传附件)",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792",
+          "id": "D1AE3CF1-CAD1-4519-922B-64A021DE01F8"
+        },
+        {
+          "defKey": "historical_transaction_info",
+          "defName": "经销商与客户历史成交信息",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573",
+          "id": "510FCA01-4162-4F5B-BB71-891E4C805E51"
+        },
+        {
+          "defKey": "dealer_sales_id",
+          "defName": "关联经销商销售",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "16120F75-6AA7-4483-868D-F07F511BB081",
+          "id": "175EC238-784F-41D7-8112-0BF4CDF87C6F"
+        },
+        {
+          "defKey": "dealer_sales_name",
+          "defName": "经销商销售人员",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
+          "id": "9C0FFB3B-15B3-4BD2-8F7D-A18CED424A1A"
+        },
+        {
+          "defKey": "accendant",
+          "defName": "维护部门及人员",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573",
+          "id": "6628A419-EA0F-44AF-A044-A9DF64320C28"
+        },
+        {
+          "defKey": "proj_conversion_time",
+          "defName": "项目转化时间",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC",
+          "id": "B9539B41-DDA7-42B4-94B7-D6AC45325136"
+        },
+        {
+          "defKey": "proj_conversion_reason",
+          "defName": "项目转化原因",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": false,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573",
+          "id": "AD77646A-71EB-48B8-8901-EC960FD7D229"
+        },
         {
           "defKey": "remark",
           "defName": "备注",
@@ -8512,8 +9056,8 @@
           "id": "8D41D4FA-8378-4F39-BFD2-9E323F15F4F3"
         },
         {
-          "defKey": "province_code",
-          "defName": "行政区县(省级)",
+          "defKey": "dist_id",
+          "defName": "行政区县ID",
           "comment": "",
           "type": "",
           "len": "",
@@ -8528,6 +9072,23 @@
           "domain": "16120F75-6AA7-4483-868D-F07F511BB081",
           "id": "C9F15FA9-6085-42F2-AE32-03570B14DB56"
         },
+        {
+          "defKey": "dist_name",
+          "defName": "行政区县名称",
+          "comment": "",
+          "type": "",
+          "len": "",
+          "scale": "",
+          "primaryKey": false,
+          "notNull": true,
+          "autoIncrement": false,
+          "defaultValue": "",
+          "hideInGraph": false,
+          "refDict": "",
+          "extProps": {},
+          "domain": "54611CCC-CA4B-42E1-9F32-4944C85B85A6",
+          "id": "1CEFD947-EBEE-417E-B094-9611F9D5187E"
+        },
         {
           "defKey": "remark",
           "defName": "备注",

+ 3 - 3
opms_admin/app/service/sys_user.go

@@ -103,9 +103,9 @@ func (s *UserService) GetUserList(req *model.SysUserSearchReq) (total int, userL
 		insql := dao.NewSysGroupDao(s.Tenant).Fields(dao.SysGroup.Columns.Id).WhereIn(dao.SysGroup.Columns.GroupCode, req.Groups)
 		userModel = userModel.LeftJoin(dao.SysUserGroup.Table, "ug", "sys_user.id=ug.user_id").WhereIn("ug.group_id", insql)
 	}
-	if userModel, err = s.SetDataScopeWhere(userModel); err != nil {
-		return 0, nil, err
-	}
+	//if userModel, err = s.SetDataScopeWhere(userModel); err != nil {
+	//	return 0, nil, err
+	//}
 
 	total, err = userModel.Count()
 	if err != nil {

+ 333 - 53
opms_parent/app/dao/cust/internal/cust_customer_contact.go

@@ -7,11 +7,11 @@ package internal
 import (
 	"context"
 	"database/sql"
-	"time"
-
 	"github.com/gogf/gf/database/gdb"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/frame/gmvc"
+	"github.com/gogf/gf/util/gconv"
+	"time"
 
 	model "dashoo.cn/micro/app/model/cust"
 )
@@ -27,22 +27,25 @@ type CustCustomerContactDao struct {
 
 // CustCustomerContactColumns defines and stores column names for table cust_customer_contact.
 type custCustomerContactColumns struct {
-	Id          string // 主键
-	CustId      string // 关联客户
-	CuctName    string // 姓名
-	CuctGender  string // 性别(10男20女)
-	Postion     string // 职位
-	Telephone   string // 电话
-	Wechat      string // 微信
-	Email       string // 邮箱
-	Remark      string // 备注
-	CreatedBy   string // 创建者
-	CreatedName string // 创建人
-	CreatedTime string // 创建时间
-	UpdatedBy   string // 更新者
-	UpdatedName string // 更新人
-	UpdatedTime string // 更新时间
-	DeletedTime string // 删除时间
+	Id             string // 主键
+	CustId         string // 关联客户
+	CuctName       string // 姓名
+	CuctGender     string // 性别(10男20女)
+	Telephone      string // 电话
+	Wechat         string // 微信
+	Email          string // 邮箱
+	Dept           string // 部门
+	Postion        string // 职位
+	OfficeLocation string // 办公地点
+	IsDecision     string // 关键决策人(10是20否)
+	Remark         string // 备注
+	CreatedBy      string // 创建者
+	CreatedName    string // 创建人
+	CreatedTime    string // 创建时间
+	UpdatedBy      string // 更新者
+	UpdatedName    string // 更新人
+	UpdatedTime    string // 更新时间
+	DeletedTime    string // 删除时间
 }
 
 var (
@@ -52,22 +55,25 @@ var (
 		DB:    g.DB("default"),
 		Table: "cust_customer_contact",
 		Columns: custCustomerContactColumns{
-			Id:          "id",
-			CustId:      "cust_id",
-			CuctName:    "cuct_name",
-			CuctGender:  "cuct_gender",
-			Postion:     "postion",
-			Telephone:   "telephone",
-			Wechat:      "wechat",
-			Email:       "email",
-			Remark:      "remark",
-			CreatedBy:   "created_by",
-			CreatedName: "created_name",
-			CreatedTime: "created_time",
-			UpdatedBy:   "updated_by",
-			UpdatedName: "updated_name",
-			UpdatedTime: "updated_time",
-			DeletedTime: "deleted_time",
+			Id:             "id",
+			CustId:         "cust_id",
+			CuctName:       "cuct_name",
+			CuctGender:     "cuct_gender",
+			Telephone:      "telephone",
+			Wechat:         "wechat",
+			Email:          "email",
+			Dept:           "dept",
+			Postion:        "postion",
+			OfficeLocation: "office_location",
+			IsDecision:     "is_decision",
+			Remark:         "remark",
+			CreatedBy:      "created_by",
+			CreatedName:    "created_name",
+			CreatedTime:    "created_time",
+			UpdatedBy:      "updated_by",
+			UpdatedName:    "updated_name",
+			UpdatedTime:    "updated_time",
+			DeletedTime:    "deleted_time",
 		},
 	}
 )
@@ -79,22 +85,25 @@ func NewCustCustomerContactDao(tenant string) CustCustomerContactDao {
 		DB:    g.DB(tenant),
 		Table: "cust_customer_contact",
 		Columns: custCustomerContactColumns{
-			Id:          "id",
-			CustId:      "cust_id",
-			CuctName:    "cuct_name",
-			CuctGender:  "cuct_gender",
-			Postion:     "postion",
-			Telephone:   "telephone",
-			Wechat:      "wechat",
-			Email:       "email",
-			Remark:      "remark",
-			CreatedBy:   "created_by",
-			CreatedName: "created_name",
-			CreatedTime: "created_time",
-			UpdatedBy:   "updated_by",
-			UpdatedName: "updated_name",
-			UpdatedTime: "updated_time",
-			DeletedTime: "deleted_time",
+			Id:             "id",
+			CustId:         "cust_id",
+			CuctName:       "cuct_name",
+			CuctGender:     "cuct_gender",
+			Telephone:      "telephone",
+			Wechat:         "wechat",
+			Email:          "email",
+			Dept:           "dept",
+			Postion:        "postion",
+			OfficeLocation: "office_location",
+			IsDecision:     "is_decision",
+			Remark:         "remark",
+			CreatedBy:      "created_by",
+			CreatedName:    "created_name",
+			CreatedTime:    "created_time",
+			UpdatedBy:      "updated_by",
+			UpdatedName:    "updated_name",
+			UpdatedTime:    "updated_time",
+			DeletedTime:    "deleted_time",
 		},
 	}
 	return dao
@@ -108,6 +117,12 @@ func (d *CustCustomerContactDao) Ctx(ctx context.Context) *CustCustomerContactDa
 	return &CustCustomerContactDao{M: d.M.Ctx(ctx)}
 }
 
+// GetCtx returns the context for current Model.
+// It returns "context.Background() i"s there's no context previously set.
+func (d *CustCustomerContactDao) GetCtx() context.Context {
+	return d.M.GetCtx()
+}
+
 // As sets an alias name for current table.
 func (d *CustCustomerContactDao) As(as string) *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.As(as)}
@@ -134,6 +149,12 @@ func (d *CustCustomerContactDao) Args(args ...interface{}) *CustCustomerContactD
 	return &CustCustomerContactDao{M: d.M.Args(args...)}
 }
 
+// Handler calls each of "handlers" on current Model and returns a new Model.
+// ModelHandler is a function that handles given Model and returns a new Model that is custom modified.
+func (d *CustCustomerContactDao) Handler(handlers ...gdb.ModelHandler) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.Handler(handlers...)}
+}
+
 // LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
 // The parameter <table> can be joined table and its joined condition,
 // and also with its alias name, like:
@@ -173,7 +194,33 @@ func (d *CustCustomerContactDao) FieldsEx(fieldNamesOrMapStruct ...interface{})
 	return &CustCustomerContactDao{M: d.M.FieldsEx(fieldNamesOrMapStruct...)}
 }
 
-// Option sets the extra operation option for the model.
+// FieldCount formats and appends commonly used field "COUNT(column)" to the select fields of model.
+func (d *CustCustomerContactDao) FieldCount(column string, as ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.FieldCount(column, as...)}
+}
+
+// FieldSum formats and appends commonly used field "SUM(column)" to the select fields of model.
+func (d *CustCustomerContactDao) FieldSum(column string, as ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.FieldSum(column, as...)}
+}
+
+// FieldMin formats and appends commonly used field "MIN(column)" to the select fields of model.
+func (d *CustCustomerContactDao) FieldMin(column string, as ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.FieldMin(column, as...)}
+}
+
+// FieldMax formats and appends commonly used field "MAX(column)" to the select fields of model.
+func (d *CustCustomerContactDao) FieldMax(column string, as ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.FieldMax(column, as...)}
+}
+
+// FieldAvg formats and appends commonly used field "AVG(column)" to the select fields of model.
+func (d *CustCustomerContactDao) FieldAvg(column string, as ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.FieldAvg(column, as...)}
+}
+
+// Option adds extra operation option for the model.
+// Deprecated, use separate operations instead.
 func (d *CustCustomerContactDao) Option(option int) *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.Option(option)}
 }
@@ -184,7 +231,39 @@ func (d *CustCustomerContactDao) OmitEmpty() *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.OmitEmpty()}
 }
 
+// OmitEmptyWhere sets optionOmitEmptyWhere option for the model, which automatically filers
+// the Where/Having parameters for "empty" values.
+func (d *CustCustomerContactDao) OmitEmptyWhere() *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.OmitEmptyWhere()}
+}
+
+// OmitEmptyData sets optionOmitEmptyData option for the model, which automatically filers
+// the Data parameters for "empty" values.
+func (d *CustCustomerContactDao) OmitEmptyData() *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.OmitEmptyData()}
+}
+
+// OmitNil sets optionOmitNil option for the model, which automatically filers
+// the data and where parameters for "nil" values.
+func (d *CustCustomerContactDao) OmitNil() *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.OmitNil()}
+}
+
+// OmitNilWhere sets optionOmitNilWhere option for the model, which automatically filers
+// the Where/Having parameters for "nil" values.
+func (d *CustCustomerContactDao) OmitNilWhere() *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.OmitNilWhere()}
+}
+
+// OmitNilData sets optionOmitNilData option for the model, which automatically filers
+// the Data parameters for "nil" values.
+func (d *CustCustomerContactDao) OmitNilData() *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.OmitNilData()}
+}
+
 // Filter marks filtering the fields which does not exist in the fields of the operated table.
+// Note that this function supports only single table operations.
+// Deprecated, filter feature is automatically enabled from GoFrame v1.16.0, it is so no longer used.
 func (d *CustCustomerContactDao) Filter() *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.Filter()}
 }
@@ -213,18 +292,174 @@ func (d *CustCustomerContactDao) WherePri(where interface{}, args ...interface{}
 	return &CustCustomerContactDao{M: d.M.WherePri(where, args...)}
 }
 
+// Having sets the having statement for the model.
+// The parameters of this function usage are as the same as function Where.
+// See Where.
+func (d *CustCustomerContactDao) Having(having interface{}, args ...interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.Having(having, args...)}
+}
+
+// Wheref builds condition string using fmt.Sprintf and arguments.
+// Note that if the number of "args" is more than the place holder in "format",
+// the extra "args" will be used as the where condition arguments of the Model.
+func (d *CustCustomerContactDao) Wheref(format string, args ...interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.Wheref(format, args...)}
+}
+
+// WhereLT builds "column < value" statement.
+func (d *CustCustomerContactDao) WhereLT(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereLT(column, value)}
+}
+
+// WhereLTE builds "column <= value" statement.
+func (d *CustCustomerContactDao) WhereLTE(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereLTE(column, value)}
+}
+
+// WhereGT builds "column > value" statement.
+func (d *CustCustomerContactDao) WhereGT(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereGT(column, value)}
+}
+
+// WhereGTE builds "column >= value" statement.
+func (d *CustCustomerContactDao) WhereGTE(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereGTE(column, value)}
+}
+
+// WhereBetween builds "column BETWEEN min AND max" statement.
+func (d *CustCustomerContactDao) WhereBetween(column string, min, max interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereBetween(column, min, max)}
+}
+
+// WhereLike builds "column LIKE like" statement.
+func (d *CustCustomerContactDao) WhereLike(column string, like interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereLike(column, like)}
+}
+
+// WhereIn builds "column IN (in)" statement.
+func (d *CustCustomerContactDao) WhereIn(column string, in interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereIn(column, in)}
+}
+
+// WhereNull builds "columns[0] IS NULL AND columns[1] IS NULL ..." statement.
+func (d *CustCustomerContactDao) WhereNull(columns ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereNull(columns...)}
+}
+
+// WhereNotBetween builds "column NOT BETWEEN min AND max" statement.
+func (d *CustCustomerContactDao) WhereNotBetween(column string, min, max interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereNotBetween(column, min, max)}
+}
+
+// WhereNotLike builds "column NOT LIKE like" statement.
+func (d *CustCustomerContactDao) WhereNotLike(column string, like interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereNotLike(column, like)}
+}
+
+// WhereNot builds "column != value" statement.
+func (d *CustCustomerContactDao) WhereNot(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereNot(column, value)}
+}
+
+// WhereNotIn builds "column NOT IN (in)" statement.
+func (d *CustCustomerContactDao) WhereNotIn(column string, in interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereNotIn(column, in)}
+}
+
+// WhereNotNull builds "columns[0] IS NOT NULL AND columns[1] IS NOT NULL ..." statement.
+func (d *CustCustomerContactDao) WhereNotNull(columns ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereNotNull(columns...)}
+}
+
+// WhereOr adds "OR" condition to the where statement.
+func (d *CustCustomerContactDao) WhereOr(where interface{}, args ...interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOr(where, args...)}
+}
+
+// WhereOrf builds "OR" condition string using fmt.Sprintf and arguments.
+func (d *CustCustomerContactDao) WhereOrf(format string, args ...interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrf(format, args...)}
+}
+
+// WhereOrLT builds "column < value" statement in "OR" conditions..
+func (d *CustCustomerContactDao) WhereOrLT(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrLT(column, value)}
+}
+
+// WhereOrLTE builds "column <= value" statement in "OR" conditions..
+func (d *CustCustomerContactDao) WhereOrLTE(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrLTE(column, value)}
+}
+
+// WhereOrGT builds "column > value" statement in "OR" conditions..
+func (d *CustCustomerContactDao) WhereOrGT(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrGT(column, value)}
+}
+
+// WhereOrGTE builds "column >= value" statement in "OR" conditions..
+func (d *CustCustomerContactDao) WhereOrGTE(column string, value interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrGTE(column, value)}
+}
+
+// WhereOrBetween builds "column BETWEEN min AND max" statement in "OR" conditions.
+func (d *CustCustomerContactDao) WhereOrBetween(column string, min, max interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrBetween(column, min, max)}
+}
+
+// WhereOrLike builds "column LIKE like" statement in "OR" conditions.
+func (d *CustCustomerContactDao) WhereOrLike(column string, like interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrLike(column, like)}
+}
+
+// WhereOrIn builds "column IN (in)" statement in "OR" conditions.
+func (d *CustCustomerContactDao) WhereOrIn(column string, in interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrIn(column, in)}
+}
+
+// WhereOrNull builds "columns[0] IS NULL OR columns[1] IS NULL ..." statement in "OR" conditions.
+func (d *CustCustomerContactDao) WhereOrNull(columns ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrNull(columns...)}
+}
+
+// WhereOrNotBetween builds "column NOT BETWEEN min AND max" statement in "OR" conditions.
+func (d *CustCustomerContactDao) WhereOrNotBetween(column string, min, max interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrNotBetween(column, min, max)}
+}
+
+// WhereOrNotLike builds "column NOT LIKE like" statement in "OR" conditions.
+func (d *CustCustomerContactDao) WhereOrNotLike(column string, like interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrNotLike(column, like)}
+}
+
+// WhereOrNotIn builds "column NOT IN (in)" statement.
+func (d *CustCustomerContactDao) WhereOrNotIn(column string, in interface{}) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrNotIn(column, in)}
+}
+
+// WhereOrNotNull builds "columns[0] IS NOT NULL OR columns[1] IS NOT NULL ..." statement in "OR" conditions.
+func (d *CustCustomerContactDao) WhereOrNotNull(columns ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.WhereOrNotNull(columns...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (d *CustCustomerContactDao) Group(groupBy ...string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.Group(groupBy...)}
+}
+
 // And adds "AND" condition to the where statement.
+// Deprecated, use Where instead.
 func (d *CustCustomerContactDao) And(where interface{}, args ...interface{}) *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.And(where, args...)}
 }
 
 // Or adds "OR" condition to the where statement.
+// Deprecated, use WhereOr instead.
 func (d *CustCustomerContactDao) Or(where interface{}, args ...interface{}) *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.Or(where, args...)}
 }
 
-// Group sets the "GROUP BY" statement for the model.
-func (d *CustCustomerContactDao) Group(groupBy string) *CustCustomerContactDao {
+// GroupBy sets the "GROUP BY" statement for the model.
+func (d *CustCustomerContactDao) GroupBy(groupBy string) *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.Group(groupBy)}
 }
 
@@ -233,6 +468,28 @@ func (d *CustCustomerContactDao) Order(orderBy ...string) *CustCustomerContactDa
 	return &CustCustomerContactDao{M: d.M.Order(orderBy...)}
 }
 
+// OrderAsc sets the "ORDER BY xxx ASC" statement for the model.
+func (d *CustCustomerContactDao) OrderAsc(column string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.OrderAsc(column)}
+}
+
+// OrderDesc sets the "ORDER BY xxx DESC" statement for the model.
+func (d *CustCustomerContactDao) OrderDesc(column string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.OrderDesc(column)}
+}
+
+// OrderRandom sets the "ORDER BY RANDOM()" statement for the model.
+func (d *CustCustomerContactDao) OrderRandom() *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.OrderRandom()}
+}
+
+// OrderBy is alias of Model.Order.
+// See Model.Order.
+// Deprecated, use Order instead.
+func (d *CustCustomerContactDao) OrderBy(orderBy string) *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.Order(orderBy)}
+}
+
 // Limit sets the "LIMIT" statement for the model.
 // The parameter <limit> can be either one or two number, if passed two number is passed,
 // it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
@@ -247,6 +504,11 @@ func (d *CustCustomerContactDao) Offset(offset int) *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.Offset(offset)}
 }
 
+// Distinct forces the query to only return distinct results.
+func (d *CustCustomerContactDao) Distinct() *CustCustomerContactDao {
+	return &CustCustomerContactDao{M: d.M.Distinct()}
+}
+
 // Page sets the paging number for the model.
 // The parameter <page> is started from 1 for paging.
 // Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
@@ -440,3 +702,21 @@ func (d *CustCustomerContactDao) LockShared() *CustCustomerContactDao {
 func (d *CustCustomerContactDao) Unscoped() *CustCustomerContactDao {
 	return &CustCustomerContactDao{M: d.M.Unscoped()}
 }
+
+// DataScope enables the DataScope feature.
+func (d *CustCustomerContactDao) DataScope(userCol ...string) *CustCustomerContactDao {
+	ctx := d.GetCtx().Value("contextService")
+	dataScope := gconv.Map(ctx)["dataScope"].(g.Map)
+	if dataScope != nil {
+		if userIds, ok := dataScope["userIds"]; ok {
+			column := "created_by"
+			if len(userCol) == 1 {
+				column = userCol[0]
+			}
+			delete(dataScope, "userIds")
+			dataScope[column] = userIds
+		}
+		return &CustCustomerContactDao{M: d.M.Where(dataScope)}
+	}
+	return d
+}

+ 491 - 135
opms_parent/app/dao/proj/internal/proj_business.go

@@ -10,6 +10,7 @@ import (
 	"github.com/gogf/gf/database/gdb"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/frame/gmvc"
+	"github.com/gogf/gf/util/gconv"
 	"time"
 
 	model "dashoo.cn/micro/app/model/proj"
@@ -26,50 +27,78 @@ type ProjBusinessDao struct {
 
 // ProjBusinessColumns defines and stores column names for table proj_business.
 type projBusinessColumns struct {
-	Id               string // 主键
-	NboCode          string // 项目编号
-	NboName          string // 项目名称
-	NboStatus        string // 项目状态
-	CustId           string // 关联客户
-	CustName         string // 客户名称
-	NboType          string // 项目类别(A类B类C类)
-	NboPhase         string // 项目阶段(暂不起用)
-	NboSource        string // 项目来源
-	NboBudget        string // 项目预算
-	ApproStatus      string // 审批状态(10待提交20审批中30审批通过40审批退回60审批拒绝)
-	ContactId        string // 关联联系人
-	ContactName      string // 联系人姓名
-	ContactPostion   string // 联系人岗位
-	ContactTelephone string // 联系人电话
-	MakerId          string // 关联决策人
-	MakerName        string // 决策人姓名
-	MakerPost        string // 决策人岗位
-	MakerTelephone   string // 决策人电话
-	SalesModel       string // 销售模式(10直销20经销30代理)
-	SaleId           string // 归属销售
-	SaleName         string // 销售姓名
-	DistributorId    string // 经销商/代理商ID
-	DistributorName  string // 经销商/代理商名称
-	ObtainTime       string // 获取时间
-	FinalFollowTime  string // 最后跟进时间
-	NextFollowTime   string // 下次跟进时间
-	PlanPurchaseTime string // 计划采购时间
-	EstTransTime     string // 预计成交时间
-	EstTransPrice    string // 预计成交价格
-	RiskProfile      string // 风险情况
-	Difficulty       string // 困难点
-	Competitor       string // 竞争公司
-	Intervention     string // 介入情况
-	DeptId           string // 所属部门ID
-	DeptName         string // 所属部门
-	Remark           string // 备注
-	CreatedBy        string // 创建者
-	CreatedName      string // 创建人
-	CreatedTime      string // 创建时间
-	UpdatedBy        string // 更新者
-	UpdatedName      string // 更新人
-	UpdatedTime      string // 更新时间
-	DeletedTime      string // 删除时间
+	Id                        string // 主键
+	NboCode                   string // 项目编码
+	NboName                   string // 项目名称
+	NboStatus                 string // 项目状态
+	CustId                    string // 关联客户
+	CustName                  string // 客户名称
+	CustProvinceId            string // 所在省ID
+	CustProvince              string // 所在省
+	CustCityId                string // 所在市ID
+	CustCity                  string // 所在市
+	CustRegionId              string // 所在区县ID
+	CustRegion                string // 所在区县
+	ProductLine               string // 产品线
+	NboType                   string // 项目级别(A 、B 、C 、成交、储备)
+	NboPhase                  string // 项目阶段(暂不起用)
+	NboSource                 string // 项目来源
+	NboBudget                 string // 项目预算
+	ApproStatus               string // 审批状态(10待提交20审批中30审批通过40审批退回60审批拒绝)
+	ContactId                 string // 关联联系人
+	ContactName               string // 联系人姓名
+	ContactPostion            string // 联系人岗位
+	ContactTelephone          string // 联系人电话
+	MakerId                   string // 关联决策人
+	MakerName                 string // 决策人姓名
+	MakerDept                 string // 决策人部门
+	MakerPost                 string // 决策人岗位
+	MakerTelephone            string // 决策人电话
+	SalesModel                string // 销售模式(10直销20经销30代理)
+	SaleId                    string // 归属销售
+	SaleName                  string // 销售姓名
+	DistributorId             string // 经销商/代理商ID
+	DistributorName           string // 经销商/代理商名称
+	FilingTime                string // 项目备案时间
+	FinalFollowId             string // 最新跟进人
+	FinalFollowName           string // 最新跟进人名称
+	FinalFollowTime           string // 最后跟进时间
+	NextFollowTime            string // 下次跟进时间
+	PlanPurchaseTime          string // 计划采购时间
+	EstTransTime              string // 预计成交时间
+	EstTransPrice             string // 预计成交价格
+	RiskProfile               string // 风险情况
+	Difficulty                string // 困难点
+	Competitor                string // 竞争公司
+	Intervention              string // 介入情况
+	DeptId                    string // 所属部门ID
+	DeptName                  string // 所属部门
+	IsBig                     string // 是否为大项目
+	TechnicalSupportName      string // 技术支持人员
+	TechnicalSupportContent   string // 技术支持内容
+	TechnicalSupportTime      string // 技术支持时间
+	CustomerSatisfaction      string // 客户满意度 (10很满意、20满意、30较满意、40一般、50不满意)
+	ParentReceiver            string // 总部对接人
+	NboBudgetTime             string // 项目预算期限
+	CapitalSource             string // 资金来源
+	ProductSatisfaction       string // 产品/方案满足情况
+	PurchasingWay             string // 采购方式
+	PurchasingTime            string // 采购时间
+	IsAdoptDashoo             string // 是否采纳大数技术参数(上传附件)
+	HistoricalTransactionInfo string // 经销商与客户历史成交信息
+	DealerSalesId             string // 关联经销商销售
+	DealerSalesName           string // 经销商销售人员
+	Accendant                 string // 维护部门及人员
+	ProjConversionTime        string // 项目转化时间
+	ProjConversionReason      string // 项目转化原因
+	Remark                    string // 备注
+	CreatedBy                 string // 创建者
+	CreatedName               string // 创建人
+	CreatedTime               string // 创建时间
+	UpdatedBy                 string // 更新者
+	UpdatedName               string // 更新人
+	UpdatedTime               string // 更新时间
+	DeletedTime               string // 删除时间
 }
 
 var (
@@ -79,50 +108,78 @@ var (
 		DB:    g.DB("default"),
 		Table: "proj_business",
 		Columns: projBusinessColumns{
-			Id:               "id",
-			NboCode:          "nbo_code",
-			NboName:          "nbo_name",
-			NboStatus:        "nbo_status",
-			CustId:           "cust_id",
-			CustName:         "cust_name",
-			NboType:          "nbo_type",
-			NboPhase:         "nbo_phase",
-			NboSource:        "nbo_source",
-			NboBudget:        "nbo_budget",
-			ApproStatus:      "appro_status",
-			ContactId:        "contact_id",
-			ContactName:      "contact_name",
-			ContactPostion:   "contact_postion",
-			ContactTelephone: "contact_telephone",
-			MakerId:          "maker_id",
-			MakerName:        "maker_name",
-			MakerPost:        "maker_post",
-			MakerTelephone:   "maker_telephone",
-			SalesModel:       "sales_model",
-			SaleId:           "sale_id",
-			SaleName:         "sale_name",
-			DistributorId:    "distributor_id",
-			DistributorName:  "distributor_name",
-			ObtainTime:       "obtain_time",
-			FinalFollowTime:  "final_follow_time",
-			NextFollowTime:   "next_follow_time",
-			PlanPurchaseTime: "plan_purchase_time",
-			EstTransTime:     "est_trans_time",
-			EstTransPrice:    "est_trans_price",
-			RiskProfile:      "risk_profile",
-			Difficulty:       "difficulty",
-			Competitor:       "competitor",
-			Intervention:     "Intervention",
-			DeptId:           "dept_id",
-			DeptName:         "dept_name",
-			Remark:           "remark",
-			CreatedBy:        "created_by",
-			CreatedName:      "created_name",
-			CreatedTime:      "created_time",
-			UpdatedBy:        "updated_by",
-			UpdatedName:      "updated_name",
-			UpdatedTime:      "updated_time",
-			DeletedTime:      "deleted_time",
+			Id:                        "id",
+			NboCode:                   "nbo_code",
+			NboName:                   "nbo_name",
+			NboStatus:                 "nbo_status",
+			CustId:                    "cust_id",
+			CustName:                  "cust_name",
+			CustProvinceId:            "cust_province_id",
+			CustProvince:              "cust_province",
+			CustCityId:                "cust_city_id",
+			CustCity:                  "cust_city",
+			CustRegionId:              "cust_region_id",
+			CustRegion:                "cust_region",
+			ProductLine:               "product_line",
+			NboType:                   "nbo_type",
+			NboPhase:                  "nbo_phase",
+			NboSource:                 "nbo_source",
+			NboBudget:                 "nbo_budget",
+			ApproStatus:               "appro_status",
+			ContactId:                 "contact_id",
+			ContactName:               "contact_name",
+			ContactPostion:            "contact_postion",
+			ContactTelephone:          "contact_telephone",
+			MakerId:                   "maker_id",
+			MakerName:                 "maker_name",
+			MakerDept:                 "maker_dept",
+			MakerPost:                 "maker_post",
+			MakerTelephone:            "maker_telephone",
+			SalesModel:                "sales_model",
+			SaleId:                    "sale_id",
+			SaleName:                  "sale_name",
+			DistributorId:             "distributor_id",
+			DistributorName:           "distributor_name",
+			FilingTime:                "filing_time",
+			FinalFollowId:             "final_follow_id",
+			FinalFollowName:           "final_follow_name",
+			FinalFollowTime:           "final_follow_time",
+			NextFollowTime:            "next_follow_time",
+			PlanPurchaseTime:          "plan_purchase_time",
+			EstTransTime:              "est_trans_time",
+			EstTransPrice:             "est_trans_price",
+			RiskProfile:               "risk_profile",
+			Difficulty:                "difficulty",
+			Competitor:                "competitor",
+			Intervention:              "Intervention",
+			DeptId:                    "dept_id",
+			DeptName:                  "dept_name",
+			IsBig:                     "is_big",
+			TechnicalSupportName:      "technical_support_name",
+			TechnicalSupportContent:   "technical_support_content",
+			TechnicalSupportTime:      "technical_support_time",
+			CustomerSatisfaction:      "customer_satisfaction",
+			ParentReceiver:            "parent_receiver",
+			NboBudgetTime:             "nbo_budget_time",
+			CapitalSource:             "capital_source",
+			ProductSatisfaction:       "product_satisfaction",
+			PurchasingWay:             "purchasing_way",
+			PurchasingTime:            "purchasing_time",
+			IsAdoptDashoo:             "is_adopt_dashoo",
+			HistoricalTransactionInfo: "historical_transaction_info",
+			DealerSalesId:             "dealer_sales_id",
+			DealerSalesName:           "dealer_sales_name",
+			Accendant:                 "accendant",
+			ProjConversionTime:        "proj_conversion_time",
+			ProjConversionReason:      "proj_conversion_reason",
+			Remark:                    "remark",
+			CreatedBy:                 "created_by",
+			CreatedName:               "created_name",
+			CreatedTime:               "created_time",
+			UpdatedBy:                 "updated_by",
+			UpdatedName:               "updated_name",
+			UpdatedTime:               "updated_time",
+			DeletedTime:               "deleted_time",
 		},
 	}
 )
@@ -134,50 +191,78 @@ func NewProjBusinessDao(tenant string) ProjBusinessDao {
 		DB:    g.DB(tenant),
 		Table: "proj_business",
 		Columns: projBusinessColumns{
-			Id:               "id",
-			NboCode:          "nbo_code",
-			NboName:          "nbo_name",
-			NboStatus:        "nbo_status",
-			CustId:           "cust_id",
-			CustName:         "cust_name",
-			NboType:          "nbo_type",
-			NboPhase:         "nbo_phase",
-			NboSource:        "nbo_source",
-			NboBudget:        "nbo_budget",
-			ApproStatus:      "appro_status",
-			ContactId:        "contact_id",
-			ContactName:      "contact_name",
-			ContactPostion:   "contact_postion",
-			ContactTelephone: "contact_telephone",
-			MakerId:          "maker_id",
-			MakerName:        "maker_name",
-			MakerPost:        "maker_post",
-			MakerTelephone:   "maker_telephone",
-			SalesModel:       "sales_model",
-			SaleId:           "sale_id",
-			SaleName:         "sale_name",
-			DistributorId:    "distributor_id",
-			DistributorName:  "distributor_name",
-			ObtainTime:       "obtain_time",
-			FinalFollowTime:  "final_follow_time",
-			NextFollowTime:   "next_follow_time",
-			PlanPurchaseTime: "plan_purchase_time",
-			EstTransTime:     "est_trans_time",
-			EstTransPrice:    "est_trans_price",
-			RiskProfile:      "risk_profile",
-			Difficulty:       "difficulty",
-			Competitor:       "competitor",
-			Intervention:     "Intervention",
-			DeptId:           "dept_id",
-			DeptName:         "dept_name",
-			Remark:           "remark",
-			CreatedBy:        "created_by",
-			CreatedName:      "created_name",
-			CreatedTime:      "created_time",
-			UpdatedBy:        "updated_by",
-			UpdatedName:      "updated_name",
-			UpdatedTime:      "updated_time",
-			DeletedTime:      "deleted_time",
+			Id:                        "id",
+			NboCode:                   "nbo_code",
+			NboName:                   "nbo_name",
+			NboStatus:                 "nbo_status",
+			CustId:                    "cust_id",
+			CustName:                  "cust_name",
+			CustProvinceId:            "cust_province_id",
+			CustProvince:              "cust_province",
+			CustCityId:                "cust_city_id",
+			CustCity:                  "cust_city",
+			CustRegionId:              "cust_region_id",
+			CustRegion:                "cust_region",
+			ProductLine:               "product_line",
+			NboType:                   "nbo_type",
+			NboPhase:                  "nbo_phase",
+			NboSource:                 "nbo_source",
+			NboBudget:                 "nbo_budget",
+			ApproStatus:               "appro_status",
+			ContactId:                 "contact_id",
+			ContactName:               "contact_name",
+			ContactPostion:            "contact_postion",
+			ContactTelephone:          "contact_telephone",
+			MakerId:                   "maker_id",
+			MakerName:                 "maker_name",
+			MakerDept:                 "maker_dept",
+			MakerPost:                 "maker_post",
+			MakerTelephone:            "maker_telephone",
+			SalesModel:                "sales_model",
+			SaleId:                    "sale_id",
+			SaleName:                  "sale_name",
+			DistributorId:             "distributor_id",
+			DistributorName:           "distributor_name",
+			FilingTime:                "filing_time",
+			FinalFollowId:             "final_follow_id",
+			FinalFollowName:           "final_follow_name",
+			FinalFollowTime:           "final_follow_time",
+			NextFollowTime:            "next_follow_time",
+			PlanPurchaseTime:          "plan_purchase_time",
+			EstTransTime:              "est_trans_time",
+			EstTransPrice:             "est_trans_price",
+			RiskProfile:               "risk_profile",
+			Difficulty:                "difficulty",
+			Competitor:                "competitor",
+			Intervention:              "Intervention",
+			DeptId:                    "dept_id",
+			DeptName:                  "dept_name",
+			IsBig:                     "is_big",
+			TechnicalSupportName:      "technical_support_name",
+			TechnicalSupportContent:   "technical_support_content",
+			TechnicalSupportTime:      "technical_support_time",
+			CustomerSatisfaction:      "customer_satisfaction",
+			ParentReceiver:            "parent_receiver",
+			NboBudgetTime:             "nbo_budget_time",
+			CapitalSource:             "capital_source",
+			ProductSatisfaction:       "product_satisfaction",
+			PurchasingWay:             "purchasing_way",
+			PurchasingTime:            "purchasing_time",
+			IsAdoptDashoo:             "is_adopt_dashoo",
+			HistoricalTransactionInfo: "historical_transaction_info",
+			DealerSalesId:             "dealer_sales_id",
+			DealerSalesName:           "dealer_sales_name",
+			Accendant:                 "accendant",
+			ProjConversionTime:        "proj_conversion_time",
+			ProjConversionReason:      "proj_conversion_reason",
+			Remark:                    "remark",
+			CreatedBy:                 "created_by",
+			CreatedName:               "created_name",
+			CreatedTime:               "created_time",
+			UpdatedBy:                 "updated_by",
+			UpdatedName:               "updated_name",
+			UpdatedTime:               "updated_time",
+			DeletedTime:               "deleted_time",
 		},
 	}
 	return dao
@@ -191,6 +276,12 @@ func (d *ProjBusinessDao) Ctx(ctx context.Context) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Ctx(ctx)}
 }
 
+// GetCtx returns the context for current Model.
+// It returns "context.Background() i"s there's no context previously set.
+func (d *ProjBusinessDao) GetCtx() context.Context {
+	return d.M.GetCtx()
+}
+
 // As sets an alias name for current table.
 func (d *ProjBusinessDao) As(as string) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.As(as)}
@@ -217,6 +308,12 @@ func (d *ProjBusinessDao) Args(args ...interface{}) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Args(args...)}
 }
 
+// Handler calls each of "handlers" on current Model and returns a new Model.
+// ModelHandler is a function that handles given Model and returns a new Model that is custom modified.
+func (d *ProjBusinessDao) Handler(handlers ...gdb.ModelHandler) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.Handler(handlers...)}
+}
+
 // LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
 // The parameter <table> can be joined table and its joined condition,
 // and also with its alias name, like:
@@ -256,7 +353,33 @@ func (d *ProjBusinessDao) FieldsEx(fieldNamesOrMapStruct ...interface{}) *ProjBu
 	return &ProjBusinessDao{M: d.M.FieldsEx(fieldNamesOrMapStruct...)}
 }
 
-// Option sets the extra operation option for the model.
+// FieldCount formats and appends commonly used field "COUNT(column)" to the select fields of model.
+func (d *ProjBusinessDao) FieldCount(column string, as ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.FieldCount(column, as...)}
+}
+
+// FieldSum formats and appends commonly used field "SUM(column)" to the select fields of model.
+func (d *ProjBusinessDao) FieldSum(column string, as ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.FieldSum(column, as...)}
+}
+
+// FieldMin formats and appends commonly used field "MIN(column)" to the select fields of model.
+func (d *ProjBusinessDao) FieldMin(column string, as ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.FieldMin(column, as...)}
+}
+
+// FieldMax formats and appends commonly used field "MAX(column)" to the select fields of model.
+func (d *ProjBusinessDao) FieldMax(column string, as ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.FieldMax(column, as...)}
+}
+
+// FieldAvg formats and appends commonly used field "AVG(column)" to the select fields of model.
+func (d *ProjBusinessDao) FieldAvg(column string, as ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.FieldAvg(column, as...)}
+}
+
+// Option adds extra operation option for the model.
+// Deprecated, use separate operations instead.
 func (d *ProjBusinessDao) Option(option int) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Option(option)}
 }
@@ -267,7 +390,39 @@ func (d *ProjBusinessDao) OmitEmpty() *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.OmitEmpty()}
 }
 
+// OmitEmptyWhere sets optionOmitEmptyWhere option for the model, which automatically filers
+// the Where/Having parameters for "empty" values.
+func (d *ProjBusinessDao) OmitEmptyWhere() *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.OmitEmptyWhere()}
+}
+
+// OmitEmptyData sets optionOmitEmptyData option for the model, which automatically filers
+// the Data parameters for "empty" values.
+func (d *ProjBusinessDao) OmitEmptyData() *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.OmitEmptyData()}
+}
+
+// OmitNil sets optionOmitNil option for the model, which automatically filers
+// the data and where parameters for "nil" values.
+func (d *ProjBusinessDao) OmitNil() *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.OmitNil()}
+}
+
+// OmitNilWhere sets optionOmitNilWhere option for the model, which automatically filers
+// the Where/Having parameters for "nil" values.
+func (d *ProjBusinessDao) OmitNilWhere() *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.OmitNilWhere()}
+}
+
+// OmitNilData sets optionOmitNilData option for the model, which automatically filers
+// the Data parameters for "nil" values.
+func (d *ProjBusinessDao) OmitNilData() *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.OmitNilData()}
+}
+
 // Filter marks filtering the fields which does not exist in the fields of the operated table.
+// Note that this function supports only single table operations.
+// Deprecated, filter feature is automatically enabled from GoFrame v1.16.0, it is so no longer used.
 func (d *ProjBusinessDao) Filter() *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Filter()}
 }
@@ -296,18 +451,174 @@ func (d *ProjBusinessDao) WherePri(where interface{}, args ...interface{}) *Proj
 	return &ProjBusinessDao{M: d.M.WherePri(where, args...)}
 }
 
+// Having sets the having statement for the model.
+// The parameters of this function usage are as the same as function Where.
+// See Where.
+func (d *ProjBusinessDao) Having(having interface{}, args ...interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.Having(having, args...)}
+}
+
+// Wheref builds condition string using fmt.Sprintf and arguments.
+// Note that if the number of "args" is more than the place holder in "format",
+// the extra "args" will be used as the where condition arguments of the Model.
+func (d *ProjBusinessDao) Wheref(format string, args ...interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.Wheref(format, args...)}
+}
+
+// WhereLT builds "column < value" statement.
+func (d *ProjBusinessDao) WhereLT(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereLT(column, value)}
+}
+
+// WhereLTE builds "column <= value" statement.
+func (d *ProjBusinessDao) WhereLTE(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereLTE(column, value)}
+}
+
+// WhereGT builds "column > value" statement.
+func (d *ProjBusinessDao) WhereGT(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereGT(column, value)}
+}
+
+// WhereGTE builds "column >= value" statement.
+func (d *ProjBusinessDao) WhereGTE(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereGTE(column, value)}
+}
+
+// WhereBetween builds "column BETWEEN min AND max" statement.
+func (d *ProjBusinessDao) WhereBetween(column string, min, max interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereBetween(column, min, max)}
+}
+
+// WhereLike builds "column LIKE like" statement.
+func (d *ProjBusinessDao) WhereLike(column string, like interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereLike(column, like)}
+}
+
+// WhereIn builds "column IN (in)" statement.
+func (d *ProjBusinessDao) WhereIn(column string, in interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereIn(column, in)}
+}
+
+// WhereNull builds "columns[0] IS NULL AND columns[1] IS NULL ..." statement.
+func (d *ProjBusinessDao) WhereNull(columns ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereNull(columns...)}
+}
+
+// WhereNotBetween builds "column NOT BETWEEN min AND max" statement.
+func (d *ProjBusinessDao) WhereNotBetween(column string, min, max interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereNotBetween(column, min, max)}
+}
+
+// WhereNotLike builds "column NOT LIKE like" statement.
+func (d *ProjBusinessDao) WhereNotLike(column string, like interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereNotLike(column, like)}
+}
+
+// WhereNot builds "column != value" statement.
+func (d *ProjBusinessDao) WhereNot(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereNot(column, value)}
+}
+
+// WhereNotIn builds "column NOT IN (in)" statement.
+func (d *ProjBusinessDao) WhereNotIn(column string, in interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereNotIn(column, in)}
+}
+
+// WhereNotNull builds "columns[0] IS NOT NULL AND columns[1] IS NOT NULL ..." statement.
+func (d *ProjBusinessDao) WhereNotNull(columns ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereNotNull(columns...)}
+}
+
+// WhereOr adds "OR" condition to the where statement.
+func (d *ProjBusinessDao) WhereOr(where interface{}, args ...interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOr(where, args...)}
+}
+
+// WhereOrf builds "OR" condition string using fmt.Sprintf and arguments.
+func (d *ProjBusinessDao) WhereOrf(format string, args ...interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrf(format, args...)}
+}
+
+// WhereOrLT builds "column < value" statement in "OR" conditions..
+func (d *ProjBusinessDao) WhereOrLT(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrLT(column, value)}
+}
+
+// WhereOrLTE builds "column <= value" statement in "OR" conditions..
+func (d *ProjBusinessDao) WhereOrLTE(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrLTE(column, value)}
+}
+
+// WhereOrGT builds "column > value" statement in "OR" conditions..
+func (d *ProjBusinessDao) WhereOrGT(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrGT(column, value)}
+}
+
+// WhereOrGTE builds "column >= value" statement in "OR" conditions..
+func (d *ProjBusinessDao) WhereOrGTE(column string, value interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrGTE(column, value)}
+}
+
+// WhereOrBetween builds "column BETWEEN min AND max" statement in "OR" conditions.
+func (d *ProjBusinessDao) WhereOrBetween(column string, min, max interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrBetween(column, min, max)}
+}
+
+// WhereOrLike builds "column LIKE like" statement in "OR" conditions.
+func (d *ProjBusinessDao) WhereOrLike(column string, like interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrLike(column, like)}
+}
+
+// WhereOrIn builds "column IN (in)" statement in "OR" conditions.
+func (d *ProjBusinessDao) WhereOrIn(column string, in interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrIn(column, in)}
+}
+
+// WhereOrNull builds "columns[0] IS NULL OR columns[1] IS NULL ..." statement in "OR" conditions.
+func (d *ProjBusinessDao) WhereOrNull(columns ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrNull(columns...)}
+}
+
+// WhereOrNotBetween builds "column NOT BETWEEN min AND max" statement in "OR" conditions.
+func (d *ProjBusinessDao) WhereOrNotBetween(column string, min, max interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrNotBetween(column, min, max)}
+}
+
+// WhereOrNotLike builds "column NOT LIKE like" statement in "OR" conditions.
+func (d *ProjBusinessDao) WhereOrNotLike(column string, like interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrNotLike(column, like)}
+}
+
+// WhereOrNotIn builds "column NOT IN (in)" statement.
+func (d *ProjBusinessDao) WhereOrNotIn(column string, in interface{}) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrNotIn(column, in)}
+}
+
+// WhereOrNotNull builds "columns[0] IS NOT NULL OR columns[1] IS NOT NULL ..." statement in "OR" conditions.
+func (d *ProjBusinessDao) WhereOrNotNull(columns ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.WhereOrNotNull(columns...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (d *ProjBusinessDao) Group(groupBy ...string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.Group(groupBy...)}
+}
+
 // And adds "AND" condition to the where statement.
+// Deprecated, use Where instead.
 func (d *ProjBusinessDao) And(where interface{}, args ...interface{}) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.And(where, args...)}
 }
 
 // Or adds "OR" condition to the where statement.
+// Deprecated, use WhereOr instead.
 func (d *ProjBusinessDao) Or(where interface{}, args ...interface{}) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Or(where, args...)}
 }
 
-// Group sets the "GROUP BY" statement for the model.
-func (d *ProjBusinessDao) Group(groupBy string) *ProjBusinessDao {
+// GroupBy sets the "GROUP BY" statement for the model.
+func (d *ProjBusinessDao) GroupBy(groupBy string) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Group(groupBy)}
 }
 
@@ -316,6 +627,28 @@ func (d *ProjBusinessDao) Order(orderBy ...string) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Order(orderBy...)}
 }
 
+// OrderAsc sets the "ORDER BY xxx ASC" statement for the model.
+func (d *ProjBusinessDao) OrderAsc(column string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.OrderAsc(column)}
+}
+
+// OrderDesc sets the "ORDER BY xxx DESC" statement for the model.
+func (d *ProjBusinessDao) OrderDesc(column string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.OrderDesc(column)}
+}
+
+// OrderRandom sets the "ORDER BY RANDOM()" statement for the model.
+func (d *ProjBusinessDao) OrderRandom() *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.OrderRandom()}
+}
+
+// OrderBy is alias of Model.Order.
+// See Model.Order.
+// Deprecated, use Order instead.
+func (d *ProjBusinessDao) OrderBy(orderBy string) *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.Order(orderBy)}
+}
+
 // Limit sets the "LIMIT" statement for the model.
 // The parameter <limit> can be either one or two number, if passed two number is passed,
 // it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
@@ -330,6 +663,11 @@ func (d *ProjBusinessDao) Offset(offset int) *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Offset(offset)}
 }
 
+// Distinct forces the query to only return distinct results.
+func (d *ProjBusinessDao) Distinct() *ProjBusinessDao {
+	return &ProjBusinessDao{M: d.M.Distinct()}
+}
+
 // Page sets the paging number for the model.
 // The parameter <page> is started from 1 for paging.
 // Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
@@ -523,3 +861,21 @@ func (d *ProjBusinessDao) LockShared() *ProjBusinessDao {
 func (d *ProjBusinessDao) Unscoped() *ProjBusinessDao {
 	return &ProjBusinessDao{M: d.M.Unscoped()}
 }
+
+// DataScope enables the DataScope feature.
+func (d *ProjBusinessDao) DataScope(userCol ...string) *ProjBusinessDao {
+	ctx := d.GetCtx().Value("contextService")
+	dataScope := gconv.Map(ctx)["dataScope"].(g.Map)
+	if dataScope != nil {
+		if userIds, ok := dataScope["userIds"]; ok {
+			column := "created_by"
+			if len(userCol) == 1 {
+				column = userCol[0]
+			}
+			delete(dataScope, "userIds")
+			dataScope[column] = userIds
+		}
+		return &ProjBusinessDao{M: d.M.Where(dataScope)}
+	}
+	return d
+}

+ 70 - 2
opms_parent/app/handler/dingtalk/ding_event.go

@@ -6,6 +6,7 @@ import (
 	custServer "dashoo.cn/micro/app/service/cust"
 	"dashoo.cn/micro/app/service/dingtalk_log"
 	platServer "dashoo.cn/micro/app/service/plat"
+	projService "dashoo.cn/micro/app/service/proj"
 	workflowServer "dashoo.cn/micro/app/service/workflow"
 	"dashoo.cn/opms_libary/plugin/dingtalk"
 	dingContext "dashoo.cn/opms_libary/plugin/dingtalk/context"
@@ -115,9 +116,56 @@ func (h *DingHandler) handleBpmsInstanceChange(msg *message.MixMessage, ctx *din
 			return err.Error()
 		}
 		return "success"
-	case model.ProjectCreate:
+	case model.ProjectUpGrade:
 		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
-			//srv.Handle(instance, msg)
+			srv, err := projService.NewBusinessService(ctx.SubsMessage.Ctx)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+			err = srv.BusinessUpgradeNotify(instance, msg)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+		}
+		err = s.Update(instance, msg)
+		if err != nil {
+			glog.Error(err)
+			return err.Error()
+		}
+		return "success"
+	case model.ProjectDownGrade:
+		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
+			srv, err := projService.NewBusinessService(ctx.SubsMessage.Ctx)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+			err = srv.BusinessDowngradeNotify(instance, msg)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+		}
+		err = s.Update(instance, msg)
+		if err != nil {
+			glog.Error(err)
+			return err.Error()
+		}
+		return "success"
+	case model.ProjectTransfer:
+		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
+			srv, err := projService.NewBusinessService(ctx.SubsMessage.Ctx)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+			err = srv.BusinessTransferNotify(instance, msg)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
 		}
 		err = s.Update(instance, msg)
 		if err != nil {
@@ -125,6 +173,26 @@ func (h *DingHandler) handleBpmsInstanceChange(msg *message.MixMessage, ctx *din
 			return err.Error()
 		}
 		return "success"
+	case model.ProjectToReserve:
+		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
+			srv, err := projService.NewBusinessService(ctx.SubsMessage.Ctx)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+			err = srv.ConvertToReserveNotify(instance, msg)
+			if err != nil {
+				glog.Error(err)
+				return err.Error()
+			}
+		}
+		err = s.Update(instance, msg)
+		if err != nil {
+			glog.Error(err)
+			return err.Error()
+		}
+		return "success"
+
 	case model.ContractCreate:
 		if msg.ProcessType == "finish" || msg.ProcessType == "terminate" {
 			//srv.Handle(instance, msg)

+ 37 - 3
opms_parent/app/handler/proj/business.go

@@ -145,8 +145,8 @@ func (p *BusinessHandler) DeleteByIds(ctx context.Context, req *comm_def.IdsReq,
 	return nil
 }
 
-// BusinessGradation 业务调
-func (p *BusinessHandler) BusinessGradation(ctx context.Context, req *projModel.BusinessGradationReq, rsp *comm_def.CommonMsg) error {
+// BusinessUpgrade 项目升
+func (p *BusinessHandler) BusinessUpgrade(ctx context.Context, req *projModel.BusinessUpgradeReq, rsp *comm_def.CommonMsg) error {
 	// 参数校验
 	if err := gvalid.CheckStruct(ctx, req, nil); err != nil {
 		return err
@@ -155,7 +155,24 @@ func (p *BusinessHandler) BusinessGradation(ctx context.Context, req *projModel.
 	if err != nil {
 		return err
 	}
-	err = businessService.BusinessGradation(req)
+	err = businessService.BusinessUpgrade(req)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// BusinessDowngrade 项目降级
+func (p *BusinessHandler) BusinessDowngrade(ctx context.Context, req *projModel.BusinessDowngradeReq, rsp *comm_def.CommonMsg) error {
+	// 参数校验
+	if err := gvalid.CheckStruct(ctx, req, nil); err != nil {
+		return err
+	}
+	businessService, err := projSrv.NewBusinessService(ctx)
+	if err != nil {
+		return err
+	}
+	err = businessService.BusinessDowngrade(req)
 	if err != nil {
 		return err
 	}
@@ -179,6 +196,23 @@ func (p *BusinessHandler) BusinessTransfer(ctx context.Context, req *projModel.B
 	return nil
 }
 
+// ConvertToReserve 转为储备项目
+func (p *BusinessHandler) ConvertToReserve(ctx context.Context, req *projModel.BusinessToReserveReq, rsp *comm_def.CommonMsg) error {
+	// 参数校验
+	if err := gvalid.CheckStruct(ctx, req, nil); err != nil {
+		return err
+	}
+	businessService, err := projSrv.NewBusinessService(ctx)
+	if err != nil {
+		return err
+	}
+	err = businessService.ConvertToReserve(req)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 // SetPrimacyContact 设置首要联系人
 func (p *BusinessHandler) SetPrimacyContact(ctx context.Context, req *projModel.BusinessPrimacyContactReq, rsp *comm_def.CommonMsg) error {
 	// 参数校验

+ 28 - 25
opms_parent/app/model/cust/cust_customer_contact.go

@@ -15,27 +15,29 @@ import (
 type CustCustomerContact internal.CustCustomerContact
 
 // Fill with you ideas below.
-//添加联系人参数
+// 添加联系人参数
 type CustCustomerContactSeq struct {
-	CustId     int    `   p:"custId"     json:"custId"      v:"required#客户ID不能为空" `              // 关联客户
-	CuctName   string `   p:"cuctName"     json:"cuctName"  v:"required#联系人名字不能为空"`              // 姓名
-	CuctGender string `   p:"cuctGender"    json:"cuctGender"`                                   // 性别(10男20女)
-	Postion    string `   p:"postion"    json:"postion"  `                                       // 职位
-	Telephone  string `   p:"telephone"    json:"telephone"  v:"required|phone#手机号不能为空|手机号格式错误"` // 电话
-	Wechat     string `   p:"wechat"    json:"wechat"`                                           // 微信
-	Email      string `   p:"email"    json:"email" v:"email#邮箱格式错误"`                            // 邮箱
-	Remark     string `   p:"remark"    json:"remark"`                                           // 备注
-	Policy     int    `   p:"policy"     json:"policy"`                                          //
+	CustId         int    `p:"custId"     json:"custId"      v:"required#客户ID不能为空" `                    // 关联客户
+	CuctName       string `p:"cuctName"     json:"cuctName"  v:"required#联系人名字不能为空"`                    // 姓名
+	CuctGender     string `p:"cuctGender"    json:"cuctGender"  v:"required|in:10,20#性别不能为空|填写错误"`      // 性别(10男20女)
+	Telephone      string `p:"telephone"    json:"telephone"  v:"required|phone#手机号不能为空|手机号格式错误"`       // 电话
+	Wechat         string `p:"wechat"    json:"wechat"  v:"required#微信不能为空"`                            // 微信
+	Email          string `p:"email"    json:"email" v:"email#邮箱格式错误"`                                  // 邮箱
+	Dept           string `p:"dept"            json:"dept"  v:"required#部门不能为空"`                        // 部门
+	Postion        string `p:"postion"    json:"postion"   v:"required#岗位不能为空" `                        // 职位
+	OfficeLocation string `p:"officeLocation" json:"officeLocation"`                                    // 办公地点
+	IsDecision     string `p:"isDecision"     json:"isDecision" v:"required|in:10,20#是否关键决策人不能为空|填写错误"` // 关键决策人(10是20否)
+	Remark         string `p:"remark"    json:"remark"`                                                 // 备注
 }
 
-//修改联系人
+// 修改联系人
 type UpdateCustCustomerContactSeq struct {
 	Id     int `  json:"id"      v:"required#ID不能为空" `
 	CustId int `  json:"custId"      v:"required#CustID不能为空" `
 	*CustCustomerContact
 }
 
-//客户联系人信息
+// 客户联系人信息
 type ContactSeq struct {
 	CustId   int    ` p:"custId"  json:"custId"      v:"required#custId不能为空" `
 	CuctName string ` p:"cuctName"  json:"cuctName"       `
@@ -45,17 +47,18 @@ type ContactSeq struct {
 //详情返回字段
 
 type CustCustomerContactInfo struct {
-	Id          int         `orm:"id,primary"   json:"id"`          // 主键
-	CustId      int         `orm:"cust_id"      json:"custId" `     // 关联客户
-	CuctName    string      `orm:"cuct_name"    json:"cuctName"  `  // 姓名
-	CuctGender  string      `orm:"cuct_gender"  json:"cuctGender"`  // 性别(10男20女)
-	Postion     string      `orm:"postion"      json:"postion"`     // 职位
-	Telephone   string      `orm:"telephone"    json:"telephone"`   // 电话
-	Wechat      string      `orm:"wechat"       json:"wechat"`      // 微信
-	Email       string      `orm:"email"        json:"email"`       // 邮箱
-	Policy      int         ` orm:"policy"     json:"policy"`       //是否决策
-	Remark      string      `orm:"remark"       json:"remark"`      // 备注
-	CreatedName string      `orm:"created_name" json:"createdName"` // 创建人
-	CreatedTime *gtime.Time `orm:"created_time" json:"createdTime"` // 创建时间
-
+	Id             int         `orm:"id,primary"   json:"id"`                // 主键
+	CustId         int         `orm:"cust_id"      json:"custId" `           // 关联客户
+	CuctName       string      `orm:"cuct_name"    json:"cuctName"  `        // 姓名
+	CuctGender     string      `orm:"cuct_gender"  json:"cuctGender"`        // 性别(10男20女)
+	Telephone      string      `orm:"telephone"    json:"telephone"`         // 电话
+	Wechat         string      `orm:"wechat"       json:"wechat"`            // 微信
+	Email          string      `orm:"email"        json:"email"`             // 邮箱
+	Dept           string      `orm:"dept"         json:"dept"`              // 部门
+	Postion        string      `orm:"postion"      json:"postion"`           // 职位
+	IsDecision     string      `orm:"is_decision"  json:"isDecision"`        // 关键决策人(10是20否)
+	OfficeLocation string      `orm:"office_location" json:"officeLocation"` // 办公地点
+	Remark         string      `orm:"remark"       json:"remark"`            // 备注
+	CreatedName    string      `orm:"created_name" json:"createdName"`       // 创建人
+	CreatedTime    *gtime.Time `orm:"created_time" json:"createdTime"`       // 创建时间
 }

+ 19 - 17
opms_parent/app/model/cust/internal/cust_customer_contact.go

@@ -10,21 +10,23 @@ import (
 
 // CustCustomerContact is the golang structure for table cust_customer_contact.
 type CustCustomerContact struct {
-	Id          int         `orm:"id,primary"   json:"id"`          // 主键
-	CustId      int         `orm:"cust_id"      json:"custId" `     // 关联客户
-	CuctName    string      `orm:"cuct_name"    json:"cuctName"  `  // 姓名
-	CuctGender  string      `orm:"cuct_gender"  json:"cuctGender"`  // 性别(10男20女)
-	Postion     string      `orm:"postion"      json:"postion"`     // 职位
-	Telephone   string      `orm:"telephone"    json:"telephone"`   // 电话
-	Wechat      string      `orm:"wechat"       json:"wechat"`      // 微信
-	Email       string      `orm:"email"        json:"email"`       // 邮箱
-	Policy      int         ` orm:"policy"     json:"policy"`       //是否决策
-	Remark      string      `orm:"remark"       json:"remark"`      // 备注
-	CreatedBy   int         `orm:"created_by"   json:"createdBy"`   // 创建者
-	CreatedName string      `orm:"created_name" json:"createdName"` // 创建人
-	CreatedTime *gtime.Time `orm:"created_time" json:"createdTime"` // 创建时间
-	UpdatedBy   int         `orm:"updated_by"   json:"updatedBy"`   // 更新者
-	UpdatedName string      `orm:"updated_name" json:"updatedName"` // 更新人
-	UpdatedTime *gtime.Time `orm:"updated_time" json:"updatedTime"` // 更新时间
-	DeletedTime *gtime.Time `orm:"deleted_time" json:"deletedTime"` // 删除时间
+	Id             int         `orm:"id,primary"      json:"id"`             // 主键
+	CustId         int         `orm:"cust_id"         json:"custId"`         // 关联客户
+	CuctName       string      `orm:"cuct_name"       json:"cuctName"`       // 姓名
+	CuctGender     string      `orm:"cuct_gender"     json:"cuctGender"`     // 性别(10男20女)
+	Telephone      string      `orm:"telephone"       json:"telephone"`      // 电话
+	Wechat         string      `orm:"wechat"          json:"wechat"`         // 微信
+	Email          string      `orm:"email"           json:"email"`          // 邮箱
+	Dept           string      `orm:"dept"            json:"dept"`           // 部门
+	Postion        string      `orm:"postion"         json:"postion"`        // 职位
+	OfficeLocation string      `orm:"office_location" json:"officeLocation"` // 办公地点
+	IsDecision     string      `orm:"is_decision"     json:"isDecision"`     // 关键决策人(10是20否)
+	Remark         string      `orm:"remark"          json:"remark"`         // 备注
+	CreatedBy      int         `orm:"created_by"      json:"createdBy"`      // 创建者
+	CreatedName    string      `orm:"created_name"    json:"createdName"`    // 创建人
+	CreatedTime    *gtime.Time `orm:"created_time"    json:"createdTime"`    // 创建时间
+	UpdatedBy      int         `orm:"updated_by"      json:"updatedBy"`      // 更新者
+	UpdatedName    string      `orm:"updated_name"    json:"updatedName"`    // 更新人
+	UpdatedTime    *gtime.Time `orm:"updated_time"    json:"updatedTime"`    // 更新时间
+	DeletedTime    *gtime.Time `orm:"deleted_time"    json:"deletedTime"`    // 删除时间
 }

+ 72 - 44
opms_parent/app/model/proj/internal/proj_business.go

@@ -10,48 +10,76 @@ import (
 
 // ProjBusiness is the golang structure for table proj_business.
 type ProjBusiness struct {
-	Id               int         `orm:"id,primary"         json:"id"`               // 主键
-	NboCode          string      `orm:"nbo_code"           json:"nboCode"`          // 项目编号
-	NboName          string      `orm:"nbo_name"           json:"nboName"`          // 项目名称
-	NboStatus        string      `orm:"nbo_status"         json:"nboStatus"`        // 项目状态
-	CustId           int         `orm:"cust_id"            json:"custId"`           // 关联客户
-	CustName         string      `orm:"cust_name"          json:"custName"`         // 客户名称
-	NboType          string      `orm:"nbo_type"           json:"nboType"`          // 项目类别(A类B类C类)
-	NboPhase         string      `orm:"nbo_phase"          json:"nboPhase"`         // 项目阶段(暂不起用)
-	NboSource        string      `orm:"nbo_source"         json:"nboSource"`        // 项目来源
-	NboBudget        float64     `orm:"nbo_budget"         json:"nboBudget"`        // 项目预算
-	ApproStatus      string      `orm:"appro_status"       json:"approStatus"`      // 审批状态(10待提交20审批中30审批通过40审批退回60审批拒绝)
-	ContactId        int         `orm:"contact_id"         json:"contactId"`        // 关联联系人
-	ContactName      string      `orm:"contact_name"       json:"contactName"`      // 联系人姓名
-	ContactPostion   string      `orm:"contact_postion"    json:"contactPostion"`   // 联系人岗位
-	ContactTelephone string      `orm:"contact_telephone"  json:"contactTelephone"` // 联系人电话
-	MakerId          int         `orm:"maker_id"           json:"makerId"`          // 关联决策人
-	MakerName        string      `orm:"maker_name"         json:"makerName"`        // 决策人姓名
-	MakerPost        string      `orm:"maker_post"         json:"makerPost"`        // 决策人岗位
-	MakerTelephone   string      `orm:"maker_telephone"    json:"makerTelephone"`   // 决策人电话
-	SalesModel       string      `orm:"sales_model"        json:"salesModel"`       // 销售模式(10直销20经销30代理)
-	SaleId           int         `orm:"sale_id"            json:"saleId"`           // 归属销售
-	SaleName         string      `orm:"sale_name"          json:"saleName"`         // 销售姓名
-	DistributorId    int         `orm:"distributor_id"     json:"distributorId"`    // 经销商/代理商ID
-	DistributorName  string      `orm:"distributor_name"   json:"distributorName"`  // 经销商/代理商名称
-	ObtainTime       *gtime.Time `orm:"obtain_time"        json:"obtainTime"`       // 获取时间
-	FinalFollowTime  *gtime.Time `orm:"final_follow_time"  json:"finalFollowTime"`  // 最后跟进时间
-	NextFollowTime   *gtime.Time `orm:"next_follow_time"   json:"nextFollowTime"`   // 下次跟进时间
-	PlanPurchaseTime *gtime.Time `orm:"plan_purchase_time" json:"planPurchaseTime"` // 计划采购时间
-	EstTransTime     *gtime.Time `orm:"est_trans_time"     json:"estTransTime"`     // 预计成交时间
-	EstTransPrice    float64     `orm:"est_trans_price"    json:"estTransPrice"`    // 预计成交价格
-	RiskProfile      string      `orm:"risk_profile"       json:"riskProfile"`      // 风险情况
-	Difficulty       string      `orm:"difficulty"         json:"difficulty"`       // 困难点
-	Competitor       string      `orm:"competitor"         json:"competitor"`       // 竞争公司
-	Intervention     string      `orm:"Intervention"       json:"intervention"`     // 介入情况
-	DeptId           int         `orm:"dept_id"            json:"deptId"`           // 所属部门ID
-	DeptName         string      `orm:"dept_name"          json:"deptName"`         // 所属部门
-	Remark           string      `orm:"remark"             json:"remark"`           // 备注
-	CreatedBy        int         `orm:"created_by"         json:"createdBy"`        // 创建者
-	CreatedName      string      `orm:"created_name"       json:"createdName"`      // 创建人
-	CreatedTime      *gtime.Time `orm:"created_time"       json:"createdTime"`      // 创建时间
-	UpdatedBy        int         `orm:"updated_by"         json:"updatedBy"`        // 更新者
-	UpdatedName      string      `orm:"updated_name"       json:"updatedName"`      // 更新人
-	UpdatedTime      *gtime.Time `orm:"updated_time"       json:"updatedTime"`      // 更新时间
-	DeletedTime      *gtime.Time `orm:"deleted_time"       json:"deletedTime"`      // 删除时间
+	Id                        int         `orm:"id,primary"                  json:"id"`                        // 主键
+	NboCode                   string      `orm:"nbo_code"                    json:"nboCode"`                   // 项目编码
+	NboName                   string      `orm:"nbo_name"                    json:"nboName"`                   // 项目名称
+	NboStatus                 string      `orm:"nbo_status"                  json:"nboStatus"`                 // 项目状态
+	CustId                    int         `orm:"cust_id"                     json:"custId"`                    // 关联客户
+	CustName                  string      `orm:"cust_name"                   json:"custName"`                  // 客户名称
+	CustProvinceId            int         `orm:"cust_province_id"            json:"custProvinceId"`            // 所在省ID
+	CustProvince              string      `orm:"cust_province"               json:"custProvince"`              // 所在省
+	CustCityId                int         `orm:"cust_city_id"                json:"custCityId"`                // 所在市ID
+	CustCity                  string      `orm:"cust_city"                   json:"custCity"`                  // 所在市
+	CustRegionId              int         `orm:"cust_region_id"              json:"custRegionId"`              // 所在区县ID
+	CustRegion                string      `orm:"cust_region"                 json:"custRegion"`                // 所在区县
+	ProductLine               string      `orm:"product_line"                json:"productLine"`               // 产品线
+	NboType                   string      `orm:"nbo_type"                    json:"nboType"`                   // 项目级别(A 、B 、C 、成交、储备)
+	NboPhase                  string      `orm:"nbo_phase"                   json:"nboPhase"`                  // 项目阶段(暂不起用)
+	NboSource                 string      `orm:"nbo_source"                  json:"nboSource"`                 // 项目来源
+	NboBudget                 float64     `orm:"nbo_budget"                  json:"nboBudget"`                 // 项目预算
+	ApproStatus               string      `orm:"appro_status"                json:"approStatus"`               // 审批状态(10待提交20审批中30审批通过40审批退回60审批拒绝)
+	ContactId                 int         `orm:"contact_id"                  json:"contactId"`                 // 关联联系人
+	ContactName               string      `orm:"contact_name"                json:"contactName"`               // 联系人姓名
+	ContactPostion            string      `orm:"contact_postion"             json:"contactPostion"`            // 联系人岗位
+	ContactTelephone          string      `orm:"contact_telephone"           json:"contactTelephone"`          // 联系人电话
+	MakerId                   int         `orm:"maker_id"                    json:"makerId"`                   // 关联决策人
+	MakerName                 string      `orm:"maker_name"                  json:"makerName"`                 // 决策人姓名
+	MakerDept                 string      `orm:"maker_dept"                  json:"makerDept"`                 // 决策人部门
+	MakerPost                 string      `orm:"maker_post"                  json:"makerPost"`                 // 决策人岗位
+	MakerTelephone            string      `orm:"maker_telephone"             json:"makerTelephone"`            // 决策人电话
+	SalesModel                string      `orm:"sales_model"                 json:"salesModel"`                // 销售模式(10直销20经销30代理)
+	SaleId                    int         `orm:"sale_id"                     json:"saleId"`                    // 归属销售
+	SaleName                  string      `orm:"sale_name"                   json:"saleName"`                  // 销售姓名
+	DistributorId             int         `orm:"distributor_id"              json:"distributorId"`             // 经销商/代理商ID
+	DistributorName           string      `orm:"distributor_name"            json:"distributorName"`           // 经销商/代理商名称
+	FilingTime                *gtime.Time `orm:"filing_time"                 json:"filingTime"`                // 项目备案时间
+	FinalFollowId             int         `orm:"final_follow_id"             json:"finalFollowId"`             // 最新跟进人
+	FinalFollowName           string      `orm:"final_follow_name"           json:"finalFollowName"`           // 最新跟进人名称
+	FinalFollowTime           *gtime.Time `orm:"final_follow_time"           json:"finalFollowTime"`           // 最后跟进时间
+	NextFollowTime            *gtime.Time `orm:"next_follow_time"            json:"nextFollowTime"`            // 下次跟进时间
+	PlanPurchaseTime          *gtime.Time `orm:"plan_purchase_time"          json:"planPurchaseTime"`          // 计划采购时间
+	EstTransTime              *gtime.Time `orm:"est_trans_time"              json:"estTransTime"`              // 预计成交时间
+	EstTransPrice             float64     `orm:"est_trans_price"             json:"estTransPrice"`             // 预计成交价格
+	RiskProfile               string      `orm:"risk_profile"                json:"riskProfile"`               // 风险情况
+	Difficulty                string      `orm:"difficulty"                  json:"difficulty"`                // 困难点
+	Competitor                string      `orm:"competitor"                  json:"competitor"`                // 竞争公司
+	Intervention              string      `orm:"Intervention"                json:"intervention"`              // 介入情况
+	DeptId                    int         `orm:"dept_id"                     json:"deptId"`                    // 所属部门ID
+	DeptName                  string      `orm:"dept_name"                   json:"deptName"`                  // 所属部门
+	IsBig                     string      `orm:"is_big"                      json:"isBig"`                     // 是否为大项目
+	TechnicalSupportName      string      `orm:"technical_support_name"      json:"technicalSupportName"`      // 技术支持人员
+	TechnicalSupportContent   string      `orm:"technical_support_content"   json:"technicalSupportContent"`   // 技术支持内容
+	TechnicalSupportTime      *gtime.Time `orm:"technical_support_time"      json:"technicalSupportTime"`      // 技术支持时间
+	CustomerSatisfaction      string      `orm:"customer_satisfaction"       json:"customerSatisfaction"`      // 客户满意度 (10很满意、20满意、30较满意、40一般、50不满意)
+	ParentReceiver            string      `orm:"parent_receiver"             json:"parentReceiver"`            // 总部对接人
+	NboBudgetTime             *gtime.Time `orm:"nbo_budget_time"             json:"nboBudgetTime"`             // 项目预算期限
+	CapitalSource             string      `orm:"capital_source"              json:"capitalSource"`             // 资金来源
+	ProductSatisfaction       string      `orm:"product_satisfaction"        json:"productSatisfaction"`       // 产品/方案满足情况
+	PurchasingWay             string      `orm:"purchasing_way"              json:"purchasingWay"`             // 采购方式
+	PurchasingTime            *gtime.Time `orm:"purchasing_time"             json:"purchasingTime"`            // 采购时间
+	IsAdoptDashoo             string      `orm:"is_adopt_dashoo"             json:"isAdoptDashoo"`             // 是否采纳大数技术参数(上传附件)
+	HistoricalTransactionInfo string      `orm:"historical_transaction_info" json:"historicalTransactionInfo"` // 经销商与客户历史成交信息
+	DealerSalesId             int         `orm:"dealer_sales_id"             json:"dealerSalesId"`             // 关联经销商销售
+	DealerSalesName           string      `orm:"dealer_sales_name"           json:"dealerSalesName"`           // 经销商销售人员
+	Accendant                 string      `orm:"accendant"                   json:"accendant"`                 // 维护部门及人员
+	ProjConversionTime        *gtime.Time `orm:"proj_conversion_time"        json:"projConversionTime"`        // 项目转化时间
+	ProjConversionReason      string      `orm:"proj_conversion_reason"      json:"projConversionReason"`      // 项目转化原因
+	Remark                    string      `orm:"remark"                      json:"remark"`                    // 备注
+	CreatedBy                 int         `orm:"created_by"                  json:"createdBy"`                 // 创建者
+	CreatedName               string      `orm:"created_name"                json:"createdName"`               // 创建人
+	CreatedTime               *gtime.Time `orm:"created_time"                json:"createdTime"`               // 创建时间
+	UpdatedBy                 int         `orm:"updated_by"                  json:"updatedBy"`                 // 更新者
+	UpdatedName               string      `orm:"updated_name"                json:"updatedName"`               // 更新人
+	UpdatedTime               *gtime.Time `orm:"updated_time"                json:"updatedTime"`               // 更新时间
+	DeletedTime               *gtime.Time `orm:"deleted_time"                json:"deletedTime"`               // 删除时间
 }

+ 49 - 6
opms_parent/app/model/proj/proj_business.go

@@ -23,6 +23,12 @@ type ProjBusinessSearchReq struct {
 	request.PageReq
 }
 
+type ProjBusinessRes struct {
+	ProjBusiness
+	ContractAmount  float64     `json:"contractAmount"`  // 合同金额
+	ProjClosingTime *gtime.Time `json:"projClosingTime"` // 合同金额
+}
+
 type AddProjBusinessReq struct {
 	NboName          string `json:"nboName"        v:"required#项目名称不能为空"`                                   // 项目名称
 	CustId           int    `json:"custId"        v:"required#关联客户不能为空"`                                    // 关联客户
@@ -38,8 +44,11 @@ type AddProjBusinessReq struct {
 	DistributorId    int    `json:"distributorId"        v:"required-unless:salesModel,10#经销商/代理商不能为空"`     // 经销商/代理商ID
 	DistributorName  string `json:"distributorName"        v:"required-unless:salesModel,10#经销商/代理商名称不能为空"` // 经销商/代理商名称
 
+	ProductLine string `json:"ProductLine"        v:"required#产品线不能为空"` // 产品线
+	IsBig       string `json:"isBig"        v:"required#是否大项目不能为空"`     // 是否大项目
+
 	NboBudget        float64     `json:"nboBudget"`        // 项目预算
-	ObtainTime       *gtime.Time `json:"obtainTime"`       // 获取时间
+	FilingTime       *gtime.Time `json:"filingTime"`       // 项目备案时间
 	PlanPurchaseTime *gtime.Time `json:"planPurchaseTime"` // 计划采购时间
 	EstTransTime     *gtime.Time `json:"estTransTime"`     // 预计成交时间
 	EstTransPrice    float64     `json:"estTransPrice"`    // 预计成交价格
@@ -79,11 +88,39 @@ type BusinessProduct struct {
 	Remark     string  `json:"remark"`                               // 备注
 }
 
-// BusinessGradationReq 项目调级请求
-type BusinessGradationReq struct {
-	Id      int    `json:"id"        v:"required# id不能为空"`                             // 主键
-	NboType string `json:"nboType"        v:"required|in:A,B,C#项目类别不能为空|项目类别只能为A、B、C"` // 项目类别(A类B类C类)
-	Remark  string `json:"remark"`                                                     // 备注
+// BusinessUpgradeReq 项目升级请求
+type BusinessUpgradeReq struct {
+	Id                      int         `json:"id"                      v:"required# id不能为空"`                     // 主键
+	NboType                 string      `json:"nboType"                 v:"required|in:10,20,30#项目级别不能为空|项目级别错误"` // 项目级别
+	NboBudget               float64     `json:"nboBudget"               v:"required#项目预算不能为空"`                    // 项目预算
+	DistributorId           int         `json:"distributorId"           v:"required#经销商/代理商不能为空"`                 // 经销商/代理商ID
+	DistributorName         string      `json:"distributorName"         v:"required#经销商/代理商名称不能为空"`               // 经销商/代理商名称
+	TechnicalSupportName    string      `json:"technicalSupportName"    v:"required# 技术支持人员不能为空"`                 // 技术支持人员
+	TechnicalSupportContent string      `json:"technicalSupportContent" v:"required# 技术支持内容不能为空"`                 // 技术支持内容
+	TechnicalSupportTime    *gtime.Time `json:"technicalSupportTime"    v:"required# 技术支持时间不能为空"`                 // 技术支持时间
+	//CustomerSatisfaction      string      `json:"customerSatisfaction"`      // 客户满意度 (10很满意、20满意、30较满意、40一般、50不满意)
+	ParentReceiver            string      `json:"parentReceiver"`                // 总部对接人
+	NboBudgetTime             *gtime.Time `json:"nboBudgetTime"`                 // 项目预算期限
+	CapitalSource             string      `json:"capitalSource"`                 // 资金来源
+	ProductSatisfaction       string      `json:"productSatisfaction"`           // 产品/方案满足情况
+	PurchasingWay             string      `json:"purchasingWay"`                 // 采购方式
+	PurchasingTime            *gtime.Time `json:"purchasingTime"`                // 采购时间
+	IsAdoptDashoo             string      `json:"isAdoptDashoo"`                 // 是否采纳大数技术参数(上传附件)
+	HistoricalTransactionInfo string      `json:"historicalTransactionInfo"`     // 经销商与客户历史成交信息
+	DealerSalesId             int         `json:"dealerSalesId"`                 // 关联经销商销售
+	DealerSalesName           string      `json:"dealerSalesName"`               // 经销商销售人员
+	Accendant                 string      `json:"accendant"`                     // 维护部门及人员
+	Remark                    string      `json:"remark" v:"required# 备注原因不能为空"` // 备注
+}
+
+// BusinessDowngradeReq 项目降级请求
+type BusinessDowngradeReq struct {
+	Id                      int         `json:"id"        v:"required# id不能为空"`                             // 主键
+	NboType                 string      `json:"nboType"        v:"required|in:10,20,30,50#项目级别不能为空|项目级别错误"` // 项目级别
+	TechnicalSupportName    string      `json:"technicalSupportName"`                                       // 技术支持人员
+	TechnicalSupportContent string      `json:"technicalSupportContent" v:"required# 技术支持内容不能为空"`           // 技术支持内容
+	TechnicalSupportTime    *gtime.Time `json:"technicalSupportTime"`                                       // 技术支持时间
+	Remark                  string      `json:"remark" v:"required# 备注原因不能为空"`                              // 备注原因
 }
 
 // BusinessTransferReq 项目转移请求
@@ -94,6 +131,12 @@ type BusinessTransferReq struct {
 	Remark   string `json:"remark"`                                // 备注
 }
 
+// BusinessToReserveReq 项目转为储备项目
+type BusinessToReserveReq struct {
+	Id                   int    `json:"id"        v:"required# id不能为空"`                       // 主键
+	ProjConversionReason string `json:"projConversionReason"        v:"required# 项目转化原因不能为空"` // 项目转化原因
+}
+
 // BusinessPrimacyContactReq 设置首要联系人请求
 type BusinessPrimacyContactReq struct {
 	Id               int    `json:"id"        v:"required# id不能为空"`            // 主键

+ 13 - 11
opms_parent/app/model/proj/proj_business_contact.go

@@ -15,17 +15,19 @@ type ProjBusinessContact internal.ProjBusinessContact
 // Fill with you ideas below.
 
 type BusinessContact struct {
-	Id         int    `json:"id"`         // 主键
-	BusId      int    `json:"busId"`      // 关联项目
-	ContactId  int    `json:"contactId"`  // 联系人主键
-	CustId     int    `json:"custId" `    // 关联客户
-	CuctName   string `json:"cuctName"  ` // 姓名
-	CuctGender string `json:"cuctGender"` // 性别(10男20女)
-	Postion    string `json:"postion"`    // 职位
-	Telephone  string `json:"telephone"`  // 电话
-	Wechat     string `json:"wechat"`     // 微信
-	Email      string `json:"email"`      // 邮箱
-	Policy     int    `json:"policy"`     //是否决策
+	Id             int    `json:"id"`             // 主键
+	BusId          int    `json:"busId"`          // 关联项目
+	ContactId      int    `json:"contactId"`      // 联系人主键
+	CustId         int    `json:"custId" `        // 关联客户
+	CuctName       string `json:"cuctName"  `     // 姓名
+	CuctGender     string `json:"cuctGender"`     // 性别(10男20女)
+	Telephone      string `json:"telephone"`      // 电话
+	Wechat         string `json:"wechat"`         // 微信
+	Email          string `json:"email"`          // 邮箱
+	Dept           string `json:"dept"`           // 部门
+	Postion        string `json:"postion"`        // 职位
+	OfficeLocation string `json:"officeLocation"` // 办公地点
+	IsDecision     string `json:"isDecision"`     // 关键决策人(10是20否)
 }
 
 // BusinessContactSearchReq 获取项目关联联系人信息

+ 9 - 3
opms_parent/app/model/workflow/plat_workflow.go

@@ -11,9 +11,15 @@ import (
 
 // BizType 业务类型(10领用20项目创建30合同创建)
 const (
-	CustomerReceive = "11" // 领取公海客户
-	ProjectCreate   = "20" // 项目创建
-	ContractCreate  = "30" // 合同创建
+	CustomerReceive  = "11" // 领取公海客户
+	ProjectCreate    = "20" // 项目创建
+	ProjectUpGrade   = "21" // 项目升级审批
+	ProjectDownGrade = "22" // 项目降级审批
+	ProjectTransfer  = "23" // 项目转移项目审批
+	ProjectToReserve = "24" // 项目转为储备项目审批
+	ProjectPersonnel = "25" // 项目协同人员审批
+
+	ContractCreate = "30" // 合同创建
 )
 
 // PlatWorkflow is the golang structure for table plat_workflow.

+ 635 - 47
opms_parent/app/service/proj/business.go

@@ -2,11 +2,18 @@ package proj
 
 import (
 	"context"
+	contractDao "dashoo.cn/micro/app/dao/contract"
+	custDao "dashoo.cn/micro/app/dao/cust"
 	projDao "dashoo.cn/micro/app/dao/proj"
 	model "dashoo.cn/micro/app/model/proj"
+	workflowModel "dashoo.cn/micro/app/model/workflow"
 	"dashoo.cn/micro/app/service"
+	workflowService "dashoo.cn/micro/app/service/workflow"
 	"dashoo.cn/opms_libary/myerrors"
+	"dashoo.cn/opms_libary/plugin/dingtalk/message"
+	"dashoo.cn/opms_libary/plugin/dingtalk/workflow"
 	"dashoo.cn/opms_libary/utils"
+	"fmt"
 	"github.com/gogf/gf/database/gdb"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/os/gtime"
@@ -16,18 +23,6 @@ import (
 	"strings"
 )
 
-const (
-	OpnCreate         = "10" // 创建动态
-	OpnUpdate         = "20" // 更新动态
-	OpnTransfer       = "30" // 转移动态
-	OpnRise           = "40" // 升级动态
-	OpnDrop           = "50" // 降级动态
-	OpnPrimacyContact = "60" // 设置首要联系人动态
-	OpnStatus         = "70" // 更新项目状态动态
-	OpnAssociation    = "80" // 关联联系人动态
-	OpnDisassociation = "90" // 解除关联联系人动态
-)
-
 type businessService struct {
 	*service.ContextService
 	Dao *projDao.ProjBusinessDao
@@ -42,19 +37,19 @@ func NewBusinessService(ctx context.Context) (svc *businessService, err error) {
 	return svc, nil
 }
 
-func (p *businessService) GetList(req *model.ProjBusinessSearchReq) (total int, businessList []*model.ProjBusiness, err error) {
-	db := p.Dao.M
+func (p *businessService) GetList(req *model.ProjBusinessSearchReq) (total int, businessList []*model.ProjBusinessRes, err error) {
+	db := p.Dao.M.As("proj")
 	if req.NboName != "" {
-		db = db.WhereLike(p.Dao.Columns.NboName, "%"+req.NboName+"%")
+		db = db.WhereLike("proj."+p.Dao.Columns.NboName, "%"+req.NboName+"%")
 	}
 	if req.CustName != "" {
-		db = db.WhereLike(p.Dao.Columns.CustName, "%"+req.CustName+"%")
+		db = db.WhereLike("proj."+p.Dao.Columns.CustName, "%"+req.CustName+"%")
 	}
 	if req.SaleName != "" {
-		db = db.WhereLike(p.Dao.Columns.SaleName, "%"+req.SaleName+"%")
+		db = db.WhereLike("proj."+p.Dao.Columns.SaleName, "%"+req.SaleName+"%")
 	}
 	if req.NboType != "" {
-		db = db.Where(p.Dao.Columns.NboType, req.NboType)
+		db = db.Where("proj."+p.Dao.Columns.NboType, req.NboType)
 	}
 	total, err = db.Count()
 	if err != nil {
@@ -62,7 +57,8 @@ func (p *businessService) GetList(req *model.ProjBusinessSearchReq) (total int,
 		err = myerrors.DbError("获取总行数失败。")
 		return
 	}
-
+	db = db.LeftJoin(contractDao.CtrContract.Table, "contract", "proj.id=contract.nbo_id").
+		Fields("proj.*,contract.contract_amount, contract.created_time as projClosingTime").Group("id")
 	err = db.Page(req.PageNum, req.PageSize).Order("id asc").Scan(&businessList)
 	return
 }
@@ -118,7 +114,7 @@ func (p *businessService) GetBusinessDynamics(req *model.BusinessReq) (total int
 }
 
 func (p *businessService) GetBusinessDynamicsList(req *model.BusinessDynamicsReq) (total int, list []map[string]interface{}, err error) {
-	dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).ProjBusinessDynamicsDao.Where(projDao.ProjBusinessDynamics.Columns.BusId, req.BusId)
+	dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).Where(projDao.ProjBusinessDynamics.Columns.BusId, req.BusId)
 	if req.OpnType != "" {
 		dynamicsDao = dynamicsDao.Where(projDao.ProjBusinessDynamics.Columns.OpnType+" = ?", req.OpnType)
 	}
@@ -137,7 +133,25 @@ func (p *businessService) GetBusinessDynamicsList(req *model.BusinessDynamicsReq
 	return
 }
 
+// 获取项目编号
+func (s *businessService) getNboCode(customerCode string) (string, error) {
+	sequence, err := service.Sequence(s.Dao.DB, "nbo_code")
+	if err != nil {
+		return "", err
+	}
+	return customerCode + sequence, nil
+}
+
 func (p *businessService) Create(req *model.AddProjBusinessReq) (err error) {
+	// 获取客户信息
+	customer, err := custDao.NewCustCustomerDao(p.Tenant).WherePri(req.CustId).One()
+	if err != nil {
+		return err
+	}
+	if customer == nil {
+		return myerrors.TipsError("客户不存在")
+	}
+
 	// 设置默认联系人
 	contact := g.Map{
 		projDao.ProjBusinessContact.Columns.ContactId: req.ContactId,
@@ -149,16 +163,28 @@ func (p *businessService) Create(req *model.AddProjBusinessReq) (err error) {
 	if err != nil {
 		return err
 	}
+
+	// 获取项目编号
+	nboCode, err := p.getNboCode(customer.CustCode)
+	if err != nil {
+		return err
+	}
 	// 初始化项目信息
 	businessData := new(model.ProjBusiness)
 	if err = gconv.Struct(req, businessData); err != nil {
 		return
 	}
-	businessData.NboCode = "NBO" + strconv.Itoa(int(gtime.Timestamp()))
-	businessData.NboStatus = "10"
-	businessData.NboType = "C"
-	businessData.ApproStatus = "10"
+	businessData.NboCode = nboCode
+	//businessData.NboStatus = StatusOK
+	businessData.NboType = StatusC
+	businessData.ApproStatus = ApprovalNotSubmit
 	businessData.EstTransPrice = totalPrice
+	businessData.CustProvinceId = customer.CustProvinceId
+	businessData.CustProvince = customer.CustProvince
+	businessData.CustCityId = customer.CustCityId
+	businessData.CustCity = customer.CustCity
+	businessData.CustRegionId = customer.CustRegionId
+	businessData.CustRegion = customer.CustRegion
 	businessData.DeptId = p.GetCxtUserDeptId()
 	service.SetCreatedInfo(businessData, p.GetCxtUserId(), p.GetCxtUserName())
 	// 事务
@@ -289,23 +315,26 @@ func (p *businessService) DeleteByIds(ids []int64) (err error) {
 
 // BusinessTransfer 项目转移
 func (p *businessService) BusinessTransfer(req *model.BusinessTransferReq) error {
-	business, err := p.Dao.WherePri(req.Id).One()
+	business, err := p.Dao.WherePri(req.Id).Where(p.Dao.Columns.ApproStatus, ApprovalNotSubmit).One()
 	if err != nil {
 		return err
 	}
 	if business == nil {
-		return myerrors.TipsError("项目不存在。")
+		return myerrors.TipsError("项目已提交审批任务,无法重复提交。")
 	}
 	businessMap := g.Map{
-		p.Dao.Columns.SaleId:   req.UserId,
-		p.Dao.Columns.SaleName: req.UserName,
-		p.Dao.Columns.Remark:   req.Remark,
+		p.Dao.Columns.ApproStatus: ApprovalWaiting,
 	}
 	service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
 
 	opnContent := businessMap
 	opnContent["origSaleId"] = business.SaleId
 	opnContent["origSaleName"] = business.SaleName
+	opnContent["saleId"] = req.UserId
+	opnContent["saleName"] = req.UserName
+	opnContent["remark"] = req.Remark
+	// 审批流
+	workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
 	err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
 		// 更新项目
 		_, err = p.Dao.TX(tx).WherePri(projDao.ProjBusiness.Columns.Id, req.Id).Data(businessMap).Update()
@@ -319,54 +348,465 @@ func (p *businessService) BusinessTransfer(req *model.BusinessTransferReq) error
 			Remark:  req.Remark,
 		}
 		err = p.CreateProjBusinessDynamics(tx, dynamics, opnContent)
-		return err
+		if err != nil {
+			g.Log().Error(err)
+			return err
+		}
+
+		// OMS项目转移 审批
+		bizCode := business.NboCode + ":" + strconv.Itoa(business.Id)
+		_, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectTransfer, &workflow.StartProcessInstanceRequest{
+			ProcessCode: &BusinessTransferRequestProcessCode,
+			FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
+				{
+					Id:    utils.String("TextField-K2AD4O5B"),
+					Name:  utils.String("项目编码"),
+					Value: utils.String(business.NboCode),
+				},
+				{
+					Id:    utils.String("TextField_7EFHRQ9DDF80"),
+					Name:  utils.String("项目名称"),
+					Value: utils.String(business.NboName),
+				},
+				{
+					Id:    utils.String("TextField_1T3DEY5FWV7K0"),
+					Name:  utils.String("客户名称"),
+					Value: utils.String(business.CustName),
+				},
+				{
+					Id:    utils.String("TextField_QDU06LXYKK00"),
+					Name:  utils.String("所在省"),
+					Value: utils.String(business.CustProvince),
+				},
+				{
+					Id:    utils.String("TextField_MVSOO6EG6YO0"),
+					Name:  utils.String("所在市"),
+					Value: utils.String(business.CustCity),
+				},
+				{
+					Id:    utils.String("TextField_1E1WOYGKRTDS0"),
+					Name:  utils.String("项目级别"),
+					Value: utils.String(nboType[business.NboType]),
+				},
+				{
+					Id:    utils.String("TextField_NRQXWLJ17HC0"),
+					Name:  utils.String("申请人"),
+					Value: utils.String(p.GetCxtUserName()),
+				},
+				{
+					Id:    utils.String("TextField_GHSQYDGD13K0"),
+					Name:  utils.String("转移原因"),
+					Value: utils.String(req.Remark),
+				},
+				{
+					Id:    utils.String("TextField_76P8FPHH0UC0"),
+					Name:  utils.String("接收人"),
+					Value: utils.String(req.UserName),
+				},
+			},
+		})
+		if err != nil {
+			g.Log().Error(err)
+			return err
+		}
+		return nil
 	})
 	return err
 }
 
-// BusinessGradation 项目调级
-func (p *businessService) BusinessGradation(req *model.BusinessGradationReq) error {
-	business, err := p.Dao.Where(projDao.ProjBusiness.Columns.Id, req.Id).One()
+// BusinessTransferNotify 项目转移 审批结果通知
+func (p *businessService) BusinessTransferNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
+	business, err := p.checkDingTalkNotify(flow, msg)
 	if err != nil {
 		return err
 	}
+
+	var data = g.Map{}
+	if msg.ProcessType == "terminate" {
+		data[p.Dao.Columns.ApproStatus] = ApprovalReturn
+	}
+	if msg.ProcessType == "finish" && msg.Result != "refuse" {
+		data[p.Dao.Columns.ApproStatus] = ApprovalRejection
+	}
+	if msg.ProcessType == "finish" && msg.Result == "agree" {
+		data[p.Dao.Columns.NboType] = StatusReserve
+		data[p.Dao.Columns.ApproStatus] = ApprovalOK
+		// 从项目动态内获取变更信息
+		var transferDynamics model.ProjBusinessDynamics
+		dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).Where(projDao.ProjBusinessDynamics.Columns.BusId, business.Id)
+		err = dynamicsDao.Where(projDao.ProjBusinessDynamics.Columns.OpnType, OpnTransfer).OrderDesc("created_time").Scan(&transferDynamics)
+		if err != nil {
+			return err
+		}
+		changeData := gconv.Map(transferDynamics.OpnContent)
+		data[p.Dao.Columns.SaleId] = changeData["saleId"]
+		data[p.Dao.Columns.SaleName] = changeData["saleName"]
+		data[p.Dao.Columns.Remark] = changeData["remark"]
+
+	}
+
+	// 项目修改
+	_, err = p.Dao.WherePri(business.Id).Data(data).Update()
+
+	// 添加项目动态
+	dynamics := model.ProjBusinessDynamics{
+		BusId:   business.Id,
+		OpnType: OpnTransferApproval,
+	}
+	err = p.CreateProjBusinessDynamics(nil, dynamics, data)
+	if err != nil {
+		return err
+	}
+	return err
+}
+
+// BusinessGradation 项目调级
+func (p *businessService) BusinessGradation(busId int, nboType, busType string) (*model.ProjBusiness, error) {
+	business, err := p.Dao.WherePri(busId).Where(p.Dao.Columns.ApproStatus, ApprovalNotSubmit).One()
+	if err != nil {
+		return nil, err
+	}
 	if business == nil {
-		return myerrors.TipsError("项目不存在。")
+		return nil, myerrors.TipsError("项目已提交审批任务,无法重复提交。")
+	}
+	if business.NboType == nboType {
+		return nil, myerrors.TipsError("同级别无法进行调级。")
+	}
+	if business.NboType == StatusDeal {
+		return nil, myerrors.TipsError("成交项目无法进行调级。")
 	}
-	if business.NboType == req.NboType {
-		return myerrors.TipsError("同级无法进行调级。")
+	if business.NboType == StatusReserve && nboType == StatusDeal {
+		return nil, myerrors.TipsError("储备项目无法直接转为成交项目。")
 	}
-	opnType := OpnRise
-	// A < B return -1 项目降级
-	if strings.Compare(business.NboType, req.NboType) < 0 {
-		opnType = OpnDrop
+	if busType == "up" && gconv.Int(business.NboType) < gconv.Int(nboType) {
+		return nil, myerrors.TipsError("项目级别错误。")
 	}
+	if busType == "down" && gconv.Int(business.NboType) > gconv.Int(nboType) {
+		return nil, myerrors.TipsError("项目级别错误。")
+	}
+	return business, err
+}
 
+// BusinessUpgrade 项目升级
+func (p *businessService) BusinessUpgrade(req *model.BusinessUpgradeReq) error {
+	business, err := p.BusinessGradation(req.Id, req.NboType, "up")
+	if err != nil {
+		return err
+	}
+	var upgradeType string
+	switch true {
+	case business.NboType == StatusC && req.NboType == StatusB:
+		upgradeType = "option_0"
+	case business.NboType == StatusB && req.NboType == StatusA:
+		upgradeType = "option_1"
+	case business.NboType == StatusC && req.NboType == StatusA:
+		upgradeType = "option_2"
+	default:
+		return myerrors.TipsError("错误的升级类型")
+	}
+	fmt.Println(upgradeType)
 	businessMap := g.Map{
-		p.Dao.Columns.NboType: req.NboType,
+		p.Dao.Columns.ApproStatus: ApprovalWaiting,
 	}
 	service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
+
+	opnContent := gconv.Map(req)
+	opnContent["origNboType"] = business.NboType
+	opnContent["approStatus"] = ApprovalWaiting
+	service.SetUpdatedInfo(opnContent, p.GetCxtUserId(), p.GetCxtUserName())
+
+	// 审批流
+	workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
 	err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
 		// 更新项目调级
-		_, err = p.Dao.TX(tx).WherePri(projDao.ProjBusiness.Columns.Id, req.Id).Data(businessMap).Update()
+		_, err = p.Dao.TX(tx).WherePri(req.Id).Data(businessMap).Update()
 		if err != nil {
 			return err
 		}
 		// 添加项目动态
 		dynamics := model.ProjBusinessDynamics{
 			BusId:   business.Id,
-			OpnType: opnType,
+			OpnType: OpnUpgrade,
 			Remark:  req.Remark,
 		}
-		err = p.CreateProjBusinessDynamics(tx, dynamics, g.Map{
-			"origNboType": business.NboType,
-			"nboType":     req.NboType,
+		err = p.CreateProjBusinessDynamics(tx, dynamics, opnContent)
+		if err != nil {
+			return err
+		}
+		// OMS项目降级 审批
+		bizCode := business.NboCode + ":" + strconv.Itoa(business.Id)
+		_, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectUpGrade, &workflow.StartProcessInstanceRequest{
+			ProcessCode: &BusinessUpgradeRequestProcessCode,
+			FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
+				{
+					Id:    utils.String("TextField-K2AD4O5B"),
+					Name:  utils.String("项目编码"),
+					Value: utils.String(business.NboCode),
+				},
+				{
+					Id:    utils.String("TextField_BDLSECETVSG0"),
+					Name:  utils.String("项目名称"),
+					Value: utils.String(business.NboName),
+				},
+				{
+					Id:    utils.String("DDSelectField_VSA3U380ZK00"),
+					Name:  utils.String("升级类型"),
+					Value: utils.String(upgradeType),
+				},
+				{
+					Id:    utils.String("TextField_1J9BJMOZ18F40"),
+					Name:  utils.String("客户名称"),
+					Value: utils.String(business.CustName),
+				},
+				{
+					Id:    utils.String("NumberField_1F88MCD0W8KG0"),
+					Name:  utils.String("项目预算"),
+					Value: utils.String(gconv.String(req.NboBudget)),
+				},
+				{
+					Id:    utils.String("TextField_1PWK6WHMGITC0"),
+					Name:  utils.String("经销商/代理商"),
+					Value: utils.String(req.DistributorName),
+				},
+				{
+					Id:    utils.String("TextField_X4D3QGARU7K0"),
+					Name:  utils.String("支持内容"),
+					Value: utils.String(req.TechnicalSupportContent),
+				},
+				{
+					Id:    utils.String("TextField_AEUWH63LJ0O0"),
+					Name:  utils.String("销售工程师"),
+					Value: utils.String(business.SaleName),
+				},
+				{
+					Id:    utils.String("DDDateField_1FW1QZQYBZVK0"),
+					Name:  utils.String("采购时间"),
+					Value: utils.String(gconv.String(req.PurchasingTime.Format("Y-m-d"))),
+				},
+				{
+					Id:    utils.String("DDSelectField_21ASEWDIB3MO0"),
+					Name:  utils.String("采购方式"),
+					Value: utils.String(gconv.String(purchasingWayType[req.PurchasingWay])),
+				},
+				{
+					Id:    utils.String("DDSelectField_5R11VVM6GI00"),
+					Name:  utils.String("是否我司参数"),
+					Value: utils.String(gconv.String(yesOrNoType[req.IsAdoptDashoo])),
+				},
+			},
 		})
+		if err != nil {
+			g.Log().Error(err)
+			return err
+		}
 		return err
 	})
 	return err
 }
 
+// BusinessUpgradeNotify 项目降级 审批结果通知
+func (p *businessService) BusinessUpgradeNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
+	business, err := p.checkDingTalkNotify(flow, msg)
+	if err != nil {
+		return err
+	}
+
+	var data = g.Map{}
+	if msg.ProcessType == "terminate" {
+		data[p.Dao.Columns.ApproStatus] = ApprovalReturn
+	}
+	if msg.ProcessType == "finish" && msg.Result != "refuse" {
+		data[p.Dao.Columns.ApproStatus] = ApprovalRejection
+	}
+	if msg.ProcessType == "finish" && msg.Result == "agree" {
+		// 从项目动态内获取变更信息
+		transferDynamics := new(model.ProjBusinessDynamics)
+		dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).Where(projDao.ProjBusinessDynamics.Columns.BusId, business.Id)
+		err = dynamicsDao.Where(projDao.ProjBusinessDynamics.Columns.OpnType, OpnUpgrade).OrderDesc("created_time").Scan(transferDynamics)
+		if err != nil {
+			return err
+		}
+
+		data = utils.MapKeySnakeCamelCase(gconv.Map(transferDynamics.OpnContent), "snake")
+		delete(data, "orig_nbo_type")
+		delete(data, "updated_by")
+		delete(data, "updated_name")
+		delete(data, "updated_time")
+		data[p.Dao.Columns.NboType] = StatusReserve
+		data[p.Dao.Columns.ApproStatus] = ApprovalOK
+	}
+
+	// 项目修改
+	_, err = p.Dao.WherePri(business.Id).Data(data).Update()
+
+	// 添加项目动态
+	dynamics := model.ProjBusinessDynamics{
+		BusId:   business.Id,
+		OpnType: OpnUpgradeApproval,
+	}
+	err = p.CreateProjBusinessDynamics(nil, dynamics, data)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// BusinessDowngrade 项目降级
+func (p *businessService) BusinessDowngrade(req *model.BusinessDowngradeReq) error {
+	business, err := p.BusinessGradation(req.Id, req.NboType, "down")
+	if err != nil {
+		return err
+	}
+	var downgradeType string
+	switch true {
+	case business.NboType == StatusB && req.NboType == StatusC:
+		downgradeType = "option_0"
+	case business.NboType == StatusA && req.NboType == StatusB:
+		downgradeType = "option_1"
+	case business.NboType == StatusA && req.NboType == StatusC:
+		downgradeType = "option_2"
+	case business.NboType == StatusA && req.NboType == StatusReserve:
+		downgradeType = "option_YZMFJYQQK6O0"
+	default:
+		return myerrors.TipsError("错误的降级类型")
+	}
+
+	businessMap := g.Map{
+		p.Dao.Columns.ApproStatus: ApprovalWaiting,
+	}
+	service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
+
+	opnContent := gconv.Map(req)
+	opnContent["origNboType"] = business.NboType
+	opnContent["approStatus"] = ApprovalWaiting
+	service.SetUpdatedInfo(opnContent, p.GetCxtUserId(), p.GetCxtUserName())
+
+	// 审批流
+	workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
+	err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
+		// 更新项目调级
+		_, err = p.Dao.TX(tx).WherePri(req.Id).Data(businessMap).Update()
+		if err != nil {
+			return err
+		}
+		// 添加项目动态
+		dynamics := model.ProjBusinessDynamics{
+			BusId:   business.Id,
+			OpnType: OpnDowngrade,
+			Remark:  req.Remark,
+		}
+		err = p.CreateProjBusinessDynamics(tx, dynamics, opnContent)
+		if err != nil {
+			return err
+		}
+		// OMS项目降级 审批
+		bizCode := business.NboCode + ":" + strconv.Itoa(business.Id)
+		_, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectDownGrade, &workflow.StartProcessInstanceRequest{
+			ProcessCode: &BusinessDowngradeRequestProcessCode,
+			FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
+				{
+					Id:    utils.String("TextField-K2AD4O5B"),
+					Name:  utils.String("项目编码"),
+					Value: utils.String(business.NboCode),
+				},
+				{
+					Id:    utils.String("TextField_BDLSECETVSG0"),
+					Name:  utils.String("项目名称"),
+					Value: utils.String(business.NboName),
+				},
+				{
+					Id:    utils.String("TextField_1J9BJMOZ18F40"),
+					Name:  utils.String("客户名称"),
+					Value: utils.String(business.CustName),
+				},
+				{
+					Id:    utils.String("TextField_GL7MQUB723K0"),
+					Name:  utils.String("所在省"),
+					Value: utils.String(business.CustProvince),
+				},
+				{
+					Id:    utils.String("TextField_CFA88QQQUUO0"),
+					Name:  utils.String("所在市"),
+					Value: utils.String(business.CustCity),
+				},
+				{
+					Id:    utils.String("DDSelectField_VSA3U380ZK00"),
+					Name:  utils.String("降级类型"),
+					Value: utils.String(downgradeType),
+				},
+				{
+					Id:    utils.String("TextField_X4D3QGARU7K0"),
+					Name:  utils.String("支持内容"),
+					Value: utils.String(req.TechnicalSupportContent),
+				},
+				{
+					Id:    utils.String("TextField_AEUWH63LJ0O0"),
+					Name:  utils.String("销售工程师"),
+					Value: utils.String(business.SaleName),
+				},
+				{
+					Id:    utils.String("TextareaField_PTGJOKD3J7K0"),
+					Name:  utils.String("降级原因"),
+					Value: utils.String(req.Remark),
+				},
+			},
+		})
+		if err != nil {
+			g.Log().Error(err)
+			return err
+		}
+		return nil
+	})
+	return err
+}
+
+// BusinessDowngradeNotify 项目降级 审批结果通知
+func (p *businessService) BusinessDowngradeNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
+	business, err := p.checkDingTalkNotify(flow, msg)
+	if err != nil {
+		return err
+	}
+
+	var data = g.Map{}
+	if msg.ProcessType == "terminate" {
+		data[p.Dao.Columns.ApproStatus] = ApprovalReturn
+	}
+	if msg.ProcessType == "finish" && msg.Result != "refuse" {
+		data[p.Dao.Columns.ApproStatus] = ApprovalRejection
+	}
+	if msg.ProcessType == "finish" && msg.Result == "agree" {
+		data[p.Dao.Columns.NboType] = StatusReserve
+		data[p.Dao.Columns.ApproStatus] = ApprovalOK
+		// 从项目动态内获取变更信息
+		transferDynamics := new(model.ProjBusinessDynamics)
+		dynamicsDao := projDao.NewProjBusinessDynamicsDao(p.Tenant).Where(projDao.ProjBusinessDynamics.Columns.BusId, business.Id)
+		err = dynamicsDao.Where(projDao.ProjBusinessDynamics.Columns.OpnType, OpnDowngrade).OrderDesc("created_time").Scan(transferDynamics)
+		if err != nil {
+			return err
+		}
+		changeData := gconv.Map(transferDynamics.OpnContent)
+		data[p.Dao.Columns.NboType] = changeData["nboType"]
+		data[p.Dao.Columns.TechnicalSupportName] = changeData["technicalSupportName"]
+		data[p.Dao.Columns.TechnicalSupportContent] = changeData["technicalSupportContent"]
+		data[p.Dao.Columns.TechnicalSupportTime] = changeData["technicalSupportTime"]
+		data[p.Dao.Columns.Remark] = changeData["remark"]
+	}
+
+	// 项目修改
+	_, err = p.Dao.WherePri(business.Id).Data(data).Update()
+
+	// 添加项目动态
+	dynamics := model.ProjBusinessDynamics{
+		BusId:   business.Id,
+		OpnType: OpnDowngradeApproval,
+	}
+	err = p.CreateProjBusinessDynamics(nil, dynamics, data)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 // SetPrimacyContact 项目设置首要联系人
 func (p *businessService) SetPrimacyContact(req *model.BusinessPrimacyContactReq) (err error) {
 	business, err := p.Dao.Where(projDao.ProjBusiness.Columns.Id, req.Id).One()
@@ -453,6 +893,154 @@ func (p *businessService) CreateProjBusinessDynamics(tx *gdb.TX, dynamics model.
 	dynamics.OpnDate = gtime.Now()
 	dynamics.OpnContent = gconv.String(opnContent)
 	service.SetCreatedInfo(&dynamics, p.GetCxtUserId(), p.GetCxtUserName())
-	_, err := projDao.NewProjBusinessDynamicsDao(p.Tenant).TX(tx).Insert(&dynamics)
+	dao := projDao.NewProjBusinessDynamicsDao(p.Tenant).M
+	if tx != nil {
+		dao = dao.TX(tx)
+	}
+	_, err := dao.Insert(&dynamics)
+	return err
+}
+
+// ConvertToReserve 转为储备项目
+func (p *businessService) ConvertToReserve(req *model.BusinessToReserveReq) error {
+	business, err := p.Dao.WherePri(req.Id).Where(p.Dao.Columns.ApproStatus, ApprovalNotSubmit).One()
+	if err != nil {
+		return err
+	}
+	if business == nil {
+		return myerrors.TipsError("项目已提交审批任务,无法重复提交。")
+	}
+	// 审批流
+	workflowSrv, _ := workflowService.NewFlowService(p.Ctx)
+	err = p.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
+		// 更新项目
+		businessMap := g.Map{
+			p.Dao.Columns.ApproStatus:          ApprovalWaiting,
+			p.Dao.Columns.ProjConversionTime:   gtime.Now(),
+			p.Dao.Columns.ProjConversionReason: req.ProjConversionReason,
+		}
+		service.SetUpdatedInfo(businessMap, p.GetCxtUserId(), p.GetCxtUserName())
+		_, err = p.Dao.TX(tx).WherePri(business.Id).Data(businessMap).Update()
+		if err != nil {
+			return err
+		}
+
+		// 添加项目动态
+		dynamics := model.ProjBusinessDynamics{
+			BusId:   business.Id,
+			OpnType: OpnToReserve,
+			Remark:  req.ProjConversionReason,
+		}
+		err = p.CreateProjBusinessDynamics(tx, dynamics, businessMap)
+		if err != nil {
+			return err
+		}
+
+		// OMS项目转储备 审批
+		bizCode := business.NboCode + ":" + strconv.Itoa(business.Id)
+		_, err = workflowSrv.StartProcessInstance(bizCode, workflowModel.ProjectToReserve, &workflow.StartProcessInstanceRequest{
+			ProcessCode: &ConvertToReserveRequestProcessCode,
+			FormComponentValues: []*workflow.StartProcessInstanceRequestFormComponentValues{
+				{
+					Id:    utils.String("TextField-K2AD4O5B"),
+					Name:  utils.String("项目编码"),
+					Value: utils.String(business.NboCode),
+				},
+				{
+					Id:    utils.String("TextField_CMH6TBXYR5S0"),
+					Name:  utils.String("项目名称"),
+					Value: utils.String(business.NboName),
+				},
+				{
+					Id:    utils.String("TextField_YQBGGYHQPS00"),
+					Name:  utils.String("客户名称"),
+					Value: utils.String(business.CustName),
+				},
+				{
+					Id:    utils.String("TextField_57000M1HBVO0"),
+					Name:  utils.String("项目级别"),
+					Value: utils.String(nboType[business.NboType]),
+				},
+				{
+					Id:    utils.String("TextField_1NDD3TY8KJB40"),
+					Name:  utils.String("销售工程师"),
+					Value: utils.String(business.SaleName),
+				},
+				{
+					Id:    utils.String("TextareaField_15KZFM4YHQ8W0"),
+					Name:  utils.String("转化原因"),
+					Value: utils.String(req.ProjConversionReason),
+				},
+			},
+		})
+		if err != nil {
+			g.Log().Error(err)
+			return err
+		}
+		return nil
+	})
+
+	return err
+}
+
+// ConvertToReserveNotify 转为储备项目 审批结果通知
+func (p *businessService) ConvertToReserveNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) error {
+	business, err := p.checkDingTalkNotify(flow, msg)
+	if err != nil {
+		return err
+	}
+	var data = g.Map{}
+	if msg.ProcessType == "terminate" {
+		data[p.Dao.Columns.ApproStatus] = ApprovalReturn
+	}
+	if msg.ProcessType == "finish" && msg.Result != "refuse" {
+		data[p.Dao.Columns.ApproStatus] = ApprovalRejection
+	}
+	if msg.ProcessType == "finish" && msg.Result == "agree" {
+		data[p.Dao.Columns.NboType] = StatusReserve
+		data[p.Dao.Columns.ApproStatus] = ApprovalOK
+	}
+
+	// 项目修改
+	_, err = p.Dao.WherePri(business.Id).Data(data).Update()
+
+	// 添加项目动态
+	dynamics := model.ProjBusinessDynamics{
+		BusId:   business.Id,
+		OpnType: OpnToReserveApproval,
+	}
+	err = p.CreateProjBusinessDynamics(nil, dynamics, data)
+	if err != nil {
+		return err
+	}
 	return err
 }
+
+// 钉钉审批通知检查
+func (p *businessService) checkDingTalkNotify(flow *workflowModel.PlatWorkflow, msg *message.MixMessage) (*model.ProjBusiness, error) {
+	bizCode := strings.Split(flow.BizCode, ":")
+	if len(bizCode) != 2 {
+		return nil, fmt.Errorf("项目转储备审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
+	}
+	nboCode := bizCode[0]
+	busId, err := strconv.Atoi(bizCode[1])
+	if err != nil {
+		return nil, fmt.Errorf("项目转储备审批 bizCode 不合法:%s Id: %d", flow.BizCode, flow.Id)
+	}
+	if msg.ProcessType != "finish" && msg.ProcessType != "terminate" {
+		return nil, fmt.Errorf("无法识别的 ProcessType :%s", msg.ProcessType)
+	}
+	if msg.Result != "agree" && msg.Result != "refuse" && msg.Result != "" {
+		return nil, fmt.Errorf("无法识别的 Result :%s", msg.Result)
+	}
+	fmt.Println(msg)
+
+	business, err := p.Dao.WherePri(busId).Where(p.Dao.Columns.NboCode, nboCode).One()
+	if err != nil {
+		return nil, err
+	}
+	if business == nil {
+		return nil, fmt.Errorf("项目不存在:%s Id: %d", flow.BizCode, flow.Id)
+	}
+	return business, nil
+}

+ 69 - 0
opms_parent/app/service/proj/const.go

@@ -0,0 +1,69 @@
+package proj
+
+import "github.com/gogf/gf/frame/g"
+
+// 项目动态类型
+const (
+	OpnCreate            = "10" // 创建动态
+	OpnUpdate            = "20" // 更新动态
+	OpnStatus            = "30" // 更新项目状态动态
+	OpnUpgrade           = "40" // 升级动态
+	OpnUpgradeApproval   = "41" // 升级审批动态
+	OpnDowngrade         = "50" // 降级动态
+	OpnDowngradeApproval = "51" // 降级审批动态
+	OpnTransfer          = "60" // 转移动态
+	OpnTransferApproval  = "61" // 转移审批动态
+	OpnAssociation       = "70" // 关联联系人动态
+	OpnDisassociation    = "71" // 解除关联联系人动态
+	OpnPrimacyContact    = "72" // 设置首要联系人动态
+	OpnToReserve         = "80" // 项目转为储备项目动态
+	OpnToReserveApproval = "81" // 项目转为储备审批项目动态
+)
+
+// 项目状态
+const (
+	StatusA       = "10" // A
+	StatusB       = "20" // B
+	StatusC       = "30" // C
+	StatusDeal    = "40" // 成交
+	StatusReserve = "50" // 储备
+)
+
+// 审批状态
+const (
+	ApprovalNotSubmit = "10" // 等待提交
+	ApprovalWaiting   = "20" // 审批中
+	ApprovalOK        = "30" // 审批通过
+	ApprovalReturn    = "40" // 审批退回
+	ApprovalRejection = "50" // 审批拒绝
+)
+
+// 钉钉审批流 Code
+var (
+	BusinessUpgradeRequestProcessCode   = "PROC-2D7A7F90-8E86-495C-A332-18690A0F0109" // 项目升级
+	BusinessDowngradeRequestProcessCode = "PROC-E5A8B695-A6AF-49CF-9909-9A31C33A1211" // 项目降级
+	BusinessTransferRequestProcessCode  = "PROC-0F466630-D0CF-495B-8921-FB4B42F38B6D" // 项目转移
+	ConvertToReserveRequestProcessCode  = "PROC-03282849-0D00-4B76-AAB3-6C0219F569C1" // 转为储备
+)
+
+// 钉钉 项目级别
+var nboType = g.MapStrStr{
+	"10": "A",
+	"20": "B",
+	"30": "C",
+	"40": "成交",
+	"50": "储备",
+}
+
+// 钉钉 采购方式
+var purchasingWayType = g.MapStrStr{
+	"10": "option_0",
+	"20": "option_1",
+	"30": "option_2",
+}
+
+// 钉钉 是否
+var yesOrNoType = g.MapStrStr{
+	"10": "option_0",
+	"20": "option_1",
+}