Browse Source

mnerge master

bding 1 year ago
parent
commit
ce932638b1
77 changed files with 5192 additions and 485 deletions
  1. 1 0
      package.json
  2. 17 0
      src/api/modules/businessCustom.js
  3. 59 0
      src/api/modules/etaMenuApi.js
  4. 4 0
      src/api/modules/rai/lableApi.js
  5. 4 0
      src/api/modules/rai/raiApi.js
  6. 5 0
      src/api/modules/rai/reportApi.js
  7. 74 0
      src/api/modules/setApi.js
  8. 58 1
      src/api/modules/statisticApi.js
  9. BIN
      src/assets/img/home/email_icon.png
  10. BIN
      src/assets/img/home/phone_icon.png
  11. BIN
      src/assets/img/icons/account-login-type.png
  12. BIN
      src/assets/img/icons/email-login-type.png
  13. BIN
      src/assets/img/icons/phone-login-type.png
  14. 2 2
      src/components/calendar.vue
  15. 10 0
      src/routes/modules/customRoutes.js
  16. 82 5
      src/routes/modules/cygxRoutes.js
  17. 6 0
      src/routes/modules/operateRoutes.js
  18. 3 1
      src/styles/vars.scss
  19. 47 0
      src/utils/commonOptions.js
  20. 3 1
      src/views/Home.vue
  21. 434 22
      src/views/Login.vue
  22. 236 0
      src/views/business_ETA_manage/businessAuth.vue
  23. 12 0
      src/views/business_ETA_manage/businessList.vue
  24. 14 22
      src/views/custom_manage/compontents/ProductReadInfo.vue
  25. 24 6
      src/views/custom_manage/compontents/ReadDialog.vue
  26. 4 0
      src/views/custom_manage/contractStatistics.vue
  27. 4 4
      src/views/custom_manage/customList/customDetail.vue
  28. 13 3
      src/views/custom_manage/customList/customList.vue
  29. 1 1
      src/views/custom_manage/customList/customListEn.vue
  30. 14 2
      src/views/custom_manage/customList/limitContactListEn.vue
  31. 3 0
      src/views/custom_manage/etaTrialList/config.js
  32. 2 2
      src/views/custom_manage/etaTrialList/etaTrialList.vue
  33. 4 0
      src/views/custom_manage/etaTrialList/textQuestionDetail.vue
  34. 73 0
      src/views/dataReport_manage/components/noRenewalReasonDia/addRemark.vue
  35. 193 0
      src/views/dataReport_manage/components/noRenewalReasonDia/confirmedNoRenewal.vue
  36. 62 0
      src/views/dataReport_manage/components/noRenewalReasonDia/viewRemark.vue
  37. 29 1
      src/views/dataReport_manage/configdata.js
  38. 224 7
      src/views/dataReport_manage/incrementalList.vue
  39. 104 3
      src/views/dataReport_manage/stockCutomList.vue
  40. 1 0
      src/views/interaction_manage/videoManage.vue
  41. 143 0
      src/views/login_manage/EmailModel.vue
  42. 430 0
      src/views/login_manage/ForgetPassModel.vue
  43. 160 0
      src/views/login_manage/MobileModel.vue
  44. 123 0
      src/views/login_manage/OrdinaryModel.vue
  45. 117 0
      src/views/login_manage/components/CaptchaInput.vue
  46. 99 0
      src/views/login_manage/components/ModelSteps.vue
  47. 79 0
      src/views/login_manage/components/VerificationBox.vue
  48. 155 0
      src/views/login_manage/css/formStyle.scss
  49. 34 0
      src/views/login_manage/modelMixins.js
  50. 70 52
      src/views/rai_manage/activityManage/activityManage.vue
  51. 20 9
      src/views/rai_manage/activityManage/applyManage.vue
  52. 86 7
      src/views/rai_manage/activityManage/components/addActivity.vue
  53. 6 0
      src/views/rai_manage/activityManage/components/addComopnents/ResearchDeduct.vue
  54. 80 0
      src/views/rai_manage/activityManage/components/addComopnents/modifyImgDlg.vue
  55. 124 0
      src/views/rai_manage/activityManage/components/imgMeeting.vue
  56. 519 0
      src/views/rai_manage/activityManage/meetingManagement.vue
  57. 1 1
      src/views/rai_manage/activityManage/roadShow/tableTabs.js
  58. 1 1
      src/views/rai_manage/activityManage/roadShowList.vue
  59. 66 60
      src/views/rai_manage/components/addChoiceness.vue
  60. 1 1
      src/views/rai_manage/components/addSummary.vue
  61. 20 0
      src/views/rai_manage/components/apply/applyTableColums.js
  62. 17 2
      src/views/rai_manage/components/reportComponents/CompanyDetail.vue
  63. 13 3
      src/views/rai_manage/cygxManage/applyUserList.vue
  64. 5 4
      src/views/rai_manage/cygxManage/lableManage.vue
  65. 67 0
      src/views/rai_manage/reportManage/components/roadshowApplyDlg.vue
  66. 15 1
      src/views/rai_manage/reportManage/reportChoiceness.vue
  67. 13 3
      src/views/report_manage/dayilyNews.vue
  68. 201 112
      src/views/resetpassword.vue
  69. 1 0
      src/views/roadshow_manage/statistics/index.scss
  70. 1 1
      src/views/roadshow_manage/statistics/researcher.vue
  71. 1 0
      src/views/system_manage/assistance_center/assistanceDocAdd.vue
  72. 53 7
      src/views/system_manage/components/addUserDialog.vue
  73. 39 132
      src/views/system_manage/departManage.vue
  74. 132 0
      src/views/system_manage/etaMenu_manage/components/ChoosedIconDialog.vue
  75. 247 0
      src/views/system_manage/etaMenu_manage/components/ModifyMenuDialog.vue
  76. 205 0
      src/views/system_manage/etaMenu_manage/etaMenuConfig.vue
  77. 22 6
      src/views/system_manage/mixin/departManageMixin.js

+ 1 - 0
package.json

@@ -39,6 +39,7 @@
     "js-md5": "^0.7.3",
     "less-loader": "^4.1.0",
     "lodash": "^4.17.21",
+    "opencc-js": "^1.0.5",
     "pptxgenjs": "^3.10.0",
     "qrcode": "^1.4.4",
     "sortablejs": "^1.15.0",

+ 17 - 0
src/api/modules/businessCustom.js

@@ -104,5 +104,22 @@ export const businessCustomInterence = {
      */
     addBusiness:(params)=>{
         return http.post('/eta_business/add',params)
+    },
+    /**
+     * 获取商家权限详情
+     * @param EtaBusinessId 商家ID
+     * @returns
+     */
+    getAuthList:(params)=>{
+        return http.get('/eta_business/menu/list',params)
+    },
+    /**
+     * 设置商家权限
+     * @param EtaBusinessId 商家ID
+     * @param MenuIds 权限的ID列表
+     * @returns 
+     */
+    setAuthList:(params)=>{
+        return http.post('/eta_business/menu/relate/save',params)
     }
 }

+ 59 - 0
src/api/modules/etaMenuApi.js

@@ -0,0 +1,59 @@
+/* ETA菜单配置api */
+import http from "@/api/http.js"
+export const menuConfigInterface = {
+    /**
+     * 获取商家菜单列表
+     * @param {String} Keyword 关键词 
+     * @returns 
+     */
+    getMenuList:params=>{
+        return http.get('/eta_business/menu/list',params)
+    },
+    /**
+     * 新增菜单
+     * @param {Number} ParentId 父级id,一级菜单填0 
+     * @param {String} MenuType 菜单类型 0菜单 1按钮 2字段
+     * @param {String} Name 菜单名称
+     * @param {String} IconPath 菜单图标地址 
+     * @param {Number} Sort 排序
+     * @param {String} Path 路由地址 etaMenuConfig 不加斜杠
+     * @param {String} Component 组件路径,目前跟路由地址是一样的值
+     * @param {Number} Hidden 0显示 1隐藏
+     * @param {String} ButtonCode 按钮唯一标识,类型为按钮字段时必填
+     * @returns 
+     */
+    addMenu:params=>{
+        return http.post('/eta_business/menu/add',params)
+    },
+    /**
+     * 编辑菜单
+     * @param {Number} MenuId 菜单ID 其他参数同上
+     * @returns 
+     */
+    editMenu:params=>{
+        return http.post('/eta_business/menu/edit',params)
+    },
+    /**
+     * 删除菜单
+     * @param {Number} MenuId 
+     * @returns 
+     */
+    removeMenu:params=>{
+        return http.post('/eta_business/menu/remove',params)
+    },
+    /**
+     * 获取菜单icon列表
+     * @returns 
+     */
+    getMenuIconList:params=>{
+        return http.get('/eta_business/menu/icon/list',params)
+    },
+    /**
+     * 新增icon
+     * @returns 
+     */
+    addMenuIcon:params=>{
+        return http.post('/eta_business/menu/icon/add',params)
+    },
+
+}

+ 4 - 0
src/api/modules/rai/lableApi.js

@@ -29,6 +29,10 @@ const lableApi = {
   postLableTagMove: (params) => {
     return http.post("/cygx/tag/move", params);
   },
+  /* 微路演视频留言列表 */
+  video_and_voiceImgActivityVideo: (params) => {
+    return http.get("/cygx/activityVideo/video_and_voice/img", params);
+  },
 };
 
 export default lableApi;

+ 4 - 0
src/api/modules/rai/raiApi.js

@@ -1218,6 +1218,10 @@ const raiInterface = {
   activityTripSendGroupList: (params) => {
     return http.get("/cygx/special/trip/tempMsg/sendGroupList", params);
   },
+  // 根据图片获取建会信息接口
+  activityImgToText: (params) => {
+    return http.post("/cygx/activity/imgToText", params);
+  },
 };
 
 /* 权益小程序管理 专项调研模块*/

+ 5 - 0
src/api/modules/rai/reportApi.js

@@ -29,6 +29,11 @@ const raiReport = {
   reportChartPermissionFirstProduct: (params) => {
     return http.get("/cygx/chartPermission/firstProduct", params);
   },
+  // 报告精选申请记录接口
+  reportSelectionTarryList: (params) => {
+    return http.get("/cygx/reportSelection/tarryList", params);
+  },
+  
 };
 
 export default raiReport;

+ 74 - 0
src/api/modules/setApi.js

@@ -244,6 +244,80 @@ const departInterence = {
 	//从其他系统跳转来用code换token
 	useCodeLogin:params=>{
 		return http.get('/sysuser/auth_code_login',params)
+	},
+    /**
+	 * 获取图形验证码 返回Base64格式数据
+	 * @returns 
+	 */
+	getCodePic:params=>{
+		return http.get('/user_login/get_captcha',params)
+	},
+	/**
+	 * 获取短信/邮箱验证码
+	 * @param {Number} VerifyType 验证方式: 1-手机号; 2-邮箱
+	 * @param {String} CaptchaId 图形验证码ID
+	 * @param {String} CaptchaCode 图形验证码的值
+	 * @param {String} Mobile 手机号 验证方式为1时必填
+	 * @param {String} Email 邮箱 验证方式为2时必填
+	 * @param {String} TelAreaCode 手机区号
+	 * @param {Number} Source 来源:1-登录;2-异常登录校验;3-忘记密码
+	 * @returns 
+	 */
+	getCodeVerify:params=>{
+		return http.post('/user_login/verify_code',params)
+	},
+	/**
+	 * ETA1.4后,用户登录
+	 * @param {Number} LoginType 登录方式: 1-账号; 2-手机号; 3-邮箱
+	 * @param {Number} AbnormalCheckType 异常登陆校验方式: 1-手机号; 2-邮箱
+	 * @param {String} Username 用户名
+	 * @param {String} Password 密码
+	 * @param {String} Mobile 手机号
+	 * @param {String} Email 邮箱
+	 * @param {String} VerifyCode 手机号/邮箱的验证码
+	 * @returns 
+	 */
+	userLogin:params=>{
+		return http.post('/user_login/login',params)
+	},
+	/**
+	 * 忘记密码账号校验,获取账号信息
+	 * @param {String} CaptchaId 
+	 * @param {String} CaptchaCode 
+	 * @param {String} UserName 
+	 * @returns 
+	 */
+	accountCheck:params=>{
+		return http.post('/user_login/forget/account_get',params)
+	},
+	/**
+	 * 忘记密码-手机/邮箱的验证码校验
+	 * @param {Number} FindType 密码找回方式:1-手机号;2-邮箱
+	 * @param {String} VerifyCode 验证码
+	 * @param {String} UserName 用户名
+	 * @param {String} Mobile 找回方式为手机号时必填
+	 * @param {String} Email 找回方式为邮箱时必填
+	 * @returns 
+	 */
+	checkCodeVerify:params=>{
+		return http.post('/user_login/forget/code_verify',params)
+	},
+	/**
+	 * 忘记密码-重置密码
+	 * @param {String} UserName 
+	 * @param {String} Password 
+	 * @param {String} RePassword 
+	 * @returns 
+	 */
+	resetPass:params=>{
+		return http.post('/user_login/forget/reset_pass',params)
+	},
+	/**
+	 * 获取手机号区号
+	 * @returns 
+	 */
+	getPhoneAreaCode:params=>{
+		return http.get('/user_login/area_code/list',params)
 	}
 }
 

+ 58 - 1
src/api/modules/statisticApi.js

@@ -44,12 +44,69 @@ const dataMainInterface = {
 	 * @param {RegionType } params 
 	 * @param {StartDate} params 
 	 * @param {DataType} params 
-	 * @returns 
+	 * @param {IsConfirm} params  是否确认续约: -1-默认全部; 0-待确认; 1-已确认
+	 * @param {CompanyAscribeId} params  归因Id
+	 * @returns  
 	 */
 	incrementalList:params => {
 		return http.get('/statistic_report/incremental_company_list',params);
 	},
 	/**
+ * 获取未续约备注列表
+ * @param {CompanyId} params 公司ID
+ * @param {ProductId} params 产品ID 1:FICC ,2权益
+ * @returns 
+ */
+	getNotRenewedRemarkList:params => {
+		return http.get('/custom/company_no_renewed_note/list',params);
+	},
+	/**
+ * 添加未续约备注
+ * @param {CompanyId} params 公司ID
+ * @param {ProductId} params 产品ID 1:FICC ,2权益
+ * @param {Content} params 内容
+ * @returns 
+ */
+	addNotRenewedRemark:params => {
+		return http.post('/custom/company_no_renewed_note/add',params);
+	},
+	/**
+ * 获取归因列表
+ * @param {KeyWord} params 
+ * @returns  
+ */
+	getAscribList:params => {
+		return http.get('/custom/company_ascribe/list',params);
+	},
+	/**
+	 * 新增归因
+	 * @param {KeyWord} params 
+	 * @returns  
+	*/
+	addAscrib:params => {
+		return http.post('/custom/company_ascribe/add',params);
+	},
+	/**
+	 * 修改归因标签
+	* @param {CompanyId} params 公司ID
+	* @param {ProductId} params 产品ID 1:FICC ,2权益
+	* @param {Content} params 内容
+	* @param {CompanyAscribeId} params 归因Id
+	 * @returns  
+	*/
+	addNoRenewedAscribe:params => {
+		return http.post('/custom/company_no_renewed_ascribe/add',params);
+	},
+	/**
+	 * 归因标签详情
+	* @param {CompanyId} params 公司ID
+	* @param {ProductId} params 产品ID 1:FICC ,2权益
+	 * @returns  
+	*/
+	infoNoRenewedAscribe:params => {
+		return http.get('/custom/company_no_renewed_ascribe/detail',params);
+	},
+	/**
 	 * 获取收入统计列表接口
 	 * @param {PageSize} params 
 	 * @param {CurrentIndex} params 

BIN
src/assets/img/home/email_icon.png


BIN
src/assets/img/home/phone_icon.png


BIN
src/assets/img/icons/account-login-type.png


BIN
src/assets/img/icons/email-login-type.png


BIN
src/assets/img/icons/phone-login-type.png


+ 2 - 2
src/components/calendar.vue

@@ -347,7 +347,7 @@ export default {
         const {ActivityType,RoadshowType} = this.selectEventInfo
         const {Province,City} = this.selectEventInfo
         //ActivityType为路演时,需要显示的内容
-        const {RoadshowPlatform,CompanyName} = this.selectEventInfo
+        const {RoadshowPlatform,CompanyName,CompanyStatus} = this.selectEventInfo
         const RoadshowContent = [{
             key:'RoadshowPlatform',
             label:'路演平台:',
@@ -361,7 +361,7 @@ export default {
         },{
             key:'CompanyName',
             label:'客户名称:',
-            content:`${CompanyName}`,
+            content:`${CompanyName}${CompanyStatus ? '('+ CompanyStatus + ')' : ''}`,
             RoadshowType:RoadshowType,
         }].filter(item=>item.RoadshowType===RoadshowType)
         //ActivityType为公开会议时,需要显示的内容

+ 10 - 0
src/routes/modules/customRoutes.js

@@ -415,6 +415,16 @@ export default [
           pathFrom: "businessETAList",
           pathName: "商家管理",
         }
+      },
+      {
+        path:'businessETAAuth',
+        name:"商家权限",
+        component: () => import('@/views/business_ETA_manage/businessAuth.vue'),
+        hidden: false,
+        meta:{
+          pathFrom: "businessETAList",
+          pathName: "商家管理",
+        }
       }
     ],
   },

+ 82 - 5
src/routes/modules/cygxRoutes.js

@@ -352,11 +352,11 @@ export default [
     ],
   },
 
-  /* 查研观向活动 */
+  /* 弘则活动管理 */
   {
     path: "/",
     component: home,
-    name: "查研观向活动",
+    name: "弘则活动管理",
     hidden: false,
     icon_path: require("@/assets/img/home/rai_activity.png"),
     children: [
@@ -397,7 +397,12 @@ export default [
         name: "报名管理",
         hidden: false,
       },
-
+      {
+        path: "meetingManagement",
+        component: () => import("@/views/rai_manage/activityManage/meetingManagement.vue"),
+        name: "到会管理",
+        hidden: false,
+      },
       {
         path: "practicalMeeting",
         component: () => import("@/views/rai_manage/activityManage/practicalMeeting.vue"),
@@ -411,7 +416,7 @@ export default [
         hidden: true,
         meta: {
           pathFrom: "practicalMeeting",
-          pathName: "线下到会管理",
+          pathName: "到会管理",
           keepAlive: false,
         },
       },
@@ -439,7 +444,7 @@ export default [
         hidden: true,
         meta: {
           pathFrom: "onLineManage",
-          pathName: "线上到会管理",
+          pathName: "到会管理",
           keepAlive: false,
         },
       },
@@ -501,4 +506,76 @@ export default [
       },
     ],
   },
+  /* 研选活动管理 */
+  {
+    path: "/",
+    component: home,
+    name: "研选活动管理",
+    hidden: false,
+    icon_path: require("@/assets/img/home/rai_activity.png"),
+    children: [
+      {
+        path: "purchaserActivityManage",
+        component: () => import("@/views/rai_manage/activityManage/activityManage.vue"),
+        name: "活动管理",
+        hidden: false
+      },
+      {
+        path: "addPurchaserActivity",
+        component: () => import("@/views/rai_manage/activityManage/components/addActivity.vue"),
+        name: "添加活动",
+        hidden: true,
+        meta: {
+          pathFrom: "purchaserActivityManage",
+          pathName: "活动管理",
+          keepAlive: false,
+        },
+      },
+      {
+        path: "editPurchaserActivity",
+        component: () => import("@/views/rai_manage/activityManage/components/addActivity.vue"),
+        name: "编辑活动",
+        hidden: true,
+        meta: {
+          pathFrom: "purchaserActivityManage",
+          pathName: "活动管理",
+          keepAlive: false,
+        },
+      },
+      {
+        path: "purchaserApplyManage",
+        component: () => import("@/views/rai_manage/activityManage/applyManage.vue"),
+        name: "报名管理",
+        hidden: false,
+      },
+      {
+        path: "purchaserMeetingManagement",
+        component: () => import("@/views/rai_manage/activityManage/meetingManagement.vue"),
+        name: "到会管理",
+        hidden: false,
+      },
+      {
+        path: "purchaserAppointment",
+        component: () => import("@/views/rai_manage/activityManage/components/appointment.vue"),
+        name: "爽约记录",
+        hidden: true,
+        meta: {
+          pathFrom: "practicalMeeting",
+          pathName: "到会管理",
+          keepAlive: false,
+        },
+      },
+      {
+        path: "attendMeeting",
+        component: () => import("@/views/rai_manage/activityManage/components/attendMeeting.vue"),
+        name: "到会详情",
+        hidden: true,
+        meta: {
+          pathFrom: "onLineManage",
+          pathName: "到会管理",
+          keepAlive: false,
+        },
+      }
+    ],
+  },
 ];

+ 6 - 0
src/routes/modules/operateRoutes.js

@@ -117,6 +117,12 @@ export default [
 					pathName: '帮助中心配置'
 				}
 			},
+			{
+				path:"etaMenuConfig",
+				component:() => import('@/views/system_manage/etaMenu_manage/etaMenuConfig'),
+				name:'ETA菜单配置',
+				hidden:false,
+			}
 		]
 	}
 ]

+ 3 - 1
src/styles/vars.scss

@@ -46,7 +46,9 @@ a[href="https://froala.com/wysiwyg-editor"], a[href="https://www.froala.com/wysi
 @charset "utf-8";
 body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,button,input,textarea,th,td { margin:0; padding:0; }
 body{ font-size:12px; font-style:normal; font-family:"\5FAE\8F6F\96C5\9ED1", Helvetica, sans-serif,; }
-html{ overflow:auto; min-width:1000px; }
+html{ overflow:auto; 
+  // min-width:1000px;
+ }
 small{ font-size:12px; }
 h1{ font-size:18px; }
 h2{ font-size:16px; }

+ 47 - 0
src/utils/commonOptions.js

@@ -0,0 +1,47 @@
+
+//验证密码的正则 产品定的规则是:8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型
+export const patternPassWord = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/
+export function checkPassWord(pwd){
+    let num = 0
+    const patternArr = [
+        /^(?=.*[0-9])/,
+        /^(?=.*[a-z])/,
+        /^(?=.*[A-Z])/,
+        /^(?=.*[@#$%^&+=.])/,
+    ]
+    patternArr.forEach(pattern=>{
+        if(pattern.test(pwd)){
+            num++
+        }
+    })
+    if(pwd.length<8){
+        num = 0
+    }
+    return num>=3
+}
+//验证手机号的正则 仅支持国内大陆的
+export const patternPhone = /0?(13|14|15|18|17)[0-9]{9}/
+export function isMobileNo(account) {
+    // 手机号正则
+    var isChinaMobile = new RegExp(
+      "(^1(3[4-9]|4[78]|5[0-27-9]|7[28]|8[2-478]|98)\\d{8}$)"
+    ); // 中国移动
+    // 手机段:134,135,136,137,138,139,147,148[卫星通信],150,151,152,157,158,159,172,178,182,183,184,187,188,198
+    var isChinaUnicom = new RegExp(
+      "(^1(3[0-2]|4[56]|5[56]|66|7[156]|8[56])\\d{8}$)"
+    ); // 中国联通
+    // 手机段:130,131,132,145,146[卫星通信],155,156,166,171,175,176,185,186
+    var isChinaTelcom = new RegExp("(^1(33|49|53|7[347]|8[019]|99)\\d{8}$)"); // 中国电信
+    // 手机段:133,149,153,173,174,177,180,181,189,199
+    var isOtherTelphone = new RegExp("(^170\\d{8}$)");
+    // 虚拟运营商170号段
+    if (isChinaMobile.test(account)) {
+      return true;
+    } else if (isChinaUnicom.test(account)) {
+      return true;
+    } else if (isChinaTelcom.test(account)) {
+      return true;
+    } else return isOtherTelphone.test(account);
+  }
+//验证邮箱的正则
+export const patternEmail = /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/

+ 3 - 1
src/views/Home.vue

@@ -256,7 +256,8 @@
           <el-row class="grid-content bg-purple-light contentc" style="min-width:900px;">
             <el-col :span="24" class="content-wrapper" :style="!isHaveAside ? 'padding: 0 30px 0 0;' : ''">
               <transition name="fade" mode="out-in">
-                <router-view></router-view>
+                <!-- 加入key 解决不同路由到同一个文件时的缓存问题 -->
+                <router-view :key="$route.path"></router-view>
               </transition>
             </el-col>
           </el-row>
@@ -997,6 +998,7 @@ export default {
   }
 }
 #containercon {
+  min-width: 1000px;
   width: 100%;
   position: absolute;
   top: 0px;

+ 434 - 22
src/views/Login.vue

@@ -1,9 +1,9 @@
 <template>
 	<div id="login">
-		<div id="login_wrapper">
+		<div id="login_wrapper" v-if="!isMobile">
 			<img class="login-bg" src="https://hzstatic.hzinsights.com/static/hz_crm_web/imgs/login_bg.png" alt />
 			<img class="login-icon" src="https://hzstatic.hzinsights.com/static/hz_crm_web/imgs/login_logo.png" alt />
-			<el-form
+			<!-- <el-form
 				:model="ruleForm"
 				:rules="rules"
 				ref="ruleForm"
@@ -71,8 +71,122 @@
 						>登录</el-button
 					>
 				</el-form-item>
-			</el-form>
+			</el-form> -->
+			<div class="login-box" id="login-container" v-if="activeModel!=='forgetPassModel'">
+				<h1 style="font-size: 38px;text-align: center;color: #333;margin-bottom: 30px;">
+					运营管理系统
+				</h1>
+				<el-tabs v-model="activeModel" @tab-click="handleClick">
+					<el-tab-pane label="账号登录" name="ordinaryModel">
+						<OrdinaryModel ref="ordinaryModel"
+							:loginCheck="loginCheck"
+							:accountCheck="accountCheck"
+							@clearnHint="clearnHint"
+							@changeModel="changeModel('forgetPassModel')"
+						/>
+					</el-tab-pane>
+					<el-tab-pane label="手机号登录" name="mobileModel">
+						<MobileModel ref="mobileModel"
+							:areaCode="areaCode"
+						/>
+					</el-tab-pane>
+					<el-tab-pane label="邮箱登录" name="emailModel">
+						<EmailModel ref="emailModel"/>
+					</el-tab-pane>
+				</el-tabs>
+				<el-button
+					type="primary"
+					size="medium"
+					@click.native="handleLogin"
+					:loading="logining"
+					class="submit_btn"
+					>登录</el-button>
+			</div>
+			<div class="login-box" v-else>
+				<ForgetPassModel 
+					ref="forgetPassModel"
+					:autoAccount="$refs.ordinaryModel?$refs.ordinaryModel.form.account:''"
+					@changeModel="changeModel('ordinaryModel')"/>
+			</div>
 		</div>
+
+		<!-- 移动端的登录页面跟移动ETA的一模一样 单独整一份 -->
+		<div id="login_wrapper_mobile" v-else>
+			<template v-if="activeModel!=='forgetPassModel'">
+				<div class="login-logo">
+					<img src="https://hzstatic.hzinsights.com/static/hz_crm_web/imgs/login_logo.png" >
+				</div>
+				<div class="login-title">sign in to continue</div>
+				<OrdinaryModel ref="ordinaryModelMobile"
+					:loginCheck="loginCheck"
+					:accountCheck="accountCheck"
+					:isMobile="isMobile"
+					@clearnHint="clearnHint"
+					@changeModel="changeModel('forgetPassModel')"
+					v-show="activeModel=='ordinaryModel'"
+				/>
+				<MobileModel ref="mobileModelMobile"
+					:areaCode="areaCode" :isMobile="isMobile" 
+					v-show="activeModel=='mobileModel'"
+				/>
+				<EmailModel ref="emailModelMobile" :isMobile="isMobile" v-show="activeModel=='emailModel'" />
+
+				<el-button type="primary" @click.native="handleLogin" 
+				:loading="logining" class="submit_btn_mobile">登录</el-button>
+				<div class="login-type-box">
+					<div class="login-type-item" @click="activeModel='ordinaryModel';handleClick({name:'ordinaryModelMobile'})"
+					v-show="activeModel!=='ordinaryModel'">
+						<img src="~@/assets/img/icons/account-login-type.png">
+						<span>账号密码登录</span>
+					</div>
+					<div class="login-type-item" @click="activeModel='mobileModel';handleClick({name:'mobileModelMobile'})"
+					v-show="activeModel!=='mobileModel'">
+						<img src="~@/assets/img/icons/phone-login-type.png">
+						<span>手机号登录</span>
+					</div>
+					<div class="login-type-item" v-show="activeModel!=='emailModel'" 
+					@click="activeModel='emailModel';handleClick({name:'emailModelMobile'})">
+						<img src="~@/assets/img/icons/email-login-type.png">
+						<span>邮箱登录</span>
+					</div>
+				</div>
+			</template>
+			<div class="login-box" v-else>
+				<!-- 忘记密码就不重新搞了,太麻烦了,就写一起吧 -->
+				<ForgetPassModel 
+					ref="forgetPassModelMobile"
+					:isMobile="isMobile" 
+					:autoAccount="$refs.ordinaryModelMobile?$refs.ordinaryModelMobile.form.account:''"
+					@changeModel="changeModel('ordinaryModel')"/>
+			</div>
+		</div>
+
+		<!-- 验证弹窗 -->
+		<el-dialog
+			class="check-dialog"
+			:visible.sync="isCheckDialogShow"
+			:close-on-click-modal="false"
+			:modal-append-to-body="false"
+			width="30%"
+			@close="isCheckDialogShow = false"
+			>
+			<el-tabs v-model="checkActiveModel" @tab-click="handleClick">
+				<el-tab-pane label="手机号验证" name="checkMobileModel">
+						<MobileModel ref="checkMobileModel"
+							:areaCode="areaCode"
+						/>
+					</el-tab-pane>
+					<el-tab-pane label="邮箱验证" name="checkEmailModel">
+						<EmailModel ref="checkEmailModel"/>
+					</el-tab-pane>
+			</el-tabs>
+			<span slot="footer" class="dialog-footer">
+				<el-button 
+					type="primary" 
+					:loading="checkLogining"
+					@click="submitCheck">提 交</el-button>
+			</span>
+		</el-dialog>
 	</div>
 </template>
 
@@ -80,7 +194,12 @@
 import { userLogin , departInterence } from '@/api/api.js'
 import http from '@/api/http.js'
 import md5 from '@/utils/md5.js'
+import EmailModel from "./login_manage/EmailModel.vue"
+import ForgetPassModel from "./login_manage/ForgetPassModel.vue"
+import MobileModel from "./login_manage/MobileModel.vue"
+import OrdinaryModel from "./login_manage/OrdinaryModel.vue"
 export default {
+	components: { OrdinaryModel, MobileModel, EmailModel, ForgetPassModel },
 	data() {
 		return {
 			b: new http.Base64(),
@@ -107,25 +226,77 @@ export default {
 			},
 			checked: false, //是否保持登录状态
 			visible: true, //密码输入类型
+
+			activeModel: 'ordinaryModel',
+			/* form check 错误提示标识*/
+			loginCheck:false, //账号或密码错误
+			accountCheck:false,//账号异常:多次输错密码、长时间未登录
+			accountForbidden:false,//账号被禁用
+			mobileCheck:false,//手机号未绑定
+			emailCheck:false,//邮箱未绑定
+			areaCode:[],
+
+			isCheckDialogShow:false,
+			checkActiveModel:'checkMobileModel',
+			isMobile:false
+		}
+	},
+	computed:{
+		activeModelForm(){
+			return this.isMobile?this.activeModel+'Mobile':this.activeModel
+		},
+		ordinaryModelForm(){
+			return this.isMobile?'ordinaryModelMobile':'ordinaryModel'
+		},
+		mobileModelForm(){
+			return this.isMobile?'mobileModelMobile':'mobileModel'
+		},
+		emailModelForm(){
+			return this.isMobile?'emailModelMobile':'emailModel'
+		}
+	},
+	watch:{
+		isMobile(value){
+			// 移动端变PC或相反的情况监听
+			// 重新获取验证码
+			this.$nextTick(()=>{
+				// console.log(this.activeModelForm);
+				if((this.activeModel=="mobileModel" || this.activeModel=="emailModel")&&
+				(!this.$refs[this.activeModelForm].picSrc))
+				this.$refs[this.activeModelForm].getCodePic()
+			})
 		}
 	},
 	created() {
 		this.keyupSubmit() //回车登录
-		let userAccount = localStorage.getItem('account') || null
+		/* let userAccount = localStorage.getItem('account') || null
 		let userCheckPass = localStorage.getItem('checkPass') || null
 		if (userAccount) {
 			this.ruleForm.account = this.b.decode(userAccount)
 			this.ruleForm.checkPass = this.b.decode(userCheckPass)
 			this.checked = true;
-		}
+		} */
+		this.getPhoneCode();//获取手机号区号
+	},
+	mounted(){
+		this.getRememberedInfo()
+		this.isMobile=!(window.innerWidth>650)
+		window.addEventListener('resize',this.setIsMobile)
+	},
+	beforeDestroy() {
+		window.removeEventListener('resize',this.setIsMobile)
 	},
 	methods: {
+		setIsMobile(){
+			this.isMobile=!(window.innerWidth>650)
+		},
 		keyupSubmit() {
 			//回车登录
 			document.onkeydown = e => {
 				let keyval = window.event.keyCode
 				if (keyval === 13) {
-					this.handleSubmit2()
+					//this.handleSubmit2()
+					!this.logining&&this.handleLogin()
 				}
 			}
 		},
@@ -221,6 +392,189 @@ export default {
 				}
 				return '/'+pathVal
 			})
+		},
+		getPhoneCode(){
+			departInterence.getPhoneAreaCode().then(res=>{
+				if(res.Ret!==200) return 
+				this.areaCode = res.Data||[]
+			})
+		},
+		handleClick(tab) {
+			//调用对应model的init方法
+			this.$refs[tab.name]&&this.$refs[tab.name].modelInit()
+			this.$refs[tab.name]&&this.$refs[tab.name].$refs.modelForm.clearValidate()
+			if(tab.name==='ordinaryModel'){
+				this.$nextTick(()=>{
+					this.getRememberedInfo()
+				})
+			}
+		},
+		changeModel(model){
+			this.activeModel = model
+			if(model!=='forgetPassModel'){
+				this.$nextTick(()=>{
+					this.getRememberedInfo()
+				})
+			}
+		},
+		handleLogin(){
+			//先进行判空的表单验证
+			this.$refs[this.activeModelForm].$refs.modelForm.validate((valid)=>{
+				if(valid){
+					this.logining = true
+					//根据activeName 调用不同的登陆接口
+					//账号密码
+						if(this.activeModel==='ordinaryModel'){
+							this.ordinaryModelLogin()
+						}
+					//手机号登录
+						if(this.activeModel==='mobileModel'){
+							this.mobileModelLogin()
+						}
+					//邮箱登录
+						if(this.activeModel==='emailModel'){
+							this.emailModelLogin()
+						}
+				}
+			})
+		},
+		submitCheck(){
+			this.$refs[this.checkActiveModel].$refs.modelForm.validate((valid)=>{
+				if(valid){
+					this.checkLogining = true
+					if(this.checkActiveModel==='checkMobileModel'){
+						this.mobileModelLogin('checkMobileModel')
+					}else{
+						this.emailModelLogin('checkEmailModel')
+					}
+				}
+			})
+		},
+		ordinaryModelLogin(){
+			const {account,checkPass,checked} = this.$refs[this.ordinaryModelForm].form
+			departInterence.userLogin({
+				LoginType:1,
+				Username:account,
+				Password:md5.hex_md5(checkPass)
+			}).then(res=>{
+				//this.logining = false
+				//账号异常 将accountCheck置为true
+				if(res.Ret===4011){
+					this.accountCheck = true
+					this.isCheckDialogShow = true
+					this.$nextTick(()=>{
+						this.$refs[this.checkActiveModel].getCodePic()
+					})
+				}
+				//账号密码错误 将loginCheck置为true
+				if(res.Ret===4012){
+					this.loginCheck = true
+				}
+				if(res.Ret!==200){
+					this.logining = false
+					return 
+				}
+				//登录成功,若设置了保存密码,在localStorage内存储一个时间戳
+				if(checked){
+					this.setLoginDate(1)
+					localStorage.setItem("account", this.b.encode(account));
+					localStorage.setItem("checkPass", this.b.encode(checkPass));
+				}else {
+					this.setLoginDate(0)
+					localStorage.removeItem("account");
+					localStorage.removeItem("checkPass");
+				}
+				this.setLoginInfo(res)
+				this.loginSys(res)
+			})
+		},
+		mobileModelLogin(model=this.mobileModelForm){
+			const {mobile,checkCode} = this.$refs[model].form
+			departInterence.userLogin({
+				LoginType:2,
+				Mobile:mobile,
+				VerifyCode:checkCode
+			}).then(res=>{
+				if(res.Ret!==200){
+					//刷新图形验证码
+					this.$refs[model].getCodePic()
+					this.$refs[model].form.picCode = ''
+					model===this.mobileModelForm&&(this.logining = false)
+					model!==this.mobileModelForm&&(this.checkLogining = false)
+					return
+				}
+				this.setLoginInfo(res)
+				this.loginSys(res)
+			})
+		},
+		emailModelLogin(model=this.emailModelForm){
+			const {email,checkCode} = this.$refs[model].form
+			departInterence.userLogin({
+				LoginType:3,
+				Email:email,
+				VerifyCode:checkCode
+			}).then(res=>{
+				if(res.Ret!==200){
+					//刷新图形验证码
+					this.$refs[model].getCodePic()
+					this.$refs[model].form.picCode = ''
+					model===this.emailModelForm&&(this.logining = false)
+					model!==this.emailModelForm&&(this.checkLogining = false)
+					return
+				}
+				this.setLoginInfo(res)
+				this.loginSys(res)
+			})
+		},
+		clearnHint(){
+			this.loginCheck = false
+			this.accountCheck = false
+		},
+		setLoginDate(type){
+			if(type===0){
+				localStorage.removeItem('timeKey')
+			}else{
+				localStorage.setItem('timeKey',Date.now())
+			}
+
+		},
+		//判断timeKey有没有过期,目前设定的是60天,也就是5184000秒
+		checkTimeKey(timeKey){
+			const nowKey = Date.now()
+			return Math.floor((nowKey-timeKey)/1000)<5184000
+		},
+		//存储登录的信息
+		setLoginInfo(res){
+			localStorage.setItem("auth", res.Data.Authorization);
+			localStorage.setItem("userName", res.Data.RealName);
+			localStorage.setItem("Role", res.Data.RoleTypeCode);
+			localStorage.setItem("RoleIdentity", res.Data.SysRoleTypeCode);
+			localStorage.setItem("RoleType", res.Data.ProductName);
+			localStorage.setItem("ManageType", res.Data.Authority);
+			localStorage.setItem("AdminId", res.Data.AdminId);
+			localStorage.setItem("AdminName", res.Data.AdminName);
+		},
+		//根据角色判断应该进入系统的哪个页面,进入系统
+		async loginSys(res){
+			let path = await this.getOtherRolePath('myCalendar');
+			path&&this.$router.push({ path });
+			this.loading = false
+			this.checkLogining = false
+		},
+		//获取用户记住的账号密码 如果有
+		getRememberedInfo(){
+			const timeKey = localStorage.getItem("timeKey")
+			if(timeKey&&this.checkTimeKey(Number(timeKey))){
+				let userAccount = localStorage.getItem("account") || null;
+				let userCheckPass = localStorage.getItem("checkPass") || null;
+				if (userAccount) {
+					this.$refs.ordinaryModel.form = {
+						account:this.b.decode(userAccount),
+						checkPass:this.b.decode(userCheckPass),
+						checked:true
+					}
+				}
+			}
 		}
 	},
     destroyed(){
@@ -228,7 +582,19 @@ export default {
     }
 }
 </script>
-
+<style lang="scss">
+#login{
+	.el-tabs__nav {
+		width: 100%;
+		display: flex;
+	}
+	.el-tabs__item{
+		font-size: 18px;
+		flex: 1;
+		text-align: center;
+	}
+}
+</style>
 <style lang="scss" scoped>
 #login {
 	width: 100%;
@@ -236,6 +602,7 @@ export default {
 	background: #fff;
 	position: relative;
 	overflow: hidden;
+	overflow-y: auto;
 	#login_wrapper {
 		width: 100%;
 		height: 100%;
@@ -262,7 +629,7 @@ export default {
 			width: 8%;
 		}
 
-		#login-container {
+		#login-container,.login-box{
 			width: 31%;
 			max-width: 570px;
 			box-sizing: border-box;
@@ -280,7 +647,7 @@ export default {
 			}
 			.submit_btn {
 				width: 100%;
-				height: 40px;
+				height: 50px;
 				background: #007eff;
 				font-size: 16px;
 				border-radius: 5px;
@@ -330,20 +697,65 @@ export default {
 			}
 		}
 	}
-	.remember-cont {
-		position: relative;
-		margin-bottom: 20px;
-		.warn-check-tip {
-			position: absolute;
-			min-width: 300px;
-			left: 130px;
-			top: 0;
-			padding: 2px 10px;
-			border: 1px solid #D1433A;
-			background: #FFEAE9;
-			color: #B72E18;
-			font-size: 14px;
+	@media screen and (max-width:650px) {
+		#login_wrapper_mobile{
+			// display: block;
+			padding: 15% 40px 20px;
+			.login-logo{
+				margin-bottom: 30px;
+				img{
+					width: 250px;
+				}
+			}
+			.login-title{
+				font-size: 14px;
+				color: #999999;
+			}
+			.submit_btn_mobile{
+				height: 44px;
+				width: 100%;
+				border-radius: 44px;
+			}
+			.login-type-box{
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				width: 54%;
+				margin: 0 auto;
+				.login-type-item{
+					display: flex;
+					flex-direction: column;
+					justify-content: center;
+					align-items: center;
+					margin-top: 50px;
+					img{
+						height: 40px;
+						width: 40px;
+						margin-bottom: 4px;
+					}
+					span{
+						font-size: 12px;
+						color: #666666;
+					}
+				}
+			}
 		}
 	}
+	// .remember-cont {
+	// 	position: relative;
+	// 	margin-bottom: 20px;
+	// 	.warn-check-tip {
+	// 		position: absolute;
+	// 		min-width: 300px;
+	// 		left: 130px;
+	// 		top: 0;
+	// 		padding: 2px 10px;
+	// 		border: 1px solid #D1433A;
+	// 		background: #FFEAE9;
+	// 		color: #B72E18;
+	// 		font-size: 14px;
+	// 	}
+	// }
 }
 </style>
+

+ 236 - 0
src/views/business_ETA_manage/businessAuth.vue

@@ -0,0 +1,236 @@
+<template>
+    <div class="business-auth-wrap">
+        <div class="header">
+            <div class="name">{{$route.query.name||''}}</div>
+            <div class="btn-wrap">
+                <el-button @click="handleBtnClik('cancel')">取消</el-button>
+                <el-button type="primary" @click="handleBtnClik('save')">保存</el-button>
+            </div>
+        </div>
+        <div class="auth-wrap">
+            <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" style="margin-bottom: 20px;">全选</el-checkbox>
+            <el-tree 
+                v-loading="treeLoading"
+                ref="checkboxTree"
+                :data="authList" 
+                :props="{label:'Name',children:'Children'}" 
+                :default-expand-all="false"
+                show-checkbox 
+                node-key="MenuId"
+                :default-checked-keys="defaultCheckedKeys"
+                @check-change="()=>{handleCheckChange()}">
+            </el-tree>
+        </div>
+    </div>
+</template>
+
+<script>
+import {businessCustomInterence} from '@/api/api.js'
+export default {
+    data() {
+        return {
+            authList:[],
+            defaultCheckedKeys:[],
+            treeLoading:false,
+            checkAll:false,
+            isIndeterminate:false
+        };
+    },
+    watch:{
+        checkAll(newVal){
+            if(newVal){
+                const topLevelNodes = this.authList.map(i=>i.MenuId)
+                this.$refs.checkboxTree.setCheckedKeys(topLevelNodes)
+            }else{
+                if(!this.isIndeterminate){
+                    this.$refs.checkboxTree.setCheckedKeys([])
+                }
+            }
+        }
+    },
+    methods: {
+        getBusinessAuthList(){
+            const EtaBusinessId = this.$route.query.id
+            if(!EtaBusinessId) return 
+            this.treeLoading = true
+            businessCustomInterence.getAuthList({
+                EtaBusinessId:Number(EtaBusinessId)
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.treeLoading = false
+                if(!res.Data) return
+                const {List,ChoiceList=[],HalfChoiceList=[]} = res.Data
+                this.authList = List||[]
+                this.defaultCheckedKeys = ChoiceList.filter((item)=>!HalfChoiceList.some((halfItem)=>item===halfItem))
+                this.handleCheckChange(this.defaultCheckedKeys,HalfChoiceList)
+            })
+        },
+        async handleBtnClik(type){
+            if(type==='save'){
+                //获取树形列表选择的项 getCheckedKeys getHalfCheckedKeys
+                const keys = this.$refs.checkboxTree.getCheckedKeys()
+                const halfKeys = this.$refs.checkboxTree.getHalfCheckedKeys()
+                if(!keys.length&&!halfKeys.length){
+                    this.$message.warning('请至少选择一个权限')
+                    return
+                }
+                //合成一个数组并去重
+                const ChoiceList = Array.from(new Set([...keys,...halfKeys]))
+                //请求接口
+                const res = await businessCustomInterence.setAuthList({
+                    EtaBusinessId:Number(this.$route.query.id),
+                    MenuIds:ChoiceList,
+                    HalfMenuIds:halfKeys
+                })
+                if(res.Ret!==200) return 
+                this.$message.success('权限设置成功')
+            }
+            this.$router.push('/businessETAList')
+        },
+        handleCheckChange(choiceList,HalfChoiceList){
+            const keys = choiceList||this.$refs.checkboxTree.getCheckedKeys()
+            const halfKeys = HalfChoiceList||this.$refs.checkboxTree.getHalfCheckedKeys()
+            const ChoiceList = Array.from(new Set([...keys]))
+            const topLevelNodes = this.authList.map(i=>i.MenuId)
+            let nodeLength = 0
+            topLevelNodes.forEach(i=>{
+                if(ChoiceList.includes(i)){nodeLength++}
+                if(!ChoiceList.includes(i)){nodeLength--}
+            })
+            if(nodeLength===topLevelNodes.length){
+                this.checkAll = true
+                this.isIndeterminate = false
+            }else{
+                this.checkAll = false
+                this.isIndeterminate = Boolean(ChoiceList.length)
+            }
+        }
+    },
+    mounted(){
+        this.getBusinessAuthList()
+    }
+};
+</script>
+
+<style lang="scss">
+.business-auth-wrap{
+    .el-tree {
+        border-top: 1px solid #E5E7ED;
+        border-left: 1px solid #E5E7ED;
+        border-right: 1px solid #E5E7ED;
+        width: 98%;
+        margin-bottom: 40px;
+        .el-tree-node__label{
+            margin:10px;
+        }
+        .el-tree-node__content{
+            min-width: 200px;
+            width: 200px;
+            white-space: normal;
+            box-sizing: border-box;
+        }
+        .el-tree-node{
+            .el-tree-node{
+                .el-tree-node__children{
+                    width: 100%;
+                }
+                .el-tree-node{
+                    &:not(:first-child){
+                    /* .el-tree-node__content{
+                        border-right: 1px solid #E5E7ED;
+                    } */
+                        border-top: 1px solid #E5E7ED;
+                    }
+                    .el-tree-node__content{
+                        border-right: 1px solid #E5E7ED;
+                    }
+                }
+    
+            }
+        }
+        .el-tree-node__content {
+            padding: 5px 10px !important;
+            height: auto;
+            .el-tree-node__expand-icon.el-icon-caret-right {
+            //display: none;
+            }
+        }
+        > .el-tree-node {
+            padding: 0 !important;
+            display: flex;
+            border-bottom: 1px solid #E5E7ED;
+
+            > .el-tree-node__children {
+            width: 100%;
+            > .el-tree-node {
+                &:not(:first-child) {
+                border-top: 1px solid #E5E7ED;
+                }
+                >.el-tree-node__content{
+                    border-left: 1px solid #E5E7ED;
+                    border-right: 1px solid #E5E7ED;
+                }
+            }
+            }
+        }
+        .el-tree-node__children {
+            display: flex;
+            flex-direction: column;
+            .el-tree-node {
+                display: flex;
+                flex: 1;
+                padding: 0px !important;
+                .el-tree-node__content {
+                    border-bottom: none;
+                    .custom-tree-node {
+                    height: 24px;
+                    display: flex;
+                    align-items: center;
+                    .tree-btn {
+                        margin-left: 10px;
+                        display: none;
+                    }
+                    .el-button {
+                        padding: 0px !important;
+                        border-radius: 4px;
+                        background: #363554;
+                        color: #ffffff;
+                    }
+                    }
+                }
+                .el-tree-node__children {
+                    .el-tree-node {
+                    &:not(:first-child) {
+                        .el-tree-node__content {
+                        //border-left: none;
+                        }
+                    }
+                    }
+                }
+            }
+        }
+    }
+
+}
+</style>
+<style scoped lang="scss">
+.business-auth-wrap{
+    border: 1px solid #ECECEC;
+    padding: 20px 30px;
+    background: #fff;
+    border-radius: 4px;
+    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
+    .header{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .name{
+            font-size: 18px;
+            font-weight: bold;
+        }
+    }
+    .auth-wrap{
+        margin-top:20px;
+    }
+}
+</style>

+ 12 - 0
src/views/business_ETA_manage/businessList.vue

@@ -99,6 +99,7 @@
                     </el-table-column>
                     <el-table-column
                         label="操作"
+                        min-width="100"
                         align="center"
                     >
                         <template slot-scope="scope">
@@ -113,6 +114,7 @@
                                     <span class="el-dropdown-link">
                                         <i class="el-icon-more el-icon--right"></i>
                                         <el-dropdown-menu slot="dropdown">
+                                            <el-dropdown-item command="setAuth">权限设置</el-dropdown-item>
                                             <el-dropdown-item command="modifySale">修改销售</el-dropdown-item>
                                             <el-dropdown-item command="disable">{{scope.row.Enable?'禁用':'启用'}}</el-dropdown-item>
                                         </el-dropdown-menu>
@@ -394,6 +396,16 @@ export default {
                 this.showModifySaller=true
             }else if (type==='disable'){
                 this.changeBusinessStatus(data)
+            }else if(type==='setAuth'){
+                /* let {href} = this.$router.resolve({path:`/businessETAAuth`,query:{id:EtaBusinessId}});
+                 window.open(href,'_blank'); */
+                 this.$router.push({
+                    path:'/businessETAAuth',
+                    query:{
+                        id:data.EtaBusinessId,
+                        name:data.BusinessName
+                    }
+                })
             }
         },
 

+ 14 - 22
src/views/custom_manage/compontents/ProductReadInfo.vue

@@ -11,13 +11,9 @@
     <div class="dialog-container">
       <div class="table-info-wrap">
         <div class="table-info">
-          <p  v-if="tableName!=='Total'">{{typeName}}</p>
+          <p>{{typeName}}</p>
           <p>共{{clickToal}}个点击量</p>
         </div>
-        <!-- <div class="btn">
-          <el-button size="mini" type="primary" 
-            v-if="tableName!=='Total'"
-            @click="changeTable({type:'Total'})">返回</el-button></div> -->
       </div>
       <el-table
         :data="tableData"
@@ -34,7 +30,7 @@
             :sortable="item.propName==='VisitCount'"
         >
         <template slot-scope="{row}">
-          <span v-if="item.propName==='VisitCount'" :class="tableName==='Total'&&row[item.propName]>0?'editsty':''">{{row[item.propName]||'0'}}</span>
+          <span v-if="item.propName==='VisitCount'" class="editsty">{{row[item.propName]||'0'}}</span>
           <span v-else-if="item.propName==='Source'">{{row[item.propName]===1?'小程序':'PC端'}}</span>
           <span v-else>{{row[item.propName]||'--'}}</span>
         </template>
@@ -61,10 +57,17 @@ const totalColumn = [
   {
     label:'产品名称',
     propName:'ProductName',
+  },{
+    label:'标题',
+    propName:'Title',
   },{
     label:'点击量',
     propName:'VisitCount',
     widthsty:100
+  },{
+    label:'来源',
+    propName:'Source',
+    widthsty:100
   },{
     label:'最近一次点击时间',
     propName:'RecentTime'
@@ -174,7 +177,8 @@ export default {
         const typeMap = {
           1:'VoicePlay',
           2:'Video',
-          3:'Question'
+          3:'Question',
+          99:'Total',
         }
         this.choosedItem = {
           ProductType: Number(subProductArr[0]),
@@ -191,11 +195,7 @@ export default {
       this.tableName = tableName
       this.tableColumn = columnMap[tableName]
       this.pageNo = 1
-      // if(tableName==='Total'){
-      //   this.getTotalReadInfo()
-      // }else{
-        this.getReadInfoDetail()
-      // }
+      this.getReadInfoDetail()
     },
     //关闭弹窗
     cancelHandle(){
@@ -223,11 +223,7 @@ export default {
     //点击页码
     handleCurrentChange(pageNo){
       this.pageNo = pageNo
-      if(this.tableName==='Total'){
-        this.getTotalReadInfo()
-      }else{
-        this.getReadInfoDetail()
-      }
+      this.getReadInfoDetail()
     },
     //获取总的阅读统计
     async getTotalReadInfo(orderType){
@@ -275,11 +271,7 @@ export default {
     sortChangeHandle({ prop,order }){
       const orderType = order==='ascending'?1:order==='descending'?2:0
       this.pageNo = 1
-      if(this.tableName==='Total'){
-        this.getTotalReadInfo(orderType)
-      }else{
-        this.getReadInfoDetail(orderType)
-      }
+      this.getReadInfoDetail(orderType)
     }
   },
   mounted(){}

+ 24 - 6
src/views/custom_manage/compontents/ReadDialog.vue

@@ -20,7 +20,7 @@
 			</el-select>
 		</div>
 		<p style="margin:15px 0;">共有{{total}}条阅读记录</p>
-		<el-table :data="newList" border style="marginBottom:40px;" height="350">
+		<el-table :data="newList" border style="marginBottom:40px;" height="350" ref="reportTableRef">
 			<el-table-column align="center" label="标题">
 				<template slot-scope="scope">{{scope.row.ResearchReportName}}</template>
 			</el-table-column>
@@ -78,6 +78,10 @@ export default {
 			this.getReportList();
 		},
 		valueType(){
+			this.newList = [];
+			if(this.$refs.reportTableRef.bodyWrapper) {
+				this.$refs.reportTableRef.bodyWrapper.scrollTop = 0;
+			}
 			this.getReportList()
 		}
 	},
@@ -116,25 +120,31 @@ export default {
 				label: 'ficc'
 				}, 
 			],
-			total:0
+			total:0,
+
+			haveMore: false,
+			page_no: 1,
 		};
 	},
 	methods: {
 		cancelHandle() {
 			this.valueType=''
 			this.type = '';
-			this.newList = this.readList;
+			this.newList = [];
 			this.$emit('cancelRead');
 		},
 		getReportList() {
 			customInterence.readList({
 				UserId:Number(this.readId),
 				TxtType:this.valueType?Number(this.valueType):0,
+				LastViewTime: this.newList.length?this.newList[this.newList.length-1].CreatedTime:''
 			}).then(res => {
 				if(res.Ret === 200) {
 					this.total=res.Data.Total
-					this.readList = res.Data.List?res.Data.List:[];
-					this.newList = res.Data.List?res.Data.List:[];
+					this.haveMore = res.Data.List.length ? true : false;
+					this.newList = [...this.newList,...res.Data.List]
+
+					if(this.page_no===1) this.$refs.reportTableRef.bodyWrapper.addEventListener('scroll',this.loadMoreList);
 				}
 			})
 		},
@@ -146,7 +156,15 @@ export default {
 			}else {
 				this.newList = this.readList;
 			}
-		}
+		},
+
+		loadMoreList:_.throttle(function(){
+			const {scrollTop,clientHeight,scrollHeight} = this.$refs.reportTableRef.bodyWrapper
+      if(scrollTop + clientHeight >= scrollHeight-10 && this.haveMore){
+					this.page_no++;
+					this.getReportList();
+			} 
+		},300)
 	},
 	created() {},
 	mounted() {},

+ 4 - 0
src/views/custom_manage/contractStatistics.vue

@@ -231,6 +231,10 @@ import {customInterence} from '@/api/api.js'
         customInterence.getSimpleServiceList().then(res=>{
           if(res.Ret!=200) return
           this.serviceList = res.Data || []
+          // 后端最外层的数据没有给 service_template_id 删除tag时会报错,手动加
+          this.serviceList.map((item,index) =>{
+            item.service_template_id = 500+index
+          })
         })
       },
       getList(){

+ 4 - 4
src/views/custom_manage/customList/customDetail.vue

@@ -627,9 +627,9 @@
 		<product-read-info
 		:productReadInfoShow="productReadInfoShow"
 		:productReadId="productReadId"
-				:subProductId="platform_type"
-				:subProductName="subProductName"
-				:clickToal="clickToal"
+		:subProductId="platform_type"
+		:subProductName="subProductName"
+		:clickToal="clickToal"
 		:productReadTitle="productReadTitle"
 		@close="productReadInfoShow=false"
 		></product-read-info>
@@ -1508,7 +1508,7 @@ export default {
 
 		/* 获取分产品的几种类型 */
 		getSubProductList() {
-			customInterence.getSubProduct().then(res => {
+			customInterence.getSubProduct({StatisticFlag:true}).then(res => {
 				if(res.Ret !== 200) return
 				
 				res.Data.forEach(item => {

+ 13 - 3
src/views/custom_manage/customList/customList.vue

@@ -411,7 +411,11 @@
 					</el-table-column>
 					<el-table-column
 					prop="createTime"
-					:label="act_status=='冻结'?'冻结时间':act_status=='正式'?'转正时间':act_status=='流失'?'流失时间':'创建时间'"
+					:label="
+						act_status=='冻结'?'冻结时间'
+						:act_status=='正式'?'转正时间'
+						:act_status=='流失'?'流失时间'
+						:act_status=='关闭'?'关闭时间':'创建时间'"
 					sortable="custom"
 					align="center" min-width="6.14%">
 						<template slot-scope="scope">
@@ -431,6 +435,9 @@
                                         ? `/${scope.row.LossTime.split('/')[1].substr(0,10)}`
                                         :''}}
 								</template>
+								<template v-else-if="act_status=='关闭'">
+									{{$moment(scope.row.CloseTime).format('YYYY.MM.DD')}}
+								</template>
 								<template v-else>
 									{{$moment(scope.row.CreatedTime).format('YYYY.MM.DD')}}
 								</template>
@@ -2033,7 +2040,10 @@ ShareListDialog},
 				}else{
 					this.SortByTodo = false
 					this.sort_type = item.order === 'ascending' ? 'asc':item.order === 'descending' ? 'desc' : '';
-					this.sort_param = item.column.label=='转正时间'?'formalTime':item.column.label=='冻结时间'?'freezeTime':item.column.label=='流失时间'?'lossTime':item.prop;
+					this.sort_param = item.column.label=='转正时间'?'formalTime'
+									:item.column.label=='冻结时间'?'freezeTime'
+									:item.column.label=='流失时间'?'lossTime'
+									:item.column.label=='关闭时间'?'closeTime':item.prop;
 				}
 				this.page_no = 1;
 				this.getTableData();
@@ -2070,7 +2080,7 @@ ShareListDialog},
 		// 用于返回按钮名称
 		btnName(btnItem,row){
 			if(btnItem!=='BtnSuspend' && btnItem!=='BtnShare') return this.btnCommandList[btnItem]
-			if(btnItem=='BtnSuspend') return row.isSuspend===1?'启用':'暂停'
+			if(btnItem=='BtnSuspend') return row.IsSuspend===1?'启用':'暂停'
 			if(btnItem=='BtnShare') return row.IsShare===1?'取消共享':'设置共享'
 		},
 		// 设置/取消 共享

+ 1 - 1
src/views/custom_manage/customList/customListEn.vue

@@ -281,7 +281,7 @@ import reportVarietyEnSet from '@/components/reportVarietyEnSet.vue'
       },
       handleShowSetVariety(item){
         this.activeItem=item
-        this.checkedVariety=item.EnPermissions||[]
+        this.checkedVariety=_.cloneDeep(item.EnPermissions||[]) 
         this.showSetVariety=true
       },
       handleChangeVariety(){

+ 14 - 2
src/views/custom_manage/customList/limitContactListEn.vue

@@ -75,6 +75,11 @@
     <!-- 添加/编辑联系人 -->
     <contact-save-en-dia :contactsSubmitForm="contactsSubmitForm" title="编辑联系人" :showAddDia.sync="showAddDia"
     :companyId="0" @updateList="getList"></contact-save-en-dia>
+
+    <el-image-viewer 
+        v-if="showViewer" 
+        :on-close="()=>{this.showViewer = false}" 
+        :url-list="[imgUrl]" />
   </div>
 </template>
 
@@ -82,12 +87,13 @@
 import clickNumberDetail from "../compontents/clickNumberDetailDia.vue"
 import ContactSaveEnDia from './components/ContactSaveEnDia.vue';
 import mPage from '@/components/mPage.vue';
+import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
 import { customInterence } from '@/api/api.js'
 
   export default {
     name:'contactLimitList',
     components:{
-      mPage,clickNumberDetail,ContactSaveEnDia
+      mPage,clickNumberDetail,ContactSaveEnDia,ElImageViewer
     },
     data() {
       return {
@@ -110,7 +116,9 @@ import { customInterence } from '@/api/api.js'
           contactsId:""
         },
         showAddDia:false,
-        contactsSubmitForm:{}
+        contactsSubmitForm:{},
+        showViewer:false,
+        imgUrl:''
       }
     },
     watch: {
@@ -208,6 +216,10 @@ import { customInterence } from '@/api/api.js'
           })
         }).catch(() => {});
       },
+      reviewCard(url){
+        this.imgUrl = url
+        this.showViewer = true
+      }
     }
   }
 </script>

+ 3 - 0
src/views/custom_manage/etaTrialList/config.js

@@ -29,6 +29,9 @@ export const etaTrialColumn = [
     key:'LastLoginTime',
     label:'最近一次登录时间',
     minWidth:'120'
+  },{
+    key:'LastLoginDuration',
+    label:'最近一次登录时长',
   },{
     key:'LoginNum',
     label:'累计登录次数',

+ 2 - 2
src/views/custom_manage/etaTrialList/etaTrialList.vue

@@ -184,7 +184,7 @@ export default {
       tableLoading:false,//表格loading
       sortKeys:[
         'Expiration','ModifyTime','LastLoginTime','ActiveTime',
-        'IndexNum','ChartNum','LoginNum'
+        'IndexNum','ChartNum','LoginNum','LastLoginDuration'
       ],//需要排序的字段
       SortParam:'',//排序字段
       SortType:'',//升序降序
@@ -273,7 +273,7 @@ export default {
     },
     sortChangeHandle({prop,order}){
       this.SortParam = prop
-      this.SortType = order==='ascending'?'asc':'desc'
+      this.SortType = order?order==='ascending'?'asc':'desc':''
       this.currentPage=1
       this.getTableData()
     },

+ 4 - 0
src/views/custom_manage/etaTrialList/textQuestionDetail.vue

@@ -74,6 +74,10 @@ import{etaTrialInterence}from '@/api/modules/crmApi.js';
         // this.$router.push('/questionnaireSurvey')
         this.$router.back()
       },
+      pageChange(page_no){
+        this.detailDataSearchP.CurrentIndex = page_no
+        this.getDetailList()
+      }
     },
     created(){
       this.quesitonTitle = this.$route.query.question

+ 73 - 0
src/views/dataReport_manage/components/noRenewalReasonDia/addRemark.vue

@@ -0,0 +1,73 @@
+<template>
+  <el-dialog
+  :visible.sync="isShow"
+  @close="$emit('update:isShow',false)"
+  :modal-append-to-body='false'
+  width="652px"
+  title="添加备注">
+    <div class="dialog-box">
+      <el-form :model="remarkForm" ref="remarkFormRef">
+        <el-form-item prop="text" :rules="{required:true,message:'备注不能为空',trigger:'blur'}">
+          <el-input v-model.trim="remarkForm.text" placeholder="请输入备注信息" type="textarea"
+          style="width: 505px;" :rows="9"></el-input>
+        </el-form-item>
+      </el-form>
+      <div class="dialog-footer">
+        <el-button @click="$emit('update:isShow',false)" class="dialog-footer-button">取消</el-button>
+        <el-button @click="save" type="primary" class="dialog-footer-button" style="margin-left: 30px;">确定</el-button>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  export default{
+    props:{
+      isShow:{
+        type:Boolean,
+        required:true
+      }
+    },
+    data() {
+      return {
+        remarkForm:{
+          text:''
+        }
+      }
+    },
+    watch:{
+      isShow(value){
+        if(value){
+          this.remarkForm.text=""
+          this.$refs.remarkFormRef && this.$refs.remarkFormRef.clearValidate()
+        }
+      }
+    },
+    methods: {
+      save(){
+        this.$refs.remarkFormRef.validate(valid=>{
+          if(valid){
+            this.$emit("saveRemark",this.remarkForm.text)
+            this.$refs.remarkFormRef.resetFields()
+          }
+        })
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .dialog-box{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: flex-start;
+    .dialog-footer{
+      margin: 30px 0;
+      .dialog-footer-button{
+        height: 40px;
+        width: 120px;
+      }
+    }
+  }
+</style>

+ 193 - 0
src/views/dataReport_manage/components/noRenewalReasonDia/confirmedNoRenewal.vue

@@ -0,0 +1,193 @@
+<template>
+  <div>
+    <el-dialog
+    :visible.sync="isShow"
+    @close="$emit('update:isShow',false)"
+    :modal-append-to-body='false'
+    width="652px"
+    title="确认不续约">
+      <div class="dialog-box">
+        <el-form :model="labelForm" ref="confirmNoRenewalFormRef">
+          <el-form-item prop="reason" :rules="{required:true,message:'不续约归因不能为空',trigger:'change'}">
+            <div style="display: flex;align-items: center;justify-content: space-between;">
+              <el-select v-model="labelForm.reason" placeholder="不续约归因" style="width: 424px;">
+                <el-option :label="item.AscribeContent" :value="item.CompanyAscribeId" v-for="item in noRenewalReasonList" :key="item.reasonId"></el-option>
+              </el-select>
+              <span class="create-reason" @click="createReason">新建</span>
+            </div>
+          </el-form-item>
+          <el-form-item prop="detailReason" :rules="{required:true,message:'详细原因不能为空',trigger:'blur'}">
+            <el-input v-model="labelForm.detailReason" placeholder="请描述详细原因" type="textarea"
+            style="width: 505px;" :rows="9"></el-input>
+          </el-form-item>
+        </el-form>
+        <div class="dialog-footer">
+          <el-button @click="$emit('update:isShow',false)" class="dialog-footer-button">取消</el-button>
+          <el-button @click="save" type="primary" class="dialog-footer-button" style="margin-left: 30px;">确定</el-button>
+        </div>
+      </div>
+    </el-dialog>
+    <el-dialog
+    :visible.sync="createReasonShow"
+    @close="resetReasonForm"
+    :modal-append-to-body='false'
+    width="652px"
+    title="新建归因">
+      <div class="dialog-box">
+        <el-form :model="remarkForm" ref="confirmReasonRef">
+          <el-form-item prop="AscribeContent" :rules="{required:true,message:'归因不能为空',trigger:'blur'}">
+            <el-autocomplete class="autocomplete-input" v-model.trim="remarkForm.AscribeContent" 
+            :fetch-suggestions="querySearch" placeholder="请输入归因名称"></el-autocomplete>
+          </el-form-item>
+        </el-form>
+        <div class="dialog-footer">
+          <el-button @click="createReasonShow=false" class="dialog-footer-button">取消</el-button>
+          <el-button @click="saveReason" type="primary" class="dialog-footer-button" style="margin-left: 30px;">确定</el-button>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+
+</template>
+
+<script>
+import { dataMainInterface } from '@/api/api.js'
+
+  export default{
+    props:{
+      isShow:{
+        type:Boolean,
+        required:true
+      },
+      dataForm:{
+        type:Object,
+        required:true
+      },
+      noRenewalReasonList:{
+        type:Array,
+        required:true
+      }
+    },
+    watch:{
+      isShow(value){
+        if(value){
+          this.labelForm.reason = this.dataForm.reason
+          this.labelForm.detailReason = this.dataForm.detailReason
+          this.$nextTick(()=>{
+            this.$refs.confirmNoRenewalFormRef && this.$refs.confirmNoRenewalFormRef.clearValidate()
+          })
+        }
+      }
+    },
+    computed: {
+      Role() {
+        let role = localStorage.getItem('Role') || '';
+        return role;
+      },
+      //确认未续约权限
+      canConfirmNotRenewed(){
+        return ['admin','rai_admin'].includes(this.Role)
+      }
+	  },
+    data() {
+      return {
+        remarkForm:{
+          AscribeContent:''
+        },
+        labelForm:{
+          reason:'',
+          detailReason:''
+        },
+        createReasonShow:false
+      }
+    },
+    methods: {
+      createReason(){
+        this.createReasonShow=true
+      },
+      resetReasonForm(){
+        this.remarkForm.AscribeContent=""
+        this.$refs.confirmReasonRef.clearValidate()
+      },
+      querySearch(queryString,cb){
+        if(!queryString){
+          cb(this.noRenewalReasonList.map(item => {
+            return {value:item.AscribeContent}
+          }))
+        }else{
+          // dataMainInterface.getAscribList({KeyWord:queryString}).then(res=>{
+          //   if(res.Ret == 200){
+          //     let suggestionsReason = res.Data.List || []
+          //     cb(suggestionsReason.map(item => {
+          //       return {value:item.AscribeContent}
+          //     }))
+          //   }
+          // }).catch(()=>{
+          //   cb([])
+          // })
+          cb(this.noRenewalReasonList.map(item => {
+            if(item.AscribeContent.indexOf(queryString)!=-1){
+              return {value:item.AscribeContent}
+            }
+          }).filter(Boolean))
+        }
+      },
+      saveReason(){
+        this.$refs.confirmReasonRef.validate(valid=>{
+          if(valid){
+            this.remarkForm.AscribeContent=this.remarkForm.AscribeContent.replace(/\s*/g,"")
+            dataMainInterface.addAscrib({AscribeContent:this.remarkForm.AscribeContent})
+            .then(res=>{
+              if(res.Ret ==200){
+                this.$message.success("新建成功")
+                this.createReasonShow=false
+                this.$emit("refreshReasonList")
+              }
+            })
+          }
+        })
+      },
+      save(){
+        if((this.Role!='rai_admin' && this.dataForm.reason) || (!this.canConfirmNotRenewed)){
+          this.$message.error("仅管理员可修改")
+          return 
+        }
+        this.$refs.confirmNoRenewalFormRef.validate(valid=>{
+          if(valid){
+            this.$emit("saveLabel",{CompanyAscribeId:this.labelForm.reason,Content:this.labelForm.detailReason})
+          }
+        })
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .dialog-box{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: flex-start;
+    .create-reason{
+      cursor: pointer;
+      color: #409EFF;
+      font-size: 14px;
+      margin-right: 20px;
+    }
+    .dialog-footer{
+      margin: 30px 0;
+      .dialog-footer-button{
+        height: 40px;
+        width: 120px;
+      }
+    }
+  }
+</style>
+<style lang="scss">
+.autocomplete-input{
+  .el-input{
+    width: 505px;
+  }
+}
+
+</style>

+ 62 - 0
src/views/dataReport_manage/components/noRenewalReasonDia/viewRemark.vue

@@ -0,0 +1,62 @@
+<template>
+  <el-dialog
+  :visible.sync="isShow"
+  @close="$emit('update:isShow',false)"
+  :modal-append-to-body='false'
+  width="652px"
+  title="历史备注">
+    <div class="dialog-box">
+      <el-table
+        :data="tableData"
+        border
+        max-height="360">
+        <el-table-column label="备注信息" prop="Content" align="center">
+          <template slot-scope="{row}">
+            {{row.Content}}
+          </template>
+        </el-table-column>
+        <el-table-column label="备注时间" prop="CreateTime" align="center">
+          <template slot-scope="{row}">
+            {{row.CreateTime}}
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  export default{
+    props:{
+      isShow:{
+        type:Boolean,
+        required:true
+      },
+      tableData:{
+        type:Array,
+        default:()=>[]
+      }
+    },
+    data() {
+      return {
+ 
+      }
+    },
+    methods: {
+      save(){
+        this.$refs.remarkFormRef.validate(valid=>{
+          if(valid){
+            this.$emit("saveRemark",this.remarkForm.text)
+            this.$refs.remarkFormRef.resetFields()
+          }
+        })
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .dialog-box{
+    padding: 0 35px 20px;
+  }
+</style>

+ 29 - 1
src/views/dataReport_manage/configdata.js

@@ -67,6 +67,13 @@ export const incrementTableColums = [
 		key:"ProductName",
 		widthsty:'100px'
 	},
+	{
+		label:"不续约归因",
+		key:"AscribeContent",
+		dataType:"未续约客户",
+		notRenewedConfirm:1,
+		sort:true
+	},
 	{
 		label:"客户状态",
 		key:"Status",
@@ -114,13 +121,20 @@ export const incrementTableColums = [
 		dataType:"未续约客户",
 		sort:true
 	},
+	{
+		label:"备注",
+		key:"Remark",
+		dataType:"未续约客户",
+		widthsty:'100px',
+		sort:true
+	},
 	{
 		label:"未续约说明",
 		key:"RenewalReason",
 		dataType:"未续约客户",
 		widthsty:'300px',
 		sort:true
-	},
+	}
 ]
 /* 存量客户表格列 */
 export const stockTableColums = [
@@ -136,6 +150,13 @@ export const stockTableColums = [
 		key:"ProductName",
 		widthsty:'100px'
 	},
+	{
+		label:"不续约归因",
+		key:"AscribeContent",
+		dataType:"未续约客户",
+		notRenewedConfirm:1,
+		sort:true
+	},
 	{
 		label:"客户状态",
 		key:"Status",
@@ -161,6 +182,13 @@ export const stockTableColums = [
 		key:"EndDate",
 		dataType:"未续约客户"
 	},
+	{
+		label:"备注",
+		key:"Remark",
+		dataType:"未续约客户",
+		widthsty:'100px',
+		sort:true
+	},
 	{
 		label:"未续约说明",
 		key:"RenewalReason",

+ 224 - 7
src/views/dataReport_manage/incrementalList.vue

@@ -1,5 +1,5 @@
 <template>
-	<div class="dataReport-container">
+	<div class="dataReport-container" id="dataReport-container">
 		<div class="dataReport-top">
 			<a :href="exportExcel" download>
 				<button class="button-sty act">导出EXCEL</button>
@@ -133,7 +133,22 @@
 				</el-row>
 			</div>
 			<div class="tabs-box" v-if="filterObj.data_type=='未续约客户'">
-				<span @click="tabsHandler(item)" :class="tabsActiveName===item.value ? 'active':''" v-for="item in tabsList" :key="item">{{item.name}}({{item.name==='试用'?NotRenewalTryOut:NotRenewalNotTryOut}})</span>
+				<el-radio-group v-model="isNotRenewedConfirm" class="tabs-box-confirm" @change="notRenewedConfirmChange">
+					<el-radio-button :label="1">已确认</el-radio-button>
+					<div class="center-line"></div>
+					<el-radio-button :label="0">待确认</el-radio-button>
+				</el-radio-group>
+				<div class="tabs-box-status" v-show="isNotRenewedConfirm">
+					<el-select v-model="noRenewalReasonId" placeholder="请选择不续约归因"
+					clearable @change="getTableData" style="width: 240px;margin-right: 50px;">
+						<el-option :label="item.AscribeContent" :value="item.CompanyAscribeId"
+						v-for="item in noRenewalReasonList" :key="item.reasonId"></el-option>
+					</el-select>
+					<span @click="tabsHandler(item)" :class="tabsActiveName===item.value ? 'active':''" 
+					v-for="item in tabsList" :key="item">
+						{{item.name}}({{item.name==='试用'?NotRenewalTryOut:NotRenewalNotTryOut}})
+					</span>
+				</div>
 			</div>
 			<el-table
 				:data="tableData"
@@ -148,7 +163,7 @@
 				:label="item.label"
 				:width="item.widthsty"
 				align="center"
-				v-if="!item.dataType || item.dataType === filterObj.data_type">
+				v-if="controlTableColumnShow(item)">
 					<template slot-scope="scope">
 						<span 
 							:style="item.textsty" 
@@ -175,6 +190,17 @@
 								{{scope.row.PackageDifference}}
 							</div>
 						</div>
+						<div v-else-if="item.key==='Remark' " class="remark-row">
+							<span class="remark-text" @click="viewHistoryRemarkFun(scope.row)" v-if="scope.row.IsShowNoRenewedNote">...</span>
+							<span class="operation-button" v-show="canConfirmNotRenewed && (!isNotRenewedConfirm)"
+							 style="margin-right: 0;" @click="addRemarkFun(scope.row)">添加</span>
+						</div>
+						<div v-else-if="item.key=='AscribeContent'">
+							<span style="color: #409EFF;cursor: pointer;"
+								@click="editReasonLabel(scope.row)" >
+								{{scope.row[item.key]}}
+							</span>
+						</div>
 						<span 
 							v-else 
 							:style="item.textsty" 
@@ -186,6 +212,14 @@
 					</template>
 				</el-table-column>
 			</template>
+			<el-table-column label="操作" width="180px" align="center"
+			v-if="canConfirmNotRenewed && (!isNotRenewedConfirm) && filterObj.data_type =='未续约客户'" >
+				<template slot-scope="scope">
+					<div class="operation-row">
+						<span class="operation-button" @click="confirmedNoRenewalFun(scope.row)">确认不续约</span>
+					</div>
+				</template>
+			</el-table-column>
 				<div slot="empty" style="lineHeight:44px;margin:60px 0;color:#999;">
 					<img src="~@/assets/img/cus_m/nodata.png" alt="" style="display:block;width:160px;height:128px;margin: auto;">
 					<span>暂无数据</span>
@@ -200,6 +234,13 @@
 		</div>
 		<!-- 未续约说明列表弹窗 -->
 		<renewalListDia :isShow.sync="isRenewalShow" :rowInfo="rowInfo"/>
+		<!-- 添加备注弹窗 -->
+		<addRemark :isShow.sync="isAddRemarkShow" @saveRemark="saveRemark"  />
+		<!-- 历史备注弹窗 -->
+		<viewRemark :isShow.sync="isViewRemarkShow" :tableData="historyRemarkList" />
+		<!-- 确认不续约弹窗 -->
+		<confirmedNoRenewal :isShow.sync="isConfirmNoRenewalShow" :dataForm="confirmNoRenewalForm" 
+			:noRenewalReasonList="noRenewalReasonList" @refreshReasonList="getNORenewalReasonList" @saveLabel="saveLabel" />
 	</div>
 </template>
 
@@ -208,11 +249,15 @@ import { incrementTableColums } from './configdata.js'
 import { dataMainInterface,customInterence } from '@/api/api.js'
 import mPage from '@/components/mPage.vue'
 import renewalListDia from './components/renewalListDia.vue'
+import addRemark from './components/noRenewalReasonDia/addRemark.vue'
+import viewRemark from './components/noRenewalReasonDia/viewRemark.vue'
+import confirmedNoRenewal from './components/noRenewalReasonDia/confirmedNoRenewal.vue'
+
 var moment = require('moment');
 moment().format();
 export default {
 	name:'',
-	components: {mPage,renewalListDia},
+	components: {mPage,renewalListDia,addRemark,viewRemark,confirmedNoRenewal},
 	computed: {
 		exportExcel() {
 			let baseUrl = process.env.API_ROOT + "/statistic_report/incremental_company_list";
@@ -234,6 +279,8 @@ export default {
 				DataType: this.filterObj.data_type == '新增试用客户' ? '新增试用' : this.filterObj.data_type,
 				Keyword:this.searchVal,
 				IsExport:true,
+				IsConfirm:this.filterObj.data_type=='未续约客户'?1:-1,
+				CompanyAscribeId:this.noRenewalReasonId
 			};
 			for (let key in obj) {
 				paramStr = `${paramStr}&${key}=${obj[key]}`;
@@ -252,6 +299,10 @@ export default {
 		ManageType() {
 			return localStorage.getItem('ManageType') || '';
 		},
+		//确认未续约权限
+		canConfirmNotRenewed(){
+			return ['admin','rai_admin'].includes(this.Role)
+		}
 	},
 	data () {
 		return {
@@ -322,6 +373,21 @@ export default {
 			tabsActiveName:'试用',
 			NotRenewalNotTryOut:0,//冻结流失的人数
 			NotRenewalTryOut:0,//试用的人数
+			isNotRenewedConfirm:1,//未续约的是否已确认
+			noRenewalReasonList:[],
+			noRenewalReasonId:'',
+			selectItemRow:{},// 当前选中的row
+			// 添加备注
+			isAddRemarkShow:false,
+			//历史备注
+			isViewRemarkShow:false,
+			historyRemarkList:[],
+			//确认不续约
+			isConfirmNoRenewalShow:false,
+			confirmNoRenewalForm:{
+				reason:"",
+				detailReason:""
+			}
 		};
 	},
 	/* 页面跳转前记录参数 */
@@ -343,6 +409,11 @@ export default {
 		next()
 	},
 	methods: {
+		controlTableColumnShow(item){
+			return !item.dataType || 
+							(item.dataType === this.filterObj.data_type && 
+							(!item.notRenewedConfirm || item.notRenewedConfirm==this.isNotRenewedConfirm)) // 已确认和待确认
+		},
 		// 搜索
 		handleSearch(){
 			if(!this.searchVal){
@@ -380,6 +451,13 @@ export default {
 		//tabs 的点击事件
 		tabsHandler(item) {
 			this.tabsActiveName = item.value;
+			this.noRenewalReasonId=''
+			this.page_no = 1;
+			this.getTableData()
+		},
+		notRenewedConfirmChange(){
+			this.tabsActiveName = '试用'
+			this.noRenewalReasonId=''
 			this.page_no = 1;
 			this.getTableData()
 		},
@@ -403,7 +481,9 @@ export default {
 				EndDate: this.end_date,
 				StartDate: this.start_date,
 				DataType: this.filterObj.data_type == '新增试用客户' ? '新增试用' : this.filterObj.data_type,
-				TryOutType:this.filterObj.data_type=='未续约客户'? this.tabsActiveName : '',
+				TryOutType:this.filterObj.data_type=='未续约客户' && this.isNotRenewedConfirm==1? this.tabsActiveName : '',
+				IsConfirm:this.filterObj.data_type=='未续约客户'?this.isNotRenewedConfirm:-1,
+				CompanyAscribeId:this.noRenewalReasonId
 			}
 			dataMainInterface.incrementalList(params).then(res => {
 				if(res.Ret === 200) {
@@ -450,6 +530,10 @@ export default {
 		/* 切换数据类型 */
 		toggleType(label) {
 			this.filterObj.data_type = label;
+			this.noRenewalReasonId=''
+			if(label == "未续约客户"){
+				this.getNORenewalReasonList()
+			}
 			this.tabsActiveName = '试用';
 			this.page_no = 1;
 			this.getTableData()
@@ -490,7 +574,13 @@ export default {
 				})
 			}
 		},
-
+		getNORenewalReasonList(){
+			dataMainInterface.getAscribList().then(res=>{
+				if(res.Ret == 200){
+					this.noRenewalReasonList=res.Data.List||[]
+				}
+			})			
+		},
 		// 未续约说明更多按钮
 		renewalReasonMore(row){
 			this.rowInfo={
@@ -499,6 +589,71 @@ export default {
 			}
 			this.isRenewalShow=true
 		},
+		// 添加备注
+		addRemarkFun(row){
+			this.selectItemRow=row
+			this.isAddRemarkShow=true
+		},
+		// 添加备注 保存
+		saveRemark(remark){
+			// console.log(remark);
+			let params={
+				CompanyId:this.selectItemRow.CompanyId,
+				ProductId:this.selectItemRow.ProductId,
+				Content:remark
+			}
+			dataMainInterface.addNotRenewedRemark(params).then(res=>{
+				if(res.Ret == 200){
+					this.$message.success("添加成功")
+					this.getTableData()
+					this.isAddRemarkShow=false
+					this.selectItemRow={}
+				}
+			})
+		},
+		// 查看历史备注
+		viewHistoryRemarkFun(row){
+			dataMainInterface.getNotRenewedRemarkList({CompanyId:row.CompanyId,ProductId:row.ProductId})
+			.then(res=>{
+				if(res.Ret == 200){
+					this.historyRemarkList=res.Data.List || []
+					this.isViewRemarkShow=true
+				}
+			})
+		},
+		confirmedNoRenewalFun(row){
+			this.confirmNoRenewalForm.reason = ""
+			this.confirmNoRenewalForm.detailReason = ""
+			this.selectItemRow = row
+			this.isConfirmNoRenewalShow=true
+		},
+		editReasonLabel(row){
+			dataMainInterface.infoNoRenewedAscribe({CompanyId:row.CompanyId,ProductId:row.ProductId})
+			.then(res=>{
+				if(res.Ret == 200){
+					this.confirmNoRenewalForm.reason = res.Data.Detail?res.Data.Detail.CompanyAscribeId||"":""
+					this.confirmNoRenewalForm.detailReason = res.Data.Detail?res.Data.Detail.Content||"":""
+					this.selectItemRow=row
+					this.isConfirmNoRenewalShow=true
+				}
+			})
+		},
+		saveLabel(item){
+			let params={
+				CompanyId:this.selectItemRow.CompanyId,
+				ProductId:this.selectItemRow.ProductId,
+				CompanyAscribeId:item.CompanyAscribeId,
+				Content:item.Content
+			}
+			dataMainInterface.addNoRenewedAscribe(params).then(res=>{
+				if(res.Ret == 200){
+					this.$message.success("确认成功")
+					this.isConfirmNoRenewalShow=false
+					this.selectItemRow={}
+					this.getTableData()
+				}
+			})
+		}
 	},
 	created() {},
 	mounted() {
@@ -517,6 +672,68 @@ export default {
 	},
 }
 </script>
-<style lang='scss'>
+<style lang='scss' scoped>
 @import './index.scss';
+.tabs-box{
+	flex-direction: column;
+	.tabs-box-confirm{
+		display: flex;
+		align-items: center;
+		margin-bottom: 20px;
+		.center-line{
+			width: 1px;
+			height: 21px;
+			background-color: #333333;
+			margin: 0 20px;
+		}
+	}
+
+}
+.operation-button{
+		color:#409EFF;
+		cursor: pointer;
+		font-size: 14px;
+		margin-right: 10px;
+	}
+.remark-row{
+	display: flex;
+	justify-content: center;
+	.remark-text{
+		width:18px ;
+		height: 18px;
+		margin-right: 8px;
+		font-size: 18px;
+		color: #409EFF;
+		cursor: pointer;
+	}
+}
+.operation-row{
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	flex-wrap: wrap;
+	.operation-button{
+		&:last-child{
+			margin-right:0;
+		}
+	}
+}
+
+</style>
+<style lang="scss">
+#dataReport-container{
+	.tabs-box{
+		.el-radio-button{
+			margin-right: 0;
+		}
+		.el-radio-button .el-radio-button__inner{
+			border: none;
+			width: 120px;
+			height: 40px;
+			border-radius: 4px;
+		}
+	}
+}
+
+
 </style>

+ 104 - 3
src/views/dataReport_manage/stockCutomList.vue

@@ -120,6 +120,11 @@
 					</el-col>	
 				</el-row>
 			</div>
+			<el-select v-model="noRenewalReasonId" placeholder="请选择不续约归因" v-show="filterObj.data_type=='未续约客户'"
+			clearable @change="getTableData" style="width: 240px;margin-top: 40px;">
+				<el-option :label="item.AscribeContent" :value="item.CompanyAscribeId"
+				v-for="item in noRenewalReasonList" :key="item.reasonId"></el-option>
+			</el-select>
 			<div class="tabs-box" v-if="filterObj.data_type=='未续约客户'">
 				<span @click="tabsHandler(item)" :class="tabsActiveName===item.value ? 'active':''" v-for="item in tabsList" :key="item">{{item.name}}({{item.name==='试用'?NotRenewalTryOut:NotRenewalNotTryOut}})</span>
 			</div>
@@ -167,6 +172,15 @@
 								{{scope.row.PackageDifference}}
 							</div>
 						</div>
+						<div v-else-if="item.key==='Remark' " class="remark-row">
+							<span class="remark-text" @click="viewHistoryRemarkFun(scope.row)" v-if="scope.row.IsShowNoRenewedNote">...</span>
+						</div>
+						<div v-else-if="item.key=='AscribeContent'">
+							<span style="color: #409EFF;cursor: pointer;"
+								@click="editReasonLabel(scope.row)" >
+								{{scope.row[item.key]}}
+							</span>
+						</div>
 						<span 
 							v-else
 							:style="item.textsty" 
@@ -190,6 +204,11 @@
 		</div>
 		<!-- 未续约说明列表弹窗 -->
 		<renewalListDia :isShow.sync="isRenewalShow" :rowInfo="rowInfo"/>
+		<!-- 历史备注弹窗 -->
+		<viewRemark :isShow.sync="isViewRemarkShow" :tableData="historyRemarkList" />
+		<!-- 确认不续约弹窗 -->
+		<confirmedNoRenewal :isShow.sync="isConfirmNoRenewalShow" :dataForm="confirmNoRenewalForm" 
+			:noRenewalReasonList="noRenewalReasonList" @refreshReasonList="getNORenewalReasonList" @saveLabel="saveLabel" />
 	</div>
 </template>
 
@@ -198,11 +217,14 @@ import { stockTableColums } from './configdata.js'
 import { dataMainInterface,customInterence } from '@/api/api.js'
 import mPage from '@/components/mPage.vue'
 import renewalListDia from './components/renewalListDia.vue'
+import viewRemark from './components/noRenewalReasonDia/viewRemark.vue'
+import confirmedNoRenewal from './components/noRenewalReasonDia/confirmedNoRenewal.vue'
+
 var moment = require('moment');
 moment().format();
 export default {
 	name:'',
-	components: {mPage,renewalListDia},
+	components: {mPage,renewalListDia,viewRemark,confirmedNoRenewal},
 	computed: {
 		exportExcel() {
 			let baseUrl = process.env.API_ROOT + "/statistic_report/stack_company_list";
@@ -225,6 +247,8 @@ export default {
 				DataType: this.filterObj.data_type,
 				Keyword:this.searchVal,
 				IsExport:true,
+				IsConfirm:this.filterObj.data_type=='未续约客户'?1:-1,
+				CompanyAscribeId:this.noRenewalReasonId,
 			};
 			for (let key in obj) {
 				paramStr = `${paramStr}&${key}=${obj[key]}`;
@@ -242,7 +266,7 @@ export default {
 		//管理权限
 		ManageType() {
 			return localStorage.getItem('ManageType') || '';
-		},
+		}
 	},
 	data () {
 		return {
@@ -296,6 +320,18 @@ export default {
 			tabsActiveName:'试用',
 			NotRenewalNotTryOut:0,//冻结流失的人数
 			NotRenewalTryOut:0,//试用的人数
+			noRenewalReasonList:[],
+			noRenewalReasonId:'',
+			selectItemRow:{},// 当前选中的row
+			//历史备注
+			isViewRemarkShow:false,
+			historyRemarkList:[],
+			//确认不续约
+			isConfirmNoRenewalShow:false,
+			confirmNoRenewalForm:{
+				reason:"",
+				detailReason:""
+			}
 		};
 	},
 	/* 页面跳转前记录参数 */
@@ -354,6 +390,8 @@ export default {
 				DataType: this.filterObj.data_type,
 				Keyword:this.searchVal,
 				TryOutType:this.filterObj.data_type=='未续约客户'? this.tabsActiveName : '',
+				IsConfirm:-1,
+				CompanyAscribeId:this.noRenewalReasonId,
 			}
 			dataMainInterface.stackList(params).then(res => {
 				if(res.Ret === 200) {
@@ -379,6 +417,10 @@ export default {
 		/* 切换数据类型 */
 		toggleType(label) {
 			this.filterObj.data_type = label;
+			if(label == "未续约客户"){
+				this.getNORenewalReasonList()
+			}
+			this.noRenewalReasonId=''
 			this.tabsActiveName = '试用';
 			this.page_no = 1;
 			this.searchVal=''
@@ -415,6 +457,53 @@ export default {
 			}
 			this.isRenewalShow=true
 		},
+		getNORenewalReasonList(){
+			dataMainInterface.getAscribList().then(res=>{
+				if(res.Ret == 200){
+					this.noRenewalReasonList=res.Data.List||[]
+				}
+			})			
+		},
+		// 查看历史备注
+		viewHistoryRemarkFun(row){
+			// console.log(row);
+			dataMainInterface.getNotRenewedRemarkList({CompanyId:row.CompanyId,ProductId:row.ProductId})
+			.then(res=>{
+				if(res.Ret == 200){
+					this.historyRemarkList=res.Data.List || []
+					this.isViewRemarkShow=true
+				}
+			})
+		},
+		editReasonLabel(row){
+			// console.log(row);
+			dataMainInterface.infoNoRenewedAscribe({CompanyId:row.CompanyId,ProductId:row.ProductId})
+			.then(res=>{
+				if(res.Ret == 200){
+					this.confirmNoRenewalForm.reason = res.Data.Detail?res.Data.Detail.CompanyAscribeId||"":""
+					this.confirmNoRenewalForm.detailReason = res.Data.Detail?res.Data.Detail.Content||"":""
+					this.selectItemRow=row
+					this.isConfirmNoRenewalShow=true
+				}
+			})
+		},
+		saveLabel(item){
+			// console.log(item);
+			let params={
+				CompanyId:this.selectItemRow.CompanyId,
+				ProductId:this.selectItemRow.ProductId,
+				CompanyAscribeId:item.CompanyAscribeId,
+				Content:item.Content
+			}
+			dataMainInterface.addNoRenewedAscribe(params).then(res=>{
+				if(res.Ret == 200){
+					this.$message.success("确认成功")
+					this.isConfirmNoRenewalShow=false
+					this.selectItemRow={}
+					this.getTableData()
+				}
+			})
+		}
 	},
 	created() {},
 	mounted() {
@@ -430,6 +519,18 @@ export default {
 	},
 }
 </script>
-<style lang='scss'>
+<style lang='scss' scoped>
 @import './index.scss';
+.remark-row{
+	display: flex;
+	justify-content: center;
+	.remark-text{
+		width:18px ;
+		height: 18px;
+		margin-right: 8px;
+		font-size: 18px;
+		color: #409EFF;
+		cursor: pointer;
+	}
+}
 </style>

+ 1 - 0
src/views/interaction_manage/videoManage.vue

@@ -978,6 +978,7 @@ export default {
                 this.imgPopData.name=item.CoverName
                 this.imgPopData.imgUrl=item.CoverUrl
                 this.imgPopData.coverId=item.CommunityVideoCoverId
+                this.imgPopData.videoType=item.Type.toString()
             }
             this.showImgPop=true
             this.$nextTick(()=>{

+ 143 - 0
src/views/login_manage/EmailModel.vue

@@ -0,0 +1,143 @@
+<template>
+    <div class="email-model-wrap model-wrap">
+        <el-form 
+            ref="modelForm" 
+            label-position="right" 
+            label-width="0px"
+            :model="form"
+            :rules="rules">
+            <el-form-item prop="email">
+                <el-input
+                    type="text"
+                    v-model="form.email"
+                    auto-complete="off"
+                    placeholder="请输入邮箱"
+                >
+                </el-input>
+                <span class="inline-message el-form-item__error" 
+                    v-show="(emailCheck||accountForbidden)&&form.email.length">
+                    {{hintMessage}}
+                </span>
+            </el-form-item>
+            <el-form-item prop="picCode">
+                <el-input
+                    class="input-with-slot"
+                    type="text"
+                    v-model="form.picCode"
+                    auto-complete="off"
+                    placeholder="请输入图形验证码"
+                >
+                    <div class="pic-box" slot="append" @click="getCodePic">
+                        <img :src="picSrc" alt="图形验证码"/>
+                    </div>
+                </el-input>
+            </el-form-item>
+            <el-form-item prop="checkCode" class="code-input">
+                <el-input
+                    type="text"
+                    v-model="form.checkCode"
+                    auto-complete="off"
+                    placeholder="请输入验证码"
+                ></el-input>
+                <el-button type="text" class="code-btn" @click="checkForm" :disabled="codeCountDown<60&&codeCountDown>0">{{codeStr}}</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+
+<script>
+import modelMixins from './modelMixins';
+import {patternEmail} from '@/utils/commonOptions'
+import {departInterence} from "@/api/api.js";
+export default {
+    mixins:[modelMixins],
+    props:{
+        emailCheck:{
+            type:Boolean,
+            default:false
+        },
+        accountForbidden:{
+            type:Boolean,
+            default:false
+        },
+        Source:{//请求验证码来源:1登陆
+            type:Number,
+            default:1
+        },
+        isMobile:{
+            type:Boolean,
+            default:false
+        },
+    },
+    data() {
+        return {
+            hasPicCode:true,
+            picSrc:'',
+            picId:'',
+            timer:0,
+            codeStr:'获取验证码',
+            codeCountDown:60,
+            form:{
+                email:'',
+                picCode:'',
+                checkCode:''
+            },
+            rules:{
+                email:[
+                    {required:true,message:'请输入邮箱',trigger:'blur'},
+                    {validator:(rule,value,callback)=>{
+                        if(!patternEmail.test(value)){
+                            callback(new Error("请输入正确的邮箱格式"))
+                        }else{
+                            callback()
+                        }
+                    },trigger:'blur'}
+                ],
+                picCode:[{required:true,message:'请输入图形验证码',trigger:'blur'}],
+                checkCode:[{required:true,message:'请输入短信验证码',trigger:'blur'}]
+            },
+            hintMessage:''
+        };
+    },
+    methods: {
+        checkForm(){
+            //首先检查是否是重新获取验证码
+            if(this.codeStr==='重新获取'){
+                //引导用户重新输入图形验证码
+                this.getCodePic()
+                this.form.picCode = ''
+            }
+            //检查邮箱和图形验证码是否正确
+            const {email,picCode} = this.form
+            if(!picCode.length){
+                this.$message.warning('请输入图形验证码')
+                return
+            }
+            if(!patternEmail.test(email)){
+                this.$message.warning('请输入正确的邮箱')
+                return
+            }
+            //通过请求发送验证码
+            departInterence.getCodeVerify({
+                VerifyType:2,
+                CaptchaId:this.picId,
+                CaptchaCode:picCode,
+                Email:email,
+                Source:this.Source
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.$message.success('验证码已发送')
+                //60秒倒计时
+                this.countDown()
+                this.timer = setInterval(()=>{
+                    this.countDown()
+                },1000)
+            })
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+@import "./css/formStyle.scss";
+</style>

+ 430 - 0
src/views/login_manage/ForgetPassModel.vue

@@ -0,0 +1,430 @@
+<template>
+    <div class="forget-pass-model">
+        <div class="header-nav" @click="changeModel">
+            <span><i class="el-icon-back"></i></span>
+            <span v-if="!isMobile">忘记密码</span>
+            <span v-else>{{ forgetPassTextMobile }}</span>
+        </div>
+        <div class="step-container model-wrap" v-show="currentStep===0">
+            <el-form 
+                ref="modelForm" 
+                label-position="right" 
+                label-width="0px"
+                :model="form"
+                :rules="rules">
+                <el-form-item prop="account">
+                    <el-input
+                        type="text"
+                        v-model="form.account"
+                        auto-complete="off"
+                        placeholder="请输入账号">
+                    </el-input>
+                </el-form-item>
+                <el-form-item prop="picCode">
+                    <el-input
+                        class="input-with-slot"
+                        type="text"
+                        v-model="form.picCode"
+                        auto-complete="off"
+                        placeholder="请输入图形验证码"
+                    >
+                        <div class="pic-box" slot="append" @click="getCodePic">
+                            <img :src="picSrc" alt="图形验证码"/>
+                        </div>
+                    </el-input>
+                </el-form-item>
+            </el-form>
+            <el-button class="submit_btn" @click="getUserInfo">下一步</el-button>
+        </div>
+        <div class="step-container" v-show="currentStep>0">
+            <div class="container-header">
+                <p>您正在找回账号{{form.account}}的密码</p>
+                <ModelSteps :active-step="currentStep"/>
+            </div>
+            <div class="container-inner model-wrap" v-show="currentStep===1 && (!isMobile)">
+                <VerificationBox
+                    verifies-type="mobile"
+                    :info-text="userMobile||'暂未绑定'"
+                    :hideBtn="!userMobile"
+                    @goNext="getCode"
+                />
+                <VerificationBox
+                    verifies-type="email"
+                    :info-text="userEmail||'暂未绑定'"
+                    :hideBtn="!userEmail"
+                    @goNext="getCode"
+                />
+            </div>
+            <div v-show="currentStep===1 && isMobile">
+                <div class="verification-item" 
+                    :class="{'active':choosedWay==='mobile','disabled':!userMobile.length}" @click="choosedWay = 'mobile'">
+                    <!-- <div class="icon"> -->
+                        <img src="~@/assets/img/icons/phone-login-type.png" />
+                    <!-- </div> -->
+                    <div class="text">{{userMobile||'暂未绑定'}}</div>
+                </div>
+                <div class="verification-item"
+                    :class="{'active':choosedWay==='email','disabled':!userEmail.length}" @click="choosedWay = 'email'">
+                    <!-- <div class="icon"> -->
+                        <img src="~@/assets/img/icons/email-login-type.png" />
+                    <!-- </div> -->
+                    <div class="text">{{userEmail||'暂未绑定'}}</div>
+                </div>
+                <el-button class="verification-button" type="primary" round @click="getCode(choosedWay)"
+                v-show="userMobile.length || userEmail.length">获取验证码</el-button>
+            </div>
+            <div class="container-inner" v-show="currentStep===2">
+                <CaptchaInput 
+                    ref="captInput"
+                />
+                <div class="btn-wrap">
+                    <el-button type="primary" plain @click="changeModel">上一步</el-button>
+                    <el-button type="primary" @click="checkInput">下一步</el-button>
+                </div>
+            </div>
+            <div class="container-inner model-wrap" v-show="currentStep===3">
+                <el-form 
+                    ref="passForm" 
+                    label-position="right" 
+                    label-width="0px"
+                    :model="passForm"
+                    :rules="passRules">
+                    <el-form-item prop="pass1">
+                        <el-input
+                            type="password" show-password
+                            v-model.trim="passForm.pass1"
+                            auto-complete="off"
+                            @copy.native.capture.prevent="()=>{return false}"
+                            @cut.native.capture.prevent="()=>{return false}"
+                            @paste.native.capture.prevent="()=>{return false}"
+                            placeholder="请输入新密码">
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item prop="pass2">
+                        <el-input
+                            type="password" show-password
+                            v-model.trim="passForm.pass2"
+                            auto-complete="off"
+                            @copy.native.capture.prevent="()=>{return false}"
+                            @cut.native.capture.prevent="()=>{return false}"
+                            @paste.native.capture.prevent="()=>{return false}"
+                            placeholder="请确认新密码">
+                        </el-input>
+                    </el-form-item>
+                </el-form>
+                <el-button class="submit_btn" @click="handleResetPass">{{checkPassStr}}</el-button>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import CaptchaInput from './components/CaptchaInput.vue';
+import ModelSteps from './components/ModelSteps.vue';
+import VerificationBox from './components/VerificationBox.vue';
+import modelMixins from './modelMixins';
+import{checkPassWord} from '@/utils/commonOptions';
+import http from '@/api/http.js';
+import {departInterence } from "@/api/api.js";
+export default {
+    mixins:[modelMixins],
+    props:{
+        autoAccount:{//自动填写的账号,如果有,作为form.accout的初始值
+            type:String,
+            default:''
+        },
+        isMobile:{
+            type:Boolean,
+            default:false
+        }
+    },
+    components: { VerificationBox, ModelSteps, CaptchaInput },
+    data() {
+        const validatePass = (rule,value,callback)=>{
+            if(value===''){
+                callback(new Error('请输入新密码'))
+            }
+            if(this.passForm.pass2!==''){
+                this.$refs.passForm.validateField('pass2')
+            }
+            if(!checkPassWord(value)){
+                callback(new Error('密码要求8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型'))
+            }else{
+                callback()
+            }
+        }
+        const validateCheck = (rule,value,callback)=>{
+            if(value===''){
+                callback(new Error('请输入确认密码'))
+            }else if(value!==this.passForm.pass1){
+                callback(new Error('两次输入的密码不一致,请检查'))
+            }else{
+                callback()
+            }
+        }
+        return {
+            currentStep:0,
+            /* form */
+            form:{//步骤0的表单
+                account:this.autoAccount,
+                picCode:''
+            },
+            picSrc:'',
+            picId:'',
+            passForm:{//设置新密码的表单
+                pass1:'',
+                pass2:''
+            },
+            /* form rule */
+            rules:{},
+            passRules:{
+                pass1:[{validator: validatePass,trigger: 'blur'}],
+                pass2:[{validator: validateCheck,trigger: 'blur'}]
+            },
+            /*user info */
+            userMobile:'',//用户的手机号
+            TelAreaCode:'',//用户手机号的区号
+            userEmail:'',//用户的邮箱
+            /* check way */
+            checkWay:'',//选择的验证方式
+            authCode:'',//手机/邮箱验证码,从CaptchaInput组件中取
+            mobileCountDown:0,//手机获取验证码倒计时
+            emailCountDown:0,//邮箱验证码倒计时
+            checkPassStr:'确定',//重置密码按钮
+            countDownNum:5,
+            resetPassTimer:0,
+            choosedWay:'mobile',
+        };
+    },
+    computed:{
+        forgetPassTextMobile(){
+            switch (this.currentStep) {
+                case 0:
+                    return "忘记密码"
+                case 1:
+                    return "安全验证"
+                case 2:
+                    return "请输入验证码"
+                case 3:
+                    return "设置密码"
+                default:
+                    break;
+            }
+        }
+    },
+    created(){
+        this.getCodePic()
+    },
+    methods: {
+        //获取用户账号信息
+        getUserInfo(){
+            //检查form是否填写完整
+            const {account,picCode} = this.form
+            if(!account){
+                this.$message.warning('请输入账号')
+                return
+            }
+            if(!picCode){
+                this.$message.warning('请输入图形验证码')
+                return
+            }
+            //请求接口获取账号数据,赋值userMobile,userEmail
+            departInterence.accountCheck({
+                CaptchaId:this.picId,
+                CaptchaCode:picCode,
+                UserName:account
+            }).then(res=>{
+                if(res.Ret!==200){
+                    //刷新图形验证码
+                    this.getCodePic()
+                    this.form.picCode=''
+                    return
+                }
+                if(res.Data){
+                    this.userMobile = res.Data.Mobile||''
+                    this.userEmail = res.Data.Email||''
+                    this.TelAreaCode = res.Data.TelAreaCode||''
+                    this.goSteps()
+                }
+                
+            })
+        },
+        //获取对应验证方式的验证码
+        getCode(way){
+            this.checkWay = way
+            departInterence.getCodeVerify({
+                VerifyType:way==='mobile'?1:2,
+                CaptchaId:this.picId,
+                CaptchaCode:this.form.picCode,
+                Mobile:way==='mobile'?this.userMobile:'',
+                TelAreaCode:way==='mobile'?this.TelAreaCode:'',
+                Email:way==='email'?this.userEmail:'',
+                Source:3
+            }).then(res=>{
+                if(res.Ret!==200) return
+                /* //60秒倒计时
+                this.countDown()
+                this.timer = setInterval(()=>{
+                    this.countDown()
+                },1000)
+                this.goSteps() */
+                this.goSteps()
+            })
+        },
+        //检查输入的验证码
+        checkInput(){
+            const code = this.$refs.captInput.captchas.map((x) => x.num).join("");
+            if(code.length!==6){
+                this.$message.warning('请输入完整的验证码')
+                return
+            }
+            departInterence.checkCodeVerify({
+                FindType:this.checkWay==='mobile'?1:2,
+                VerifyCode:code,
+                UserName:this.form.account,
+                Mobile:this.checkWay==='mobile'?this.userMobile:'',
+                Email:this.checkWay==='email'?this.userEmail:''
+            }).then(res=>{
+                if(res.Ret!==200) return
+                this.goSteps()
+            })
+
+        },
+        goSteps(){
+            this.currentStep++
+        },
+        changeModel(){
+            if(this.currentStep>0){
+                this.currentStep--
+                if(this.currentStep===0){
+                    this.getCodePic()
+                    this.form.picCode = ''
+                }
+            }else{
+                this.$emit('changeModel')
+            }
+            
+        },
+        handleResetPass(){
+            if(this.checkPassStr.includes('去登陆')){
+                this.$emit('changeModel')
+                return
+            }
+            this.$refs.passForm.validate((valid)=>{
+                if(valid){
+                    //重置密码
+                    departInterence.resetPass({
+                        UserName:this.form.account,
+                        Password:new http.Base64().encode(this.passForm.pass1),
+                        RePassword:new http.Base64().encode(this.passForm.pass2)
+                    }).then(res=>{
+                        if(res.Ret!==200) return
+                        this.$message.success('重置密码成功,请登陆')
+                        this.resetPassCountDown()
+                        this.resetPassTimer = setInterval(()=>{
+                            this.resetPassCountDown()
+                        },1000)
+                    })
+                }
+            })
+        },
+        resetPassCountDown(){
+            this.countDownNum--
+            this.checkPassStr = `去登陆(${this.countDownNum}s)`
+            if(this.countDownNum<=0){
+                clearInterval(this.resetPassTimer)
+                this.$emit('changeModel')
+                return
+            }
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+@import "./css/formStyle.scss";
+</style>
+<style scoped lang="scss">
+.forget-pass-model{
+    .header-nav{
+        font-size: 38px;
+        margin-bottom: 60px;
+        cursor: pointer;
+    }
+    .step-container{
+        .container-header{
+            margin-bottom: 60px;
+            p{
+               font-size: 18px;
+               padding-bottom: 20px;
+               border-bottom: 1px solid #DCDFE6; 
+               margin-bottom: 60px;
+            }
+            .el-steps{
+                margin-top: 60px;
+            }
+        }
+        .container-inner{
+            .btn-wrap{
+                margin-top: 100px;
+                text-align: center;
+                .el-button{
+                    width:200px;
+                }
+            }
+        }
+    }
+    .verification-item{
+        display: flex;
+        align-items: center;
+        width:100%;
+        box-sizing: border-box;
+        padding:10px 15px;
+        margin-bottom: 30px;
+        border: 1px solid #DCDFE6;
+        border-radius: 8px;
+        background-color: #fff;
+        &.active{
+            border: 1px solid #0052D9;
+            background-color: #F2F3FF;
+        }
+        &.disabled{
+            user-select: none;
+            pointer-events: none;
+        }
+        img{
+            width: 40px;
+            margin-right: 10px;
+        }
+    }
+    .verification-button{
+        width: 100%;
+        margin-top: 20px;
+    }
+    @media screen and (max-width:650px) {
+        .header-nav{
+            font-size: 24px;
+        }
+        .submit_btn{
+            border-radius: 50px;
+        }
+        .step-container{
+            .container-header{
+                display: none;
+            }
+            .container-inner{
+                .btn-wrap{
+                    .el-button{
+                        width:100%;
+                        margin-left: 0;
+                        border-radius: 42px;
+                        &:first-child{
+                            margin-bottom: 30px;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+</style>

+ 160 - 0
src/views/login_manage/MobileModel.vue

@@ -0,0 +1,160 @@
+<template>
+    <div class="mobile-model-wrap model-wrap">
+        <el-form 
+            ref="modelForm" 
+            label-position="right" 
+            label-width="0px"
+            :model="form"
+            :rules="rules">
+            <el-form-item prop="mobile">
+                <el-input
+                    class="input-with-slot"
+                    type="text"
+                    v-model="form.mobile"
+                    auto-complete="off"
+                    placeholder="请输入手机号"
+                >
+                    <el-select v-model="areaCodeSelect" slot="prepend" placeholder="请选择">
+                        <el-option v-for="item in areaCode" :key="item.Value"
+                            :label="item.Name" :value="item.Value" />
+                    </el-select>
+                </el-input>
+                <span class="inline-message el-form-item__error" 
+                    v-show="(mobileCheck||accountForbidden)&&form.mobile.length">
+                    {{hintMessage}}
+                </span>
+            </el-form-item>
+            <el-form-item prop="picCode">
+                <el-input
+                    class="input-with-slot"
+                    type="text"
+                    v-model="form.picCode"
+                    auto-complete="off"
+                    placeholder="请输入图形验证码"
+                >
+                    <div class="pic-box" slot="append" @click="getCodePic">
+                        <img :src="picSrc" alt="图形验证码"/>
+                    </div>
+                </el-input>
+            </el-form-item>
+            <el-form-item prop="checkCode" class="code-input">
+                <el-input
+                    type="text"
+                    v-model="form.checkCode"
+                    auto-complete="off"
+                    placeholder="请输入验证码">
+                </el-input>
+                <el-button type="text" class="code-btn" @click="checkForm" :disabled="codeCountDown<60&&codeCountDown>0">{{codeStr}}</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+
+<script>
+import modelMixins from './modelMixins';
+import {isMobileNo} from '@/utils/commonOptions'
+import {departInterence } from "@/api/api.js";
+export default {
+    mixins:[modelMixins],
+    props:{
+        mobileCheck:{
+            type:Boolean,
+            default:false
+        },
+        accountForbidden:{
+            type:Boolean,
+            default:false
+        },
+        areaCode:{
+            type:Array,
+            default:()=>{return []}
+        },
+        Source:{//请求验证码来源:1登陆
+            type:Number,
+            default:1
+        },
+        isMobile:{
+            type:Boolean,
+            default:false
+        },
+    },
+    data() {
+        return {
+            hasPicCode:true,//是否需要图形验证码
+            areaCodeSelect:'86',
+            picSrc:'',//图形验证码地址
+            picId:'',//图形验证码id
+            timer:0,
+            codeStr:'获取验证码',
+            codeCountDown:60,
+            form:{
+                mobile:'',
+                picCode:'',
+                checkCode:''
+            },
+            rules:{
+                mobile:[
+                    {required: true,message: "请输入手机号",trigger: "blur"},
+                    {validator:(rule,value,callback)=>{
+                        if(this.areaCodeSelect==='86'&&!isMobileNo(value)){
+                            callback(new Error('请输入正确的手机号格式'));
+                        }else if(this.areaCodeSelect!=='86'&&isNaN(value.trim())){
+                            callback(new Error('请输入正确的手机号格式'));
+                        }else{
+                            callback()
+                        }
+                    },trigger:'blur'}
+                ],
+                picCode:[{required:true,message:'请输入图形验证码',trigger:'blur'}],
+                checkCode:[{required:true,message:'请输入短信验证码',trigger:'blur'}]
+            }
+        };
+    },
+    methods: {
+        checkForm(){
+            //首先检查是否是重新获取验证码
+            if(this.codeStr==='重新获取'){
+                //引导用户重新输入图形验证码
+                this.getCodePic()
+                this.form.picCode = ''
+            }
+            //检查手机号和图形验证码是否正确
+            const {picCode,mobile} = this.form
+            if(!picCode.length){
+                this.$message.warning('请输入图形验证码')
+                return
+            }
+            if(this.areaCodeSelect==='86'&&!isMobileNo(mobile)){
+                this.$message.warning('请输入正确的手机号')
+                return
+            }
+            /* this.countDown()
+                this.timer = setInterval(()=>{
+                    this.countDown()
+                },1000) */
+            //通过请求发送验证码
+            departInterence.getCodeVerify({
+                VerifyType:1,
+                CaptchaId:this.picId,
+                CaptchaCode:picCode,
+                Mobile:mobile,
+                TelAreaCode:this.areaCodeSelect,
+                Source:this.Source
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.$message.success('验证码已发送')
+                //60秒倒计时
+                this.countDown()
+                this.timer = setInterval(()=>{
+                    this.countDown()
+                },1000)
+            })
+
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+@import "./css/formStyle.scss";
+</style>

+ 123 - 0
src/views/login_manage/OrdinaryModel.vue

@@ -0,0 +1,123 @@
+<template>
+    <div class="ordinary-model-wrap model-wrap">
+        <el-form 
+            ref="modelForm" 
+            label-position="right" 
+            label-width="0px"
+            :model="form"
+            :rules="rules">
+            <el-form-item prop="account">
+                <el-input
+                    type="text"
+                    v-model="form.account"
+                    auto-complete="off"
+                    placeholder="请输入用户名"
+                />
+                <span class="inline-message el-form-item__error" 
+                    v-show="(loginCheck||accountCheck)&&form.account.length">
+                    {{hintMessage}}
+                </span>
+            </el-form-item>
+            <el-form-item prop="checkPass">
+                <el-input
+                    type="password" :show-password="isMobile?false:true"
+                    v-model="form.checkPass"
+                    auto-complete="off"
+                    placeholder="请输入密码"
+                    @copy.native.capture.prevent="()=>{return false}"
+                    @cut.native.capture.prevent="()=>{return false}"
+                    @paste.native.capture.prevent="()=>{return false}"
+                >
+                    <span slot="append" @click="changeModel" v-if="isMobile">忘记密码?</span>
+                </el-input>
+                <span class="inline-message el-form-item__error" 
+                    v-show="(loginCheck||accountCheck)&&form.checkPass.length">
+                    {{hintMessage}}</span>
+            </el-form-item>
+            <el-form-item class="remember-cont" prop="checked">
+                <el-checkbox v-model="form.checked" class="remember">
+                    记住账号密码
+                    <el-tooltip effect="dark" content="有效期60天" placement="top">
+                        <span class="hint-text">
+                            <i class="el-icon-question"></i>
+                        </span>
+                    </el-tooltip>
+                </el-checkbox>
+                <el-button type="text" style="font-size: 16px;" @click="changeModel">忘记密码</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+
+<script>
+import modelMixins from './modelMixins';
+export default {
+    mixins:[modelMixins],
+    props:{
+        loginCheck:{
+            type:Boolean,
+            default:false
+        },
+        accountCheck:{
+            type:Boolean,
+            default:false
+        },
+        isMobile:{
+            type:Boolean,
+            default:false
+        },
+    },
+    data() {
+        const validateClearn = (rule,value,callBack)=>{
+            if(this.loginCheck||this.accountCheck){
+                this.$emit('clearnHint')
+            }
+            callBack()
+        }
+        return {
+            form:{
+                account:'',
+                checkPass:'',
+                checked:false
+            },
+            rules:{
+                account:[
+                    {required: true,message: "请输入账号",trigger: "blur"},
+                    {validator:validateClearn,trigger:['change']}
+                ],
+                checkPass:[
+                    {required: true,message: "请输入密码",trigger: "blur"},
+                    {validator:validateClearn,trigger:['change']}
+                ]
+            },
+            hintMessage:''
+        };
+    },
+    watch:{
+        loginCheck(newVal){
+            //显示/隐藏inline-message
+            if(newVal){
+                this.hintMessage="账号或密码错误"
+            }else{
+                this.hintMessage=''
+            }
+        },
+        accountCheck(newVal){
+            if(newVal){
+                this.hintMessage="账号异常,请通过验证登录"
+            }else{
+                this.hintMessage=''
+            }
+        }
+    },
+    methods: {
+        changeModel(){
+            this.$emit('changeModel')
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+@import "./css/formStyle.scss";
+</style>

+ 117 - 0
src/views/login_manage/components/CaptchaInput.vue

@@ -0,0 +1,117 @@
+<template>
+    <!-- 格子验证码输入组件 -->
+    <div class="row-center captcha_input_wrap">
+        <input
+            v-for="(item, index) in captchas"
+            :key="index"
+            v-model="item.num"
+            :id="'captcha' + index"
+            @input="inputFinash(index)"
+            @focus="adjust(index)"
+            @keydown="(e)=>{inputDirection(index,e)}"
+            class="captcha_input_box row-center"
+            :class="[index <= activeInput ? 'active' : '']"
+            type="tel"
+            maxlength="1"
+        />
+  </div>
+</template>
+  
+  <script>
+export default {
+  data() {
+    return {
+      // 当前输入框
+      activeInput: 0,
+      captchas: [
+        { num: "" },
+        { num: "" },
+        { num: "" },
+        { num: "" },
+        { num: "" },
+        { num: "" },
+      ],
+    };
+  },
+  //   页面加载后聚焦第一个
+  mounted() {
+    let dom = document.getElementById("captcha" + this.activeInput);
+    dom.focus();
+  },
+ 
+  methods: {
+    // 自动校准输入顺序
+    adjust(index) {
+      let dom = document.getElementById("captcha" + this.activeInput);
+      if (index !== this.activeInput && dom) {
+        dom.focus();
+      }
+    },
+    // 控制前后方向
+    inputDirection(index,e) {
+      let val = this.captchas[index].num;
+      // 回退键处理
+      if (e.key==='Backspace' && val === "") {
+        // 重新校准
+        let dom = document.getElementById("captcha" + (index - 1));
+        this.activeInput = index - 1;
+        if (dom) dom.focus();
+      }
+      if (e.key!=='Backspace' && val !== "") {
+        let dom = document.getElementById("captcha" + (index + 1));
+        this.activeInput = index + 1;
+        if (dom) dom.focus();
+      }
+    },
+    // 输入框相互联动
+    inputFinash(index) {
+      let val = this.captchas[index].num;
+      this.activeInput = val ? index + 1 : index - 1;
+      let dom = document.getElementById("captcha" + this.activeInput);
+      if (dom) dom.focus();
+      if (index == this.captchas.length - 1) {
+        let code = this.captchas.map((x) => x.num).join("");
+        if (code.length == 6) {
+          this.$emit("finish", code);
+        }
+      }
+    },
+  },
+};
+</script>
+  
+<style scoped lang='scss'>
+.row-center {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    gap:40px;
+}
+.captcha_input_wrap {
+    width: 100%;
+}
+.captcha_input_box {
+    width: 40px;
+    height: 40px;
+    background: rgba(255, 255, 255, 1);
+    border-radius: 6px;
+    border: 1px solid #dddddd;
+    font-size: 16px;
+    text-align: center;
+    color: #1e243a;
+    outline: none;
+}
+.active {
+    border: 1px solid #3654C1 !important;
+}
+
+@media screen and (max-width:650px) {
+  .row-center {
+    gap:10px;
+  }
+  .captcha_input_box{
+    box-sizing: border-box;
+  }
+}
+</style>

+ 99 - 0
src/views/login_manage/components/ModelSteps.vue

@@ -0,0 +1,99 @@
+<template>
+    <ul class="model-step-wrap">
+        <li v-for="(step,index) in stepList" :key="step.text"
+            class="step-item"
+            :class="{'active':index+1===activeStep,'success':index+1<activeStep}"
+        >   
+            <div class="step-line"></div>
+            <div class="step-num" v-if="index+1>=activeStep">{{index+1}}</div>
+            <div class="step-num" v-else><i class="el-icon-check"></i></div>
+            <div class="step-text">{{step.text}}</div>
+            
+        </li>
+    </ul>
+</template>
+
+<script>
+export default {
+    props:{
+        stepList:{
+            type:Array,
+            default:()=>{
+                return [
+                    {text:'选择验证方式'},
+                    {text:'进行安全验证'},
+                    {text:'设置密码'}
+                ]
+            }
+        },
+        activeStep:{
+            type:Number,
+            default:1
+        }
+    },
+    data() {
+        return {
+
+        };
+    },
+    methods: {
+
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.model-step-wrap{
+    display: flex;
+    justify-content: center;
+    width: 100%;
+    .step-item{
+        display: flex;
+        align-items: center;
+        gap: 12px;
+        color: #DCDCDC;
+        font-size: 20px;
+        &:first-child{
+            .step-line{
+                display: none;
+            }
+        }
+        &:last-child{
+            .step-text{
+                margin-right: 0;
+            }
+        }
+        &.active,&.success{
+            color:#3654C1;
+            .step-num{
+                border-color: #3654C1;
+                color: #3654C1;
+            }
+            .step-line{
+                background-color: #3654C1;
+            }
+        }
+        &.success{
+            color: #000;
+        }
+        .step-num{
+            width:24px;
+            height:24px;
+            font-size: 16px;
+            border:1px solid #DCDCDC;
+            border-radius: 50%;
+            text-align: center;
+            line-height: 25px;
+        }
+        .step-line{
+           flex: 1;
+           height:2px;
+           background-color:#DCDCDC ;
+           min-width: 40px;
+        }
+        .step-text{
+            margin-right: 16px;
+        }
+    }
+}
+</style>

+ 79 - 0
src/views/login_manage/components/VerificationBox.vue

@@ -0,0 +1,79 @@
+<template>
+    <div class="verification-box-wrap">
+        <div class="icon">
+            <img :src="verifiesType==='mobile'?mobile_src:email_src" />
+        </div>
+        <div class="text">{{infoText}}</div>
+        <el-button  type="primary" @click="goNext" v-if="!hideBtn" :disabled="countDown">{{countDown?`重发(${countDown}秒)`:btnText}}</el-button>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        verifiesType:{//安全验证 mobile or email
+            type:String,
+            default:'mobile'
+        },
+        infoText:{//手机号或邮箱
+            type:String,
+            default:'123456'
+        },
+        hideBtn:{
+            type:Boolean,
+            default:false
+        },
+        countDown:{
+            type:Number,
+            default:0
+        },
+        btnText:{
+            type:String,
+            default:'开始验证'
+        }
+    },
+    data() {
+        return {
+            mobile_src:require('@/assets/img/home/phone_icon.png'),
+            email_src:require('@/assets/img/home/email_icon.png'),
+        };
+    },
+    methods: {
+        goNext(){
+            this.$emit('goNext',this.verifiesType)
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.verification-box-wrap{
+    display: flex;
+    align-items: center;
+    margin-bottom: 60px;
+    cursor: pointer;
+    .icon{
+        width:40px;
+        height:40px;
+        box-sizing: border-box;
+        padding:8px;
+        border-radius: 50%;
+        box-shadow: 0px 2px 12px 0px #0000001A;
+        text-align: center;
+        img{
+            width: 24px;
+            height: 24px;
+        }
+    }
+    .text{
+        margin-left: 20px;
+        font-size: 18px;
+    }
+    .el-button{
+        /* background-color: #3654C1;
+        color: #fff; */
+        margin-left: auto;
+    }
+}
+
+</style>

+ 155 - 0
src/views/login_manage/css/formStyle.scss

@@ -0,0 +1,155 @@
+.model-wrap{
+    margin-top: 25px;
+    .remember-cont{
+        margin-top: -10px;
+        margin-bottom: 60px !important;
+        width: 100%;
+        .hint-text{
+            color: #606266 !important;
+            font-size: 16px;
+        }
+        .el-form-item__content{
+            display: flex;
+            width: 100%;
+            justify-content: space-between;
+            .remember{
+                flex: 1;
+                .el-checkbox__label{
+                    font-size: 16px;
+                }
+            }
+        }
+    }
+    .el-form-item{
+        margin-bottom: 40px;
+        .el-input__inner{
+            height: 50px;
+            border-radius: 8px;
+            font-size: 16px;
+        }
+    }
+    .el-form-item.is-error{
+        .inline-message{
+            display: none;
+        }
+    }
+    .input-with-slot{
+        display: flex;
+        &.el-input-group--prepend{
+            .el-input__inner{
+                border-top-left-radius: 0;
+                border-bottom-left-radius: 0;
+            }
+        }
+        &.el-input-group--append{
+            .el-input__inner{
+                border-top-right-radius: 0;
+                border-bottom-right-radius: 0;
+            }
+        }
+        .el-input__inner{
+            flex: 1;
+            height: 50px !important;
+        }
+        .el-input-group__prepend,.el-input-group__append{
+            padding:0 !important;
+            background-color: #fff;
+            width:110px;
+            height: 50px;
+            box-sizing: border-box;
+            overflow: hidden;
+            .el-input__inner{
+                padding:0;
+            }
+            .el-select{
+                margin:0;
+                width:110px;
+                .el-input__inner{
+                    width:100%;
+                    text-align: center;
+                }
+            }
+        }    
+        .pic-box{
+            cursor: pointer;
+            width:110px;
+            height:50px;
+            overflow: hidden;
+            padding:5px;
+            box-sizing: border-box;
+            background-color: #D7F1F6;
+            img{
+                width: 100%;
+                height: 100%;
+            }
+        }
+        .code{
+            display: inline-block;
+            width:100%;
+            text-align: center;
+            line-height: 40px;
+            cursor: pointer;
+        }
+    }
+    .submit_btn {
+        width: 100%;
+        height: 50px;
+        background: #007eff;
+        font-size: 20px;
+        border-radius: 5px;
+        color: #fff;
+    }
+    .code-input{
+        position:relative;
+        .code-btn{
+            position:absolute;
+            top:5px;
+            right: 20px;
+            font-size: 16px;
+        }
+    }
+}
+
+@media screen and (max-width:650px) {
+    .model-wrap{
+        margin-top: 60px;
+        .el-form-item{
+            margin-bottom: 40px;
+            .el-input{
+                .el-input-group__prepend{
+                    border: none;
+                    border-radius: 0;
+                    border-bottom:solid 1px #DCDFE6;
+                    width: 70px;
+                    .el-input--suffix{
+                        width: 40px;
+                        .el-input__suffix{
+                            display: none;
+                        }
+                    }
+                }
+                .el-input__inner{
+                    border-radius: 0;
+                    border: none;
+                    border-bottom:solid 1px #DCDFE6;
+                    padding-left: 0;
+                }
+                .el-input-group__append{
+                    background-color: transparent;
+                    border: none;
+                    border-radius: 0;
+                    border-bottom:solid 1px #DCDFE6;
+                    padding: 0;
+                    span{
+                        color:#257EFF ;
+                        font-size: 14px;
+                    }
+                }
+            }
+
+        }
+        .remember-cont{
+            display: none;
+        }
+    }
+}

+ 34 - 0
src/views/login_manage/modelMixins.js

@@ -0,0 +1,34 @@
+import {departInterence } from "@/api/api.js";
+export default {
+    methods:{
+        modelInit(){
+            //重置表单
+            this.form = this.$options.data().form
+            //如果有图形验证码,重新请求
+            this.hasPicCode && this.getCodePic()
+        },
+        //获取图片验证码
+        getCodePic(){
+            //存base64和id
+            departInterence.getCodePic().then(res=>{
+                if(res.Ret!==200) return 
+                if(res.Data){
+                    this.picSrc = res.Data.Base64Blob,
+                    this.picId = res.Data.Id
+                }
+                
+            })
+        },
+        countDown(){
+            /* if(!this.timer) return */
+            console.log('click down')
+            this.codeCountDown--
+            this.codeStr=`重新获取(${this.codeCountDown})秒`
+            if(this.codeCountDown<=0){
+                clearInterval(this.timer)
+                this.codeStr = '重新获取'
+                return
+            }
+        }
+    }
+}

+ 70 - 52
src/views/rai_manage/activityManage/activityManage.vue

@@ -5,16 +5,13 @@
     <el-card style="margin-bottom: 20px">
       <div class="top-card-box">
         <div class="tabs-box">
-          <span
-            v-for="(item, index) in listTitle"
-            :key="item.ChartPermissionId"
-            @click="tabsBoxBtn(item, index)"
-            :class="index == tabsPitchon ? 'pitch' : ''"
-            >{{ item.PermissionName }}</span
-          >
+          <span v-for="(item, index) in listTitle" :key="item.ChartPermissionId" @click="tabsBoxBtn(item, index)" :class="index == tabsPitchon ? 'pitch' : ''">{{ item.PermissionName }}</span>
         </div>
-        <div>
-          <el-button type="primary" @click="$router.push('/addActivity')">添加活动</el-button>
+        <div style="display: flex">
+          <el-upload ref="imgUpload" action="#" :http-request="handleUploadImg" :show-file-list="false" accept="image/*">
+            <el-button type="primary">识图建会</el-button>
+          </el-upload>
+          <el-button style="margin-left: 20px" type="primary" @click="$router.push(!isResearch ? '/addActivity' : '/addPurchaserActivity')">添加活动</el-button>
         </div>
       </div>
     </el-card>
@@ -23,45 +20,18 @@
       <!-- 选择部分 -->
       <div class="screen-box">
         <div>
-          <el-select placeholder="行业" clearable v-model="industry" @change="conditionChange" style="margin-bottom: 20px">
-            <el-option
-              v-for="item in chartPermissionList"
-              :label="item.PermissionName"
-              :key="item.ChartPermissionId"
-              :value="item.ChartPermissionId"
-            ></el-option>
+          <el-select placeholder="行业" clearable v-model="industry" @change="conditionChange" style="margin-bottom: 20px" v-if="!isResearch">
+            <el-option v-for="item in chartPermissionList" :label="item.PermissionName" :key="item.ChartPermissionId" :value="item.ChartPermissionId"></el-option>
           </el-select>
           <el-select placeholder="活动类型" clearable v-model="cactivityTypeVal" @change="conditionChange">
-            <el-option
-              v-for="item in cactivityTypeList"
-              :label="item.ActivityTypeName"
-              :key="item.ActivityTypeId"
-              :value="item.ActivityTypeId"
-            ></el-option>
+            <el-option v-for="item in cactivityTypeList" :label="item.ActivityTypeName" :key="item.ActivityTypeId" :value="item.ActivityTypeId"></el-option>
           </el-select>
-          <el-date-picker
-            v-model="publishDate"
-            type="date"
-            placeholder="发布时间"
-            format="yyyy 年 MM 月 dd 日"
-            value-format="yyyy-MM-dd"
-            @change="conditionChange"
-          >
-          </el-date-picker>
-          <date-picker
-            style="margin-bottom: 20px"
-            v-model="issueTime"
-            type="date"
-            range
-            placeholder="活动时间"
-            value-type="format"
-            @change="conditionChange"
-          >
-          </date-picker>
+          <el-date-picker v-model="publishDate" type="date" placeholder="发布时间" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd" @change="conditionChange"> </el-date-picker>
+          <date-picker style="margin-bottom: 20px" v-model="issueTime" type="date" range placeholder="活动时间" value-type="format" @change="conditionChange"> </date-picker>
           <el-select placeholder="发布状态" clearable v-model="status" @change="conditionChange" style="margin-bottom: 20px">
             <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id"></el-option>
           </el-select>
-          <el-input v-model="activityLabel" @input="titleInput" placeholder="请输入活动标签" clearable style="display: inline-block; width: 220px">
+          <el-input v-model="activityLabel" @input="titleInput" placeholder="请输入活动标签" clearable style="display: inline-block; width: 220px; margin-bottom: 20px">
             <i slot="prefix" class="el-input__icon el-icon-search"></i>
           </el-input>
         </div>
@@ -94,13 +64,13 @@
         <el-table-column align="center" width="146" label="操作">
           <template slot-scope="{ row }">
             <span v-if="row.PublishStatus == 0 && tabsPitchon == 0" class="editsty" @click="operationBtn(row.ActivityId, '发布')">发布</span>
-            <span v-if="row.PublishStatus == 3 && tabsPitchon == 0" class="editsty" @click="operationBtn(row.ActivityId, '重新发布')">重新发布</span>
-            <span v-if="row.PublishStatus == 1 && tabsPitchon == 0" class="editsty" @click="operationBtn(row.ActivityId, '取消发布')">取消发布</span>
+            <span v-if="row.PublishStatus == 3" class="editsty" @click="operationBtn(row.ActivityId, '重新发布')">重新发布</span>
+            <span v-if="row.PublishStatus == 1" class="editsty" @click="operationBtn(row.ActivityId, '取消发布')">取消发布</span>
             &nbsp;&nbsp;
             <span class="editsty" @click="editBtn(row.ActivityId, row.PublishStatus)">编辑</span>
             &nbsp;&nbsp;
             <span class="deletesty" v-if="row.PublishStatus == 0 && tabsPitchon == 0" @click="operationBtn(row.ActivityId, '删除')">删除</span>
-            <span class="editsty" v-if="row.IsShowSigninButton " @click="handleDownLoadImg(row)">下载签到码</span>
+            <span class="editsty" v-if="row.IsShowSigninButton" @click="handleDownLoadImg(row)">下载签到码</span>
           </template>
         </el-table-column>
       </el-table>
@@ -110,17 +80,28 @@
       </el-col>
     </el-card>
     <atc-particulars :dialogVisible.sync="dialogVisible" :detailData.sync="detailData" />
+    <imgMeeting :isShowImgMeetingDlg.sync="isShowImgMeetingDlg" :imgMeetingData.sync="imgMeetingData" @childrenImgMeetingHandler="childrenImgMeetingHandler" />
   </div>
 </template>
 
 <script>
+import * as OpenCC from "opencc-js";
+// 将繁体中文(香港)转换为简体中文(中国大陆)
+const converter = OpenCC.Converter({ from: "hk", to: "cn" });
 import mPage from "@/components/mPage.vue";
-import { raiInterface } from "@/api/api.js";
+import { raiInterface, sealInterence } from "@/api/api.js";
 import AtcParticulars from "../components/atcParticulars.vue";
+import imgMeeting from "./components/imgMeeting.vue";
 export default {
   name: "",
-  components: { mPage, AtcParticulars },
-  props: {},
+  components: { mPage, AtcParticulars, imgMeeting },
+  props: {
+    Type: {
+      type: String,
+      emnu: ["hongze", "purchaser"], // 弘则,研选
+      default: "hongze",
+    },
+  },
   data() {
     return {
       listTitle: [
@@ -159,12 +140,19 @@ export default {
       detailData: {}, //
       activityLabel: "",
       publishDate: "",
+      baseApi: process.env.API_ROOT,
+      isShowImgMeetingDlg: false,
+      imgMeetingData: [],
     };
   },
   computed: {
     sta() {
       return this.status >= 0 && typeof this.status == "number" ? this.status : 2;
     },
+    // 弘则 研选 是否是研选
+    isResearch() {
+      return this.$route.path.indexOf("purchaser") != -1 ? true : false;
+    },
   },
   created() {},
   mounted() {
@@ -180,7 +168,8 @@ export default {
       this.activityLabel = initialize.activityLabel;
       this.publishDate = initialize.publishDate;
     }
-    this.chartPermission();
+    // 研选下 没有行业的搜索框
+    !this.isResearch && this.chartPermission();
     this.activityType();
     this.getsummaryManageList();
   },
@@ -247,7 +236,7 @@ export default {
     //编辑
     editBtn(id, show) {
       this.$router.push({
-        path: "/editActivity",
+        path: !this.isResearch ? "/editActivity" : "/editPurchaserActivity",
         query: {
           id: id,
           isShow: show,
@@ -261,7 +250,7 @@ export default {
     },
     //获取行业
     chartPermission() {
-      raiInterface.chartPermission().then((res) => {
+      raiInterface.chartPermission({ IsHideResearch: !this.isResearch }).then((res) => {
         if (res.Ret === 200) {
           this.chartPermissionList = res.Data.List;
         }
@@ -269,7 +258,7 @@ export default {
     },
     //活动类型
     activityType() {
-      raiInterface.getActivityType().then((res) => {
+      raiInterface.getActivityType({ IsResearch: this.isResearch }).then((res) => {
         if (res.Ret === 200) {
           this.cactivityTypeList = res.Data.List;
         }
@@ -290,6 +279,7 @@ export default {
           ActiveState: this.activeStateId,
           ActivityLabel: this.activityLabel,
           PublishStartDate: this.publishDate,
+          IsResearch: this.isResearch,
         })
         .then((res) => {
           if (res.Ret !== 200) return;
@@ -331,6 +321,34 @@ export default {
         a.click();
       };
     },
+    async handleUploadImg(params) {
+      if (!params.file) return;
+      const fd = new FormData();
+      fd.append("file", params.file);
+      try {
+        const res = await sealInterence.resourceUpload(fd);
+        if (res.Ret === 200) {
+          const resImg = await raiInterface.activityImgToText({
+            ImgUrl: res.Data.ResourceUrl,
+          });
+          if (resImg.Ret === 200) {
+            this.isShowImgMeetingDlg = true;
+            this.imgMeetingData = resImg.Data.List.map((item) => {
+              return {
+                ...item,
+                Company: converter(item.Company),
+              };
+            });
+          }
+        }
+      } catch (err) {
+        console.log(err);
+      }
+    },
+    // 点击取消的回调事件
+    childrenImgMeetingHandler() {
+      this.$refs.imgUpload.clearFiles();
+    },
   },
   /* 页面跳转前记录参数 */
   beforeRouteLeave(to, form, next) {

+ 20 - 9
src/views/rai_manage/activityManage/applyManage.vue

@@ -37,8 +37,14 @@
           <el-button type="primary" @click="sendMessage">发送模板消息</el-button>
         </div>
         <div>
-          <el-select placeholder="行业" clearable v-model="industry" @change="conditionChange" style="margin-bottom: 20px">
-            <el-option v-for="item in chartPermissionList" :label="item.PermissionName" :key="item.ChartPermissionId" :value="item.ChartPermissionId"></el-option>
+          <el-select placeholder="行业" clearable v-model="industry" @change="conditionChange" style="margin-bottom: 20px"
+          v-if="!isResearch">
+            <el-option
+              v-for="item in chartPermissionList"
+              :label="item.PermissionName"
+              :key="item.ChartPermissionId"
+              :value="item.ChartPermissionId"
+            ></el-option>
           </el-select>
           <el-select placeholder="活动类型" clearable @focus="activityType" v-model="cactivityTypeVal" @change="conditionChange" style="margin-bottom: 20px">
             <el-option v-for="item in cactivityTypeList" :label="item.ActivityTypeName" :key="item.ActivityTypeId" :value="item.ActivityTypeId"></el-option>
@@ -112,7 +118,7 @@ import ParticularsDialog from "../components/apply/particularsDialog.vue";
 import AtcParticulars from "../components/atcParticulars.vue";
 import GenerationAsk from "../components/generationAsk.vue";
 import SummaryRemind from "../components/apply/summaryRemind.vue";
-import { ListTitle, TableApplyColums, StatusSelect, PublishSelect } from "../components/apply/applyTableColums";
+import { ListTitle , purchaserListTitle , TableApplyColums, StatusSelect, PublishSelect } from "../components/apply/applyTableColums";
 import TemplateMessage from "../components/apply/templateMessage.vue";
 export default {
   name: "",
@@ -159,8 +165,12 @@ export default {
     };
   },
   computed: {
+    // 弘则 研选 是否是研选
+    isResearch(){
+      return this.$route.path.indexOf("purchaser")!=-1?true:false
+    },
     listTitle() {
-      return ListTitle;
+      return !this.isResearch?ListTitle:purchaserListTitle;
     },
     statusSelect() {
       return StatusSelect;
@@ -177,12 +187,12 @@ export default {
       this.page_no = 1;
       this.init();
       this.getsDataList();
-    },
+    }
   },
   created() {},
   mounted() {
     this.tableApplyColums = TableApplyColums(1);
-    this.chartPermission();
+    !this.isResearch && this.chartPermission();
     this.getsDataList();
   },
   methods: {
@@ -197,7 +207,7 @@ export default {
       this.tableApplyColums = TableApplyColums(item.ChartPermissionId);
       this.cactivityTypeVal = "";
       this.isResearchPoints = false;
-      this.tabsSelectionOne = item.ChartPermissionId == 2 ? false : true;
+      this.tabsSelectionOne = item.ChartPermissionId == 2 || item.ChartPermissionId == 5 ? false : true;
       this.page_no = 1;
       this.getsDataList();
     },
@@ -215,6 +225,7 @@ export default {
           ActivityTypeId: this.cactivityTypeVal,
           ActiveState: this.cactivityStatus,
           PublishStatus: this.publishStatus ? Number(this.publishStatus) : 2,
+          IsResearch:this.isResearch
         })
         .then((res) => {
           if (res.Ret !== 200) return;
@@ -304,7 +315,7 @@ export default {
     },
     //获取行业
     chartPermission() {
-      raiInterface.chartPermission().then((res) => {
+      raiInterface.chartPermission({IsHideResearch:!this.isResearch}).then((res) => {
         if (res.Ret === 200) {
           this.chartPermissionList = res.Data.List;
         }
@@ -392,7 +403,7 @@ export default {
         let status = row[key] == 1 ? "未开始" : row[key] == 2 ? "进行中" : "已结束";
         return status;
       } else if (key == "PublishStatus") {
-        let status = row["PublishStatus"] == 1 ? "已发布" : "未发布";
+        let status = row["PublishStatus"] == 1 ? "已发布" : row["PublishStatus"] == 2 ?"未发布":"已取消";
         return status;
       } else {
         return row[key];

+ 86 - 7
src/views/rai_manage/activityManage/components/addActivity.vue

@@ -11,6 +11,7 @@
             clearable
             v-model="optionFormregion"
             style="width: 360px; margin-right: 30px"
+            v-if="!isResearch"
           >
             <el-option v-for="item in chartPermissionList" :label="item.PermissionName" :key="item.PermissionName" :value="item.PermissionName"></el-option>
           </el-select>
@@ -75,7 +76,7 @@
         </div>
         <!-- 复选 模块 -->
         <div style="margin-top: 20px">
-          <research-deduct ref="researchSelect" :cactivityType="cactivityType" :optionFormregion="optionFormregion" />
+          <research-deduct ref="researchSelect" :cactivityType="cactivityType" :optionFormregion="optionFormregion" :isResearch="isResearch" />
         </div>
         <div style="margin: 20px 0 0 98px" class="add-delete" v-for="(item, index) in addSubjectLabel" :key="index">
           <template v-if="subjectRadio == 2">
@@ -207,6 +208,13 @@
           </el-upload>
           <el-progress type="circle" :percentage="percentage" width="40" style="margin-left: 10px" v-if="startUpload"></el-progress>
         </div>
+        <div class="audio-content cover-content" style="margin-top: 10px" v-if="(fileListAudio.length || addEditVideo.length) && defaultImage">
+          <span class="text" style="width: 70px; text-align: right">封面:</span>
+          <div class="img-content">
+            <img :src="defaultImage" alt="" />
+            <div class="modify" @click="modifyImgHandler">修改</div>
+          </div>
+        </div>
       </template>
       <div style="text-align: center; margin-top: 30px">
         <el-button type="primary" @click="submitForm('保存')">保存</el-button>
@@ -262,6 +270,7 @@
       </template>
       <p style="padding-bottom: 50px"></p>
     </el-dialog>
+    <modify-img-dlg :modifyImgVisible.sync="modifyImgVisible" :videoAndVoiceList.sync="videoAndVoiceList" />
   </div>
 </template>
 
@@ -273,10 +282,11 @@ import AddIndustryMark from "../../components/addIndustryMark.vue";
 import richTextMixins from "../../components/apply/RichTextMixins";
 import MD5 from "js-md5";
 import ResearchDeduct from "./addComopnents/ResearchDeduct.vue";
+import ModifyImgDlg from "./addComopnents/modifyImgDlg.vue";
 
 export default {
   name: "",
-  components: { AddIndustryMark, ResearchDeduct },
+  components: { AddIndustryMark, ResearchDeduct, ModifyImgDlg },
   props: {},
   data() {
     return {
@@ -343,9 +353,18 @@ export default {
       startUpload: false, //开始上传
       percentage: 0,
       isShowAddIcon: true, //主题标签的添加的iocn 是否显示
+      modifyImgVisible: false,
+      defaultImage: "",
+      shareImg:'',
+      videoAndVoiceList: [],
     };
   },
-  computed: {},
+  computed: {
+    // 弘则 研选 是否是研选
+    isResearch(){
+      return this.$route.path.indexOf("Purchaser")!=-1?true:false
+    }
+  },
   mixins: [richTextMixins],
   watch: {
     radio: {
@@ -374,10 +393,20 @@ export default {
         this.isCheckAllType(newval === 4 ? true : false);
       },
     },
+    '$route.path':{
+      handler(value){
+        console.log(value,'value');
+      },
+      immediate:true
+    }
   },
   created() {},
   mounted() {
-    this.chartPermission();
+    if(!this.isResearch){
+      this.chartPermission();
+    }else{
+      this.optionFormregion="买方研选"
+    }
     this.getActivityType();
     this.customerTypelist();
     this.getIndustry();
@@ -392,6 +421,7 @@ export default {
     }
   },
   methods: {
+    // 上传音频
     async handleUploadAudio(e) {
       const loading = this.$loading({
         lock: true,
@@ -403,6 +433,7 @@ export default {
       form.append("file", e.file);
       const res = await resourceVoiceupload(form);
       if (res.Ret === 200) {
+        this.getVideoAndImg(1);
         let obj = {
           name: res.Data.ResourceName,
           url: res.Data.ResourceUrl,
@@ -476,6 +507,8 @@ export default {
       raiInterface.activityDetail({ ActivityId: Number(this.$route.query.id) }).then((res) => {
         if (res.Ret !== 200) return;
         const { Data } = res;
+        this.defaultImage = Data.BackgroundImg
+        this.shareImg = Data.ShareImg
         this.activeIsState = Data.ActiveState;
         this.cactivityType = Data.ActivityTypeId;
         this.optionFormregion = Data.ChartPermissionName;
@@ -506,6 +539,7 @@ export default {
           RefPage.SiginupDeadline = Data.SiginupDeadline;
           RefPage.PointsSet = Data.PointsSet;
           RefPage.institutionName = Data.PointsSet.CompanyName;
+          RefPage.isShowHz = !!Data.IsShowHz
         });
         this.addEditVideo = Data.VideoDetail
           ? [Data.VideoDetail].map((item) => {
@@ -613,7 +647,7 @@ export default {
         Body: this.content,
         PermissionName: this.optionFormregion,
         CustomerTypeIds: this.checkedCitiesTwo,
-        IsAllCustomerType:this.checkAll?1:0,
+        IsAllCustomerType: this.checkAll ? 1 : 0,
         LimitPeopleNum: Number(this.astrict) || 0,
         IndustrialManagementIdS: arr.length ? arr.join(",") : "",
         IndustrialSubjectIdS: this.markValue.length ? this.markValue.join(",") : "",
@@ -633,6 +667,10 @@ export default {
         IsBClass: RefPage.isBClass ? 1 : 0,
         SiginupDeadline: RefPage.SiginupDeadline,
         PointsSet,
+        BackgroundImg:this.defaultImage,
+        ShareImg:this.shareImg,
+        IsResearch:this.optionFormregion.includes('研选')?true:false,
+        IsShowHz:RefPage.isShowHz?1:0
       });
 
       if (res.Ret !== 200) return;
@@ -641,7 +679,7 @@ export default {
     },
     //获取行业
     chartPermission() {
-      raiInterface.chartPermissionList().then((res) => {
+      raiInterface.chartPermissionList({IsHideResearch:!this.isResearch}).then((res) => {
         if (res.Ret === 200) {
           this.chartPermissionList = res.Data.List;
         }
@@ -649,7 +687,7 @@ export default {
     },
     //获取活动类型
     getActivityType() {
-      raiInterface.getActivityType().then((res) => {
+      raiInterface.getActivityType({IsResearch:this.isResearch}).then((res) => {
         if (res.Ret === 200) {
           this.isShowAddIcon = res.Data.IsShowAddIcon;
           this.cactivityTypeList = res.Data.List;
@@ -948,6 +986,7 @@ export default {
         const res = await ALOSSINS.multipartUpload(temName, file, { ...options });
         console.log("上传结果", res);
         if (res.res.status === 200) {
+          this.getVideoAndImg(2);
           let VideoUrl = "https://hzstatic.hzinsights.com/" + res.name;
           this.addEditVideo[0].url = VideoUrl;
           this.startUpload = false;
@@ -981,6 +1020,23 @@ export default {
         this.checkAll = false;
       }
     },
+    // 点击修改图片的弹框
+    modifyImgHandler() {
+      let type = this.addEditVideo.length > 0 ? 2 : 1;
+      this.getVideoAndImg(type, "修改");
+      this.modifyImgVisible = true;
+    },
+    // video_and_voiceImgActivityVideo()
+    async getVideoAndImg(type, isOne = "") {
+      const res = await raiInterface.video_and_voiceImgActivityVideo({
+        FileType: type,
+        ActivityId: Number(this.$route.query.id),
+      });
+      if (res.Ret === 200) {
+        isOne == "修改" ? "" : (this.defaultImage = res.Data.List[0].ImgUrl);
+        this.videoAndVoiceList = res.Data.List;
+      }
+    },
   },
 };
 </script>
@@ -1085,6 +1141,29 @@ export default {
       }
     }
   }
+  .cover-content {
+    align-items: stretch;
+    vertical-align: bottom;
+    .img-content {
+      position: relative;
+      height: 200px;
+      width: 200px;
+      border: 1px solid #ccc;
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+    .modify {
+      position: absolute;
+      bottom: 0;
+      right: -50px;
+      height: 20px;
+      cursor: pointer;
+      color: #409eff;
+    }
+  }
+
   .el-upload-list__item.is-success.focusing .el-icon-close-tip {
     display: none !important;
   }

+ 6 - 0
src/views/rai_manage/activityManage/components/addComopnents/ResearchDeduct.vue

@@ -6,6 +6,7 @@
         <i class="el-icon-info" />
       </el-tooltip>
     </el-checkbox>
+    <el-checkbox v-if="isResearch && [1,3,5].includes(cactivityType)" v-model="isShowHz"> 同时在弘则活动页展示 </el-checkbox>
     <el-checkbox v-if="cactivityType == 3" v-model="isExternalLabel"> 外部资源 </el-checkbox>
     <template v-if="cactivityType == 7 || cactivityType == 2">
       <el-checkbox v-model="isYidongConduct">
@@ -85,6 +86,10 @@ export default {
       type: String,
       default: "",
     },
+    isResearch: {
+      type:Boolean,
+      default: false,
+    },
   },
   data() {
     return {
@@ -109,6 +114,7 @@ export default {
         CancelDeadlineType: "", //截至报名时间
       },
       dataDeadlineSet: [],
+      isShowHz:false
     };
   },
   computed: {

+ 80 - 0
src/views/rai_manage/activityManage/components/addComopnents/modifyImgDlg.vue

@@ -0,0 +1,80 @@
+<template>
+  <div class="container">
+    <!-- 选择图片的弹框 -->
+    <el-dialog title="选择图片" :visible.sync="modifyImgVisible" width="80%" v-dialogDrag :close-on-click-modal="false" :modal-append-to-body="false" center>
+      <div class="seleect-img-box">
+        <div class="content-img" @click="clickSelectImg(item)" v-for="(item, index) in videoAndVoiceList" :key="index">
+          <img :src="item.ImgUrl" alt="" class="item-img" />
+        </div>
+      </div>
+      <!-- <el-col :span="24" class="toolbar">
+        <m-page :total="total" :page_no="page_no" :pageSize="10" @handleCurrentChange="handleCurrentChangeSelectImg" />
+      </el-col> -->
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { raiInterface } from "@/api/api.js";
+
+export default {
+  name: "",
+  components: {},
+  props: {
+    modifyImgVisible: {
+      type: Boolean,
+      default: false,
+    },
+    videoAndVoiceList: {
+      type: Array,
+      default: [],
+    },
+  },
+  data() {
+    return {
+      imgListArr: [],
+      total: 0,
+      page_no: 1,
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {},
+  mounted() {
+    // this.getSelectImgListAll();
+  },
+  methods: {
+    // 选择图片的分页
+    handleCurrentChangeSelectImg(page) {
+      this.page_no = page;
+      this.getSelectImgList();
+    },
+    clickSelectImg(item) {
+      this.$parent.defaultImage = item.ImgUrl;
+      this.$parent.shareImg = item.ShareImg;
+      this.$emit("update:modifyImgVisible", false);
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.seleect-img-box {
+  display: flex;
+  flex-wrap: wrap;
+  .content-img {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 236px;
+    height: 133px;
+    flex-shrink: 0;
+    margin: 0 50px 50px 0;
+    border: 1px solid #dcdfe6;
+    cursor: pointer;
+    .item-img {
+      width: 222px;
+      height: 119px;
+    }
+  }
+}
+</style>

+ 124 - 0
src/views/rai_manage/activityManage/components/imgMeeting.vue

@@ -0,0 +1,124 @@
+<template>
+  <div class="container-img-meeting">
+    <el-dialog width="800px" v-dialogDrag :close-on-click-modal="false" :modal-append-to-body="false" center title="新建标的" :visible.sync="isShowImgMeetingDlg" :before-close="handleClose">
+      <div style="margin-bottom: 10px">
+        <p>请确认建会信息:</p>
+        <div class="box-content" style="padding-left:20px">
+          <div class="box-date">日期</div>
+          <div class="box-time">时间</div>
+          <div class="box-name">公司名称</div>
+        </div>
+      </div>
+      <div class="box-content hover-box-content" v-for="(item, index) in imgMeetingData" :key="item.id">
+        <div class="box-date">
+          <el-date-picker v-model="item.TitmeYMD" type="date" value-format="yyyy年MM月dd日" format="yyyy年MM月dd日  (周ddd)" placeholder="选择日期" style="width: 230px"> </el-date-picker>
+        </div>
+        <div class="box-time">
+          <el-time-picker v-model="item.TitmeHM" value-format="hh:mm A" format="hh:mm A" placeholder="任意时间点" style="width: 160px"> </el-time-picker>
+        </div>
+        <div class="box-name">
+          <el-input v-model="item.Company" placeholder="请输入内容" style="width: 100%" clearable></el-input>
+        </div>
+        <div class="delete-item-icon" @click="deleteLabelItem(item, index)">
+          <img src="~@/assets/img/icons/delete-Item.png" alt="" />
+        </div>
+      </div>
+
+      <span slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="confirmPerson">确定</el-button>
+        <el-button @click="handleClose">取消</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { raiInterface } from "@/api/api.js";
+export default {
+  name: "",
+  components: {},
+  props: {
+    isShowImgMeetingDlg: {
+      type: Boolean,
+      required: true,
+      default: false,
+    },
+    imgMeetingData: {
+      default: [],
+      required: true,
+      type: Array,
+    },
+  },
+  data() {
+    return {
+      value1: "",
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {},
+  mounted() {},
+  methods: {
+    // 确定事件
+    async confirmPerson() {
+      let isConfirm = this.imgMeetingData.every((item) => item.TitmeYMD && item.TitmeHM && item.Company);
+      if (!isConfirm) return this.$message.error("每格的内容都必填。");
+      const res = await raiInterface.preserveAndPublishAdd({
+        ListImgToText: this.imgMeetingData,
+      });
+      console.log(res);
+      if (res.Ret === 200) {
+        this.$message.success("新增成功!");
+        this.$parent.page_no = 1;
+        this.$parent.getsummaryManageList();
+        this.handleClose();
+      }
+    },
+    handleClose() {
+      this.$emit("update:isShowImgMeetingDlg", false);
+
+      this.$emit("childrenImgMeetingHandler");
+    },
+    deleteLabelItem(item, index) {
+      this.$parent.imgMeetingData.splice(index, 1);
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.container-img-meeting {
+  .box-content {
+    margin-top: 20px;
+    display: flex;
+    font-weight: 500;
+
+    .box-date {
+      width: 230px;
+      margin-right: 20px;
+    }
+    .box-time {
+      width: 160px;
+      margin-right: 20px;
+    }
+    .box-name {
+      width: 260px;
+    }
+    .delete-item-icon {
+      display: flex;
+      align-items: center;
+      margin-left: 20px;
+      img {
+        width: 15px;
+        height: 15px;
+      }
+    }
+  }
+  .hover-box-content {
+    margin-top: 0;
+    padding: 10px 20px;
+    &:hover {
+      background-color: #eaf3fe;
+    }
+  }
+}
+</style>

+ 519 - 0
src/views/rai_manage/activityManage/meetingManagement.vue

@@ -0,0 +1,519 @@
+<template>
+  <!-- 实际到会管理页面 -->
+  <div class="container-practical">
+    <!-- 头部el-card -->
+    <el-card style="margin-bottom: 20px">
+      <div class="top-card-box">
+        <el-radio-group v-model="meetingTab" class="tabs-box">
+          <el-radio-button :label="1">线上到会管理</el-radio-button>
+          <el-radio-button :label="2">线下到会管理</el-radio-button>
+        </el-radio-group>
+        <div>
+          <el-input v-model="keyWord" placeholder="请输入活动名称" style="width: 521px" clearable>
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+          </el-input>
+        </div>
+      </div>
+    </el-card>
+    <!-- 内容el-card -->
+    <el-card>
+      <!-- 选择部分 -->
+      <div class="screen-box">
+        <div>
+          <el-select placeholder="行业" clearable v-model="industry" @change="conditionChange" style="margin-bottom: 20px"
+          v-if="!isResearch">
+            <el-option
+              v-for="item in chartPermissionList"
+              :label="item.PermissionName"
+              :key="item.ChartPermissionId"
+              :value="item.ChartPermissionId"
+            ></el-option>
+          </el-select>
+          <el-select
+            placeholder="活动类型"
+            clearable
+            @focus="activityType"
+            v-model="cactivityTypeVal"
+            @change="conditionChange"
+            style="margin-bottom: 20px"
+          >
+            <el-option
+              v-for="item in cactivityTypeList"
+              :label="item.ActivityTypeName"
+              :key="item.ActivityTypeId"
+              :value="item.ActivityTypeId"
+            ></el-option>
+          </el-select>
+          <date-picker v-model="issueTime" type="date" range placeholder="活动时间" value-type="format" @change="conditionChange"> </date-picker>
+        </div>
+        <div class="top-buttons">
+          <el-button type="primary" @click="searchCustomer = true" v-if="meetingTab==1">搜索流失客户</el-button>
+          <el-button style="margin-left: 20px" type="primary" 
+          @click="$router.push(isResearch?'/purchaserAppointment':'/appointment')">查看客户爽约记录</el-button>
+        </div>
+      </div>
+      <!-- 表格部分 -->
+      <el-table :data="dataList" style="width: 100%; margin-top: 20px" border="">
+        <el-table-column min-width="400" align="center" label="活动名称">
+          <template slot-scope="scope">
+            <span class="editsty" @click="titleBtnClick(scope.row.ActivityId)"> {{ scope.row.ActivityName }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="ChartPermissionName" align="center" label="行业"></el-table-column>
+        <el-table-column min-width="120" prop="ActivityTypeName" align="center" label="活动类型"></el-table-column>
+        <el-table-column min-width="219" prop="ActivityTimeText" align="center" label="活动时间"></el-table-column>
+        <el-table-column prop="" align="center" label="报名人数">
+          <template slot-scope="scope">
+            <span class="editsty" @click="particulars(scope.row.ActivityId)">{{ scope.row.SignupPeopleNum }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column min-width="105" prop="MeetPeopleNum" align="center" label="实际参会人数"></el-table-column>
+        <el-table-column min-width="105" prop="UpdateTime" align="center" label="数据更新时间" v-if="meetingTab==1"></el-table-column>
+        <el-table-column min-width="115" align="center" label="操作" v-if="meetingTab==1">
+          <template slot-scope="scope">
+            <!-- <input type="file" size="small" name="file" @change="fileSelected()" id="fileImport" class="true-file" style="display: none" /> -->
+            <p class="editsty" v-if="scope.row.IsShowHandMovement" @click="matching(scope.row.ActivityId)">&nbsp;&nbsp;手动匹配</p>
+            <!-- <span class="editsty" v-if="scope.row.IsYidongConduct === 1" @click="particularsSubmit(scope.row.ActivityId)"
+              >{{ scope.row.IsSubmitMeeting === 0 ? "上传" : "修改" }}参会表格</span
+            > -->
+            <span class="editsty" v-if="scope.row.IsShowSubmitMeeting" @click="arriveHandel(scope.row.ActivityId)">&nbsp;&nbsp;提交到会情况</span>
+            <span class="editsty" v-if="scope.row.IsShowUpdateMeeting" @click="arriveHandel(scope.row.ActivityId)">&nbsp;&nbsp;修改到会情况</span>
+            <span class="editsty" v-if="scope.row.IsShowAttendanceDetails" @click="attendMeeting(scope.row, '到会详情')">&nbsp;&nbsp;到会详情</span>
+            <el-popover v-else-if="scope.row.IsSubmitMeeting == 1 && scope.row.OperationStyle == 2" width="500" trigger="hover" placement="right">
+              <p>到会详情浏览记录</p>
+              <el-table :data="gridData" style="width: 100%" border height="350">
+                <el-table-column align="center" property="RealName" label="浏览人"></el-table-column>
+                <el-table-column align="center" property="CreateTime" label="浏览时间"></el-table-column>
+                <el-table-column align="center" property="StopTime" label="停留时长">
+                  <template slot-scope="{ row }">
+                    {{ row.StopTime }}
+                    <span v-if="row.StopTime">s</span>
+                  </template>
+                </el-table-column>
+              </el-table>
+              <p slot="reference" class="editsty" @mouseenter="popoverMouseenter(scope.row.ActivityId)" @click="goDetail(scope.row.ActivityId)">
+                &nbsp;&nbsp;到会详情
+              </p>
+            </el-popover>
+          </template>
+        </el-table-column>
+        <el-table-column min-width="200" align="center" label="操作" v-else-if="meetingTab==2">
+          <template slot-scope="scope">
+            <span v-if="scope.row.OperationStyle == 1" class="editsty" @click="arriveHandel(scope.row.ActivityId)"
+              >&nbsp;&nbsp;提交到会情况</span
+            >
+
+            <span class="editsty" v-if="scope.row.OperationStyle == 2" @click="arriveHandel(scope.row.ActivityId)"
+              >&nbsp;&nbsp;修改到会情况</span
+            >
+
+            <span class="editsty" v-if="scope.row.OperationStyle == 2" @click="particularsOffline(scope.row.ActivityId, '到会详情')"
+              >&nbsp;&nbsp;到会详情</span
+            >
+           
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-col :span="24" class="toolbar">
+        <m-page :total="total" :page_no="page_no" :pageSize="PageSize" @handleCurrentChange="handleCurrentChange" />
+      </el-col>
+    </el-card>
+    <!-- 详情弹框 -->
+    <atc-particulars :dialogVisible.sync="dialogVisible" :detailData.sync="detailData" />
+    <el-dialog
+      v-dialogDrag
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      center
+      :visible.sync="dialogLeparticaShow"
+      customClass="custom-applydialog"
+      :before-close="confirmPerson"
+    >
+      <div slot="title" style="display: flex; align-items: center">
+        <img :src="$icons.warntop" style="color: #fff; width: 16px; height: 16px; margin-right: 5px" />
+        <span style="font-size: 16px">
+          {{ excelType == "Teleconference" && isLimitPeople == 1 ? "预约外呼详情" : "报名详情" }}
+        </span>
+      </div>
+      <div>
+        <p style="margin-bottom: 10px" v-if="isYiDongShow">
+          <template v-if="memberType == 'Admin'"> 共有{{ totalDlg }}人{{ excelType == "AppointmentCall" ? "预约外呼" : "报名" }} </template>
+          <template v-else-if="memberType == 'Sale'">
+            共有{{ totalDlg }}人{{ excelType == "AppointmentCall" ? "预约外呼" : "报名" }},其中本人名下客户{{ myTotalDlg }}人
+          </template>
+          <template v-else>
+            共有{{ totalDlg }}人{{ excelType == "AppointmentCall" ? "预约外呼" : "报名" }},其中本组名下客户{{ myTotalDlg }}人
+          </template>
+        </p>
+        <p style="margin-bottom: 10px" v-else>
+          <template v-if="memberType == 'Admin'"> 共有{{ totalDlg }}人报名</template>
+        </p>
+        <el-table max-height="260px" :data="tableDataSub" border style="width: 100%">
+          <el-table-column width="130" align="center" prop="RealName" key="name" label="姓名"></el-table-column>
+          <el-table-column width="150" align="center" prop="Mobile" key="mobile" label="手机号" v-if="isYiDongShow"></el-table-column>
+          <el-table-column
+            width="150"
+            align="center"
+            prop="OutboundMobile"
+            key="outboundMobile"
+            label="外呼号码"
+            v-if="isYiDongShow"
+          ></el-table-column>
+          <el-table-column align="center" prop="CompanyName" key="company" label="公司名称" v-if="isCClassNot"></el-table-column>
+          <el-table-column width="150" align="center" prop="SellerName" key="seller" label="所属销售"></el-table-column>
+          <el-table-column min-width="110" key="meeting" align="center" label="参会方式" v-if="isYiDongShow">
+            <template slot-scope="{ row }">
+              <span>
+                {{ row.SignupType == 1 ? "预约外呼" : row.SignupType == 2 ? "自主拨入" : row.SignupType == 4 ? "自主入会" : "" }}
+              </span>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="confirmPerson">知道了</el-button>
+      </span>
+    </el-dialog>
+    <matching-dlg :matchingDlgShow.sync="matchingDlgShow" :matchingId="matchingId" />
+    <partical-dialog
+      :type="attendType"
+      :offlineId="offlineId"
+      :submitDialog.sync="submitDialog"
+      :dialogVisiblepartica.sync="dialogVisiblepartica"
+      :particlaDlg="particlaDlg"
+    />
+    <search-customer-dlg :searchCustomer.sync="searchCustomer" />
+  </div>
+</template>
+
+<script>
+import mPage from "@/components/mPage.vue";
+import { raiInterface } from "@/api/api.js";
+import AtcParticulars from "../components/atcParticulars.vue";
+import MatchingDlg from "../components/matchingDlg.vue";
+import ParticalDialog from "../components/particalDialog.vue";
+import SearchCustomerDlg from "../components/apply/searchCustomerDlg.vue";
+
+export default {
+  name: "meetingManagement",
+  components: { mPage, AtcParticulars, MatchingDlg, ParticalDialog, SearchCustomerDlg },
+  props: {},
+  data() {
+    return {
+      meetingTab:1,
+      dataList: [], //表格的列表
+      tableDataSub: [],
+      page_no: sessionStorage.getItem("interviewListBack") ? JSON.parse(sessionStorage.getItem("interviewListBack")).page_no : 1,
+      total: 0, //条数
+      PageSize: 10, //每页显示几条
+      keyWord: "",
+      industry: "", //行业
+      cactivityTypeVal: "", //活动
+      chartPermissionList: [], //行业的数组
+      cactivityTypeList: [], //活动类型
+      issueTime: "", //时间
+      tabsPitchonType: 1,
+      detailData: {}, //
+      dialogVisible: false,
+      dialogLeparticaShow: false,
+      companyId: "", //
+      excelType: "",
+      isLimitPeople: "",
+      totalDlg: 0,
+      myTotalDlg: 0,
+      memberType: "",
+      matchingDlgShow: false, //匹配弹框
+      matchingId: "",
+      gridData: [],
+      submitDialog: false, //
+      offlineId: "",
+      dialogVisiblepartica: false, //
+      searchCustomer: false, //搜索流失客户
+      isYidongConduct: 0,
+      particlaDlg: {
+        isSpecial: false,
+        id: "",
+        title: "",
+        type: "",
+      },
+    };
+  },
+  computed: {
+    // 弘则 研选 是否是研选
+    isResearch(){
+      return this.$route.path.indexOf("purchaser")!=-1?true:false
+    },
+    exportUser() {
+      return process.env.API_ROOT + "/cygx/activityMeet/meetingExport?" + localStorage.getItem("auth") || "";
+    },
+    isYiDongShow() {
+      return this.isYidongConduct === 1 || this.excelType !== "CClass";
+    },
+    isCClassNot() {
+      return this.isYidongConduct != 1 && this.excelType == "CClass";
+    },
+    attendType(){
+      return this.meetingTab == 1 ? "" : "线下到会";
+    }
+  },
+  watch: {
+    keyWord() {
+      this.page_no = 1;
+      this.init();
+      this.getsDataList();
+    },
+    meetingTab(value) {
+      if(!this.keyWord){
+        this.page_no = 1;
+        this.init();
+        this.getsDataList();
+      } else this.keyWord=""
+    },
+  },
+  created() {},
+  mounted() {
+    !this.isResearch && this.chartPermission();
+    this.getsDataList();
+  },
+  methods: {
+    init() {
+      this.industry = ""; //行业
+      this.issueTime = ""; //时间
+      this.cactivityTypeVal = ""; //活动
+    },
+    //获取行业
+    chartPermission() {
+      raiInterface.chartPermission({IsHideResearch:!this.isResearch}).then((res) => {
+        if (res.Ret === 200) {
+          this.chartPermissionList = res.Data.List;
+        }
+      });
+    },
+    //活动类型
+    activityType() {
+      raiInterface
+        .activityTypeMeetType({
+          MeetType: this.meetingTab,
+          IsResearch:this.isResearch
+        })
+        .then((res) => {
+          if (res.Ret === 200) {
+            this.cactivityTypeList = res.Data.List;
+          }
+        });
+    },
+    //change事件
+    conditionChange() {
+      this.page_no = 1;
+      this.getsDataList();
+    },
+    //列表表格
+    getsDataList() {
+      raiInterface
+        .activityMeetList({
+          CurrentIndex: this.page_no,
+          PageSize: this.PageSize,
+          StartDate: this.issueTime[0],
+          EndDate: this.issueTime[1],
+          KeyWord: this.keyWord,
+          SearchType: this.tabsPitchonType,
+          ChartPermissionId: this.industry,
+          ActivityTypeId: this.cactivityTypeVal,
+          MeetType: this.meetingTab,
+          IsResearch:this.isResearch
+        })
+        .then((res) => {
+          if (res.Ret !== 200) return;
+          this.dataList = res.Data.List;
+          this.total = res.Data.Paging.Totals;
+        });
+    },
+    //分页
+    handleCurrentChange(page) {
+      this.page_no = page;
+      this.getsDataList();
+    },
+    //手动匹配
+    matching(id) {
+      this.matchingId = id;
+      this.matchingDlgShow = true;
+    },
+    //到会详情
+    attendMeeting(item, text) {
+      if (item.SubmitMeetingType == 1 || item.YidongActivityId) {
+        this.offlineId = item.ActivityId;
+        this.particlaDlg = {
+          id: item.ActivityId,
+          title: text,
+          type: item.SubmitMeetingType,
+        };
+        this.dialogVisiblepartica = true;
+      } else {
+        this.goDetail(item.ActivityId);
+      }
+    },
+    //详情弹框
+    particulars(id) {
+      if(this.meetingTab == 1){
+        raiInterface
+        .appointmentList({
+          ActivityId: id,
+        })
+        .then((res) => {
+          if (res.Ret !== 200) return;
+          this.excelType = res.Data.ExcelType;
+          this.isLimitPeople = res.Data.IsLimitPeople;
+          this.totalDlg = res.Data.Total;
+          this.myTotalDlg = res.Data.MyTotal;
+          this.memberType = res.Data.MemberType;
+          this.isYidongConduct = res.Data.IsYidongConduct;
+          this.$nextTick(() => {
+            this.tableDataSub = res.Data.List;
+          });
+        });
+        this.dialogLeparticaShow = true;
+      }else if(this.meetingTab == 2){
+        this.particularsOffline(id,'报名详情')
+      }
+
+    },
+    particularsOffline(id,text){
+      this.offlineId = id;
+      this.particlaDlg = {
+        id,
+        title: text,
+      };
+      this.dialogVisiblepartica = true;
+    },
+    // meetingExport() {
+    //   const loading = this.$loading({
+    //     lock: true,
+    //     text: "客户参会详情文件下载中...",
+    //     spinner: "el-icon-loading",
+    //     background: "rgba(0, 0, 0, 0.7)",
+    //   });
+    //   const xhr = new XMLHttpRequest();
+    //   xhr.open("GET", this.exportUser, true);
+    //   xhr.responseType = "blob";
+    //   xhr.onload = function () {
+    //     if (this.status == 200) {
+    //       loading.close();
+    //       var blob = this.response;
+    //       var a = document.createElement("a");
+    //       var url = window.URL.createObjectURL(blob); //创建url对象
+    //       a.href = url;
+    //       a.download = "客户参会详情.xlsx";
+    //       a.click();
+    //       window.URL.revokeObjectURL(url); //释放url对象
+    //     } else {
+    //       this.$message.error("下载失败!");
+    //     }
+    //   };
+    //   xhr.send();
+    // },
+    //到会情况
+    // particularsSubmit(id) {
+    //   this.companyId = id;
+    //   $("#fileImport").click();
+    // },
+    //点击标题的弹框
+    titleBtnClick(id) {
+      raiInterface.activityDetail({ ActivityId: Number(id) }).then((res) => {
+        if (res.Ret == 200) {
+          this.detailData = res.Data;
+        }
+      });
+      this.dialogVisible = true;
+    },
+    //关闭弹框
+    confirmPerson() {
+      this.tableDataSub = [];
+      this.dialogLeparticaShow = false;
+    },
+    //到会情况
+    arriveHandel(id) {
+      this.offlineId = id;
+      this.submitDialog = true;
+    },
+    // 上传
+    // fileSelected(type) {
+    //   const that = this;
+    //   if (document.getElementById("fileImport").files[0]) {
+    //     let hostfile = document.getElementById("fileImport").files[0];
+    //     let size = Math.floor(hostfile.size / 1024 / 1024);
+    //     if (size > 200) {
+    //       that.$message.error("上传文件大小不能大于200M!");
+    //       hostfile = {};
+    //       return false;
+    //     }
+    //     if (hostfile.name.toLowerCase().includes(".xlsx")) {
+    //       let form = new FormData();
+    //       form.append("File", hostfile); //hostfile.name
+    //       form.append("ActivityId", that.companyId);
+
+    //       raiInterface.activityMeetImport(form).then((res) => {
+    //         if (res.Ret === 200) {
+    //           that.isShowImportDia = true;
+    //           that.importParams = form;
+    //           that.importData = res.Data || [];
+    //           this.$confirm("参会情况已提交成功,可点击【到会详情】查看", "提示", {
+    //             confirmButtonText: "知道了",
+    //             type: "warning",
+    //             showCancelButton: false,
+    //           });
+    //           this.getsDataList();
+    //         }
+    //         $("#fileImport").val("");
+    //         hostfile = {};
+    //       });
+    //     } else {
+    //       that.$message.error("请上传.xlsx的文件格式!");
+    //     }
+    //   }
+    // },
+    goDetail(id) {
+      let routerUrl = this.$router.resolve({
+        path: "attendMeeting",
+        query: {
+          id: id,
+        },
+      });
+      window.open(routerUrl.href, "_blank");
+    },
+    async popoverMouseenter(id) {
+      const res = await raiInterface.activityMeetHistoryList({
+        ActivityId: id,
+      });
+      if (res.Ret === 200) {
+        this.gridData = res.Data.List || [];
+      }
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.container-practical {
+  .top-card-box {
+    display: flex;
+    justify-content: space-between;
+  }
+  .screen-box {
+    display: flex;
+    justify-content: space-between;
+    .top-buttons{
+      display: flex;
+      align-items: flex-start;
+    }
+    .el-select {
+      margin-right: 25px;
+    }
+  }
+  .mx-datepicker {
+    width: 220px !important;
+    margin-right: 25px;
+  }
+  .custom-applydialog {
+    height: 820px;
+  }
+}
+</style>

+ 1 - 1
src/views/rai_manage/activityManage/roadShow/tableTabs.js

@@ -161,7 +161,7 @@ export const PalyTable = [
   },
 ];
 export const TopTabs = [
-  { name: "产业视频", value: 1 },
   { name: "活动视频", value: 2 },
   { name: "活动音频", value: 3 },
+  { name: "产业视频", value: 1 },
 ];

+ 1 - 1
src/views/rai_manage/activityManage/roadShowList.vue

@@ -88,7 +88,7 @@ export default {
     return {
       tableColums: [],
       dataList: [],
-      tabActive: 1, //tabs 选中
+      tabActive: 2, //tabs 选中
       chartPermissionList: [], //行业的数组
       chartPermissionId: "", //行业的id
       issueTime: "", //活动时间

+ 66 - 60
src/views/rai_manage/components/addChoiceness.vue

@@ -50,12 +50,9 @@
             </div>
           </el-form-item>
         </el-form>
-          <!-- 产业/标的 模块 -->
-          <div class="content-module">
-          <draggable
-          v-model="industryList"
-          animation="300"
-          @update="sortChange">
+        <!-- 产业/标的 模块 -->
+        <div class="content-module">
+          <draggable v-model="industryList" animation="300" @update="sortChange">
             <div class="content-industry" v-for="(item, index) in industryList" :key="item.ChartPermissionId">
               <div class="content-name" :class="industryIndex == index ? 'active' : ''" @click="industryBtn(item, index)">{{ item.ChartPermissionName }}</div>
             </div>
@@ -63,15 +60,8 @@
           <div v-for="(item, index) in industryList" :key="item.ChartPermissionId">
             <RichText v-show="industryIndex == index" :ref="'logic' + index" :spareId="'logictest' + index" :isText="contentTextLogic" />
           </div>
-          <draggable
-          :list="industryListItem"
-          animation="300"
-          class="classification"
-          filter=".addIndustrial"
-          :move="onMove"
-          @update="ificationSortChange">
-            <div v-for="(val, num) in industryListItem" :key="val.IndustrialSubjectId" class="industrial" 
-            @click="ificationIndustrialBtn(val, num)" :class="num == ificationIndustrial ? 'pitch' : ''">
+          <draggable :list="industryListItem" animation="300" class="classification" filter=".addIndustrial" :move="onMove" @update="ificationSortChange">
+            <div v-for="(val, num) in industryListItem" :key="val.IndustrialSubjectId" class="industrial" @click="ificationIndustrialBtn(val, num)" :class="num == ificationIndustrial ? 'pitch' : ''">
               <span style="margin-right: 19px">{{ val.IndustrialSubjectName }}</span>
               <span v-if="num == ificationIndustrial">
                 <img src="~@/assets/img/icons/edit1.png" style="width: 12px; height: 12px; marginright: 10px" @click="editText(val, num)" />
@@ -107,6 +97,9 @@
         <div class="content-resource">
           <span class="resource">综述报告:</span>
           <span class="show">{{ overviewList.Title }}</span>
+          <div style="margin-left: 20px">
+            <el-switch @change="switchChangeHandler" v-model="overviewList.IsShowOverviewArticle" :active-value="1" :inactive-value="0" active-text="显示链接" inactive-text="不显示链接"> </el-switch>
+          </div>
         </div>
         <div class="content-bottom">
           <el-button type="primary" @click="confirm('预览')">预览</el-button>
@@ -137,11 +130,11 @@
 <script>
 import RichText from "./richText.vue";
 import { raiInterface } from "@/api/api.js";
-import draggable from 'vuedraggable';
+import draggable from "vuedraggable";
 
 export default {
   name: "",
-  components: { RichText , draggable},
+  components: { RichText, draggable },
   props: {},
   data() {
     return {
@@ -161,10 +154,10 @@ export default {
       },
       rules: {
         title: [{ required: true, message: "请输入标题", trigger: "blur" }],
-        author: [{ required: true, message: "请输入作者", trigger: "blur" }],
-        time: [{ required: true, message: "请输入时间", trigger: "change" }],
-        explain: [{ required: true, message: "请输入产品说明", trigger: "blur" }],
-        reportLink: [{ required: true, message: "请输入报告链接", trigger: "blur" }],
+        // author: [{ required: true, message: "请输入作者", trigger: "blur" }],
+        // time: [{ required: true, message: "请输入时间", trigger: "change" }],
+        // explain: [{ required: true, message: "请输入产品说明", trigger: "blur" }],
+        // reportLink: [{ required: true, message: "请输入报告链接", trigger: "blur" }],
       },
       industryList: [], //行业
       industryIndex: 0, //
@@ -193,10 +186,11 @@ export default {
           this.overviewList = {
             ArticleId: this.industryListItem[this.ificationIndustrial].OverviewArticleId,
             Title: this.industryListItem[this.ificationIndustrial].OverviewArticleTitle,
+            IsShowOverviewArticle: this.industryListItem[this.ificationIndustrial].IsShowOverviewArticle,
           };
         } else {
           this.industrialSubjectName = "";
-          this.overviewList = { ArticleId: 0, Title: "" };
+          this.overviewList = { ArticleId: 0, Title: "", IsShowOverviewArticle: 0 };
         }
       },
       deep: true,
@@ -277,6 +271,7 @@ export default {
         this.overviewList = {
           ArticleId: res.Data.List[0].List && res.Data.List[0].List[0].OverviewArticleId,
           Title: res.Data.List[0].List && res.Data.List[0].List[0].OverviewArticleTitle,
+          IsShowOverviewArticle: res.Data.List[0].List && res.Data.List[0].List[0].IsShowOverviewArticle,
         };
       }
     },
@@ -334,6 +329,7 @@ export default {
         this.overviewList = {
           ArticleId: item.OverviewArticleId,
           Title: item.OverviewArticleTitle,
+          IsShowOverviewArticle: item.IsShowOverviewArticle,
         };
       }
     },
@@ -409,6 +405,7 @@ export default {
               CompanyLabel: [{ name: "", value: item.List.length + 1 }],
               OverviewArticleId: overviewList.ArticleId,
               OverviewArticleTitle: overviewList.Title,
+              IsShowOverviewArticle: overviewList.IsShowOverviewArticle,
             });
           }
         });
@@ -443,8 +440,11 @@ export default {
               IndustrialManagementName: arr.IndustryName,
               IndustrialSubjectId: arr.IndustrialSubjectId + "",
               IndustrialSubjectName: arr.SubjectName,
+              CompanyLabel: item.List[this.editNum].CompanyLabel && item.List[this.editNum].CompanyLabel.length>0?
+                            item.List[this.editNum].CompanyLabel : [{ name: "", value: item.List.length + 1 }],
               OverviewArticleId: overviewList.ArticleId,
               OverviewArticleTitle: overviewList.Title,
+              IsShowOverviewArticle: overviewList.IsShowOverviewArticle,
             };
             item.List.splice(this.editNum, 1, obj);
           }
@@ -491,7 +491,6 @@ export default {
           let params = this.dataHandle(type);
           // console.log(params);
           if (type == "预览") {
-            console.log(params);
             sessionStorage.setItem("choicenessPre", JSON.stringify(params));
             let { href } = this.$router.resolve({ name: "预览报告精选" });
             window.open(href, "_blank");
@@ -572,43 +571,50 @@ export default {
     deleteLabelItem(item, index) {
       this.industryListItem[this.ificationIndustrial].CompanyLabel.splice(index, 1);
     },
-      // 拖拽排序更新
-  sortChange({oldIndex,newIndex}){
-    this.industryIndex=this.sortChangeFun(this.industryIndex,oldIndex,newIndex)
-  },
-  //标的拖拽排序更新
-  ificationSortChange({oldIndex,newIndex}){
-    this.ificationIndustrial=this.sortChangeFun(this.ificationIndustrial,oldIndex,newIndex)
-  },
-  // 排序更新后的逻辑
-  sortChangeFun(currentIndex,oldIndex,newIndex){
-    console.log({currentIndex,oldIndex,newIndex});
-    let bigger,smaller
-    if(oldIndex>newIndex){
-      bigger=oldIndex
-      smaller=newIndex
-    }else{
-      bigger=newIndex
-      smaller=oldIndex
-    }
-    // 当前算中tab的排序 小于较小的 大于较大的 则不用做变动
-    if(currentIndex < smaller || currentIndex > bigger) return currentIndex
-    // 移动的是当前选中的
-    if(currentIndex == oldIndex) return newIndex
-    if(oldIndex>newIndex){
-      // 向左移 加加
-      currentIndex++
-    }else if(oldIndex<newIndex){
-      // 向右移 减减
-      currentIndex--
-    }
-    return currentIndex
-  },
-  onMove(e){
-    // 返回false表示不允许停靠
-    return !!e.relatedContext.element
-  },
-  },
+    switchChangeHandler(e) {
+      this.industryListItem.forEach((item) => {
+        if (item.OverviewArticleId === this.overviewList.ArticleId) {
+          item.IsShowOverviewArticle = e;
+        }
+      });
+    },
+    // 拖拽排序更新
+    sortChange({ oldIndex, newIndex }) {
+      this.industryIndex = this.sortChangeFun(this.industryIndex, oldIndex, newIndex);
+    },
+    //标的拖拽排序更新
+    ificationSortChange({ oldIndex, newIndex }) {
+      this.ificationIndustrial = this.sortChangeFun(this.ificationIndustrial, oldIndex, newIndex);
+    },
+    // 排序更新后的逻辑
+    sortChangeFun(currentIndex, oldIndex, newIndex) {
+      console.log({ currentIndex, oldIndex, newIndex });
+      let bigger, smaller;
+      if (oldIndex > newIndex) {
+        bigger = oldIndex;
+        smaller = newIndex;
+      } else {
+        bigger = newIndex;
+        smaller = oldIndex;
+      }
+      // 当前算中tab的排序 小于较小的 大于较大的 则不用做变动
+      if (currentIndex < smaller || currentIndex > bigger) return currentIndex;
+      // 移动的是当前选中的
+      if (currentIndex == oldIndex) return newIndex;
+      if (oldIndex > newIndex) {
+        // 向左移 加加
+        currentIndex++;
+      } else if (oldIndex < newIndex) {
+        // 向右移 减减
+        currentIndex--;
+      }
+      return currentIndex;
+    },
+    onMove(e) {
+      // 返回false表示不允许停靠
+      return !!e.relatedContext.element;
+    },
+  }
 };
 </script>
 <style lang="scss">

+ 1 - 1
src/views/rai_manage/components/addSummary.vue

@@ -100,7 +100,7 @@
       </span>
     </el-dialog>
     <add-industry-mark
-      addOfEditFormregion="研选"
+      optionFormregion="研选"
       :source="2"
       :addIndustryDlg.sync="addIndustryDlg"
       :addMarkDlg.sync="addMarkDlg"

+ 20 - 0
src/views/rai_manage/components/apply/applyTableColums.js

@@ -117,6 +117,26 @@ export const ListTitle = [
     ChartPermissionId: 3,
   },
 ];
+
+export const purchaserListTitle = [
+  {
+    PermissionName: "专家电话会",
+    ChartPermissionId: 1,
+  },
+  {
+    PermissionName: "专家线下沙龙",
+    ChartPermissionId: 2,
+  },
+  {
+    PermissionName: "买方线下交流",
+    ChartPermissionId: 5,
+  },
+  {
+    PermissionName: "公司调研",
+    ChartPermissionId: 3,
+  },
+];
+
 //表格列
 export const TableApplyColums = (type) => {
   return type === 1

+ 17 - 2
src/views/rai_manage/components/reportComponents/CompanyDetail.vue

@@ -10,8 +10,11 @@
             </tr>
           </thead>
           <tr v-for="(item, index) in childrenList" :key="index">
-            <td v-for="(i, unm) in item" :key="unm">
+            <td v-for="(i, unm) in item" :key="unm" class="new-box">
               <span class="thbody-rs">{{ i.name }}</span>
+              <template v-if="i.IsNew == 1">
+                <img v-if="unm % 2 == 0" src="https://hzchart.oss-cn-shanghai.aliyuncs.com/cygx/new_subject.png" alt="" class="new-img" />
+              </template>
             </td>
           </tr>
         </table>
@@ -65,15 +68,16 @@ export default {
             }
           });
         this.dataList = res.Data.List;
-        console.log(childrenIndex);
         for (let i = 0; i < childrenIndex; i++) {
           let childrenArr = [];
           this.dataList.forEach((item) => {
             childrenArr.push({
               name: item.List[i] ? item.List[i].SubjectName : "",
+              ...item.List[i],
             });
             childrenArr.push({
               name: item.List[i] ? item.List[i].Count : "",
+              ...item.List[i],
             });
           });
           this.childrenList.push(childrenArr);
@@ -106,6 +110,7 @@ export default {
       color: #666;
       thead {
         position: sticky;
+        z-index: 999;
         top: 0;
         left: 0;
         border-left: 1px solid #dcdfe6;
@@ -137,5 +142,15 @@ export default {
   div::-webkit-scrollbar {
     width: 3px !important;
   }
+  .new-box {
+    position: relative;
+    .new-img {
+      position: absolute;
+      width: 20px;
+      height: 20px;
+      top: 0;
+      left: 0;
+    }
+  }
 }
 </style>

+ 13 - 3
src/views/rai_manage/cygxManage/applyUserList.vue

@@ -43,12 +43,12 @@
             <span v-else>{{ scope.row.CompanyName }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="SellerName" label="所属销售" align="center">
+        <el-table-column prop="SellerName" label="所属销售" align="center" width="125">
           <template slot-scope="scope">
             <span>{{ scope.row.SellerName }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="CreateTime" label="申请时间" min-width="130" align="center">
+        <el-table-column prop="CreateTime" label="申请时间" width="160" align="center">
           <template slot-scope="scope">
             <span>{{ scope.row.CreateTime }}</span>
           </template>
@@ -58,11 +58,16 @@
             <span>{{ scope.row.CompanyIdTypeName }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="ApplicationSource" label="申请来源" min-width="130" align="center">
+        <el-table-column prop="ApplicationSource" label="申请来源" width="115" align="center">
           <template slot-scope="scope">
             <span>{{ scope.row.ApplicationSource }}</span>
           </template>
         </el-table-column>
+        <el-table-column prop="Title" label="申请内容" min-width="130" align="center">
+          <template slot-scope="scope">
+            <span class="editsty" @click="applicationContent(scope.row)">{{ scope.row.Title }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" align="center" min-width="110">
           <template slot-scope="scope">
             <span class="editsty" v-if="scope.row.BusinessCardUrl" @click="previewImg(scope.row)">查看名片</span>
@@ -188,6 +193,11 @@ export default {
           }
         });
     },
+    // 申请内容
+    applicationContent(item) {
+      window.open(item.HttpUrl, "_blank");
+      console.log(item);
+    },
   },
   created() {},
   mounted() {

+ 5 - 4
src/views/rai_manage/cygxManage/lableManage.vue

@@ -24,7 +24,7 @@
       </div>
       <el-table border :data="tableList">
         <el-table-column align="center" key="name" prop="TagName" label="标签名称" width=""></el-table-column>
-        <el-table-column align="center" key="series" prop="ArticleTypes" label="报告系列" width=""></el-table-column>
+        <el-table-column align="center" key="series" prop="ArticleTypes" label="报告类型" width=""></el-table-column>
         <el-table-column align="center" key="type" prop="ActivityTypes" label="活动类型" width=""></el-table-column>
         <el-table-column align="center" key="industry" prop="Industries" label="相关产业" width=""></el-table-column>
         <el-table-column align="center" key="subject" prop="SubjectNames" label="相关标的" width=""></el-table-column>
@@ -65,7 +65,7 @@
                 filterable
                 remote
                 reserve-keyword
-                placeholder="请输入关联的报告系列(选填,可输入多个)"
+                placeholder="请输入关联的报告类型(选填,可输入多个)"
                 :remote-method="remoteMethodArticle"
               >
                 <el-option v-for="item in optionsArticle" :key="item.SubCategoryName" :label="item.SubCategoryName" :value="item.SubCategoryName"> </el-option>
@@ -119,7 +119,6 @@
 import Sortable from "sortablejs";
 import mPage from "@/components/mPage.vue";
 import { raiInterface } from "@/api/api.js";
-// import { async } from "@antv/x6/lib/registry/marker/async";
 export default {
   name: "",
   components: { mPage },
@@ -192,7 +191,9 @@ export default {
 
     // 获取活动类型
     async activityType() {
-      const res = await raiInterface.getActivityType();
+      const res = await raiInterface.getActivityType({
+        IsGetAll:true,
+      });
       if (res.Ret === 200) {
         this.optionsActivity = res.Data.List;
       }

+ 67 - 0
src/views/rai_manage/reportManage/components/roadshowApplyDlg.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="container">
+    <!-- 选择图片的弹框 -->
+    <el-dialog title="路演申请" :visible.sync="isRadshowApplyShow" width="50%" :before-close="handleClose" v-dialogDrag :close-on-click-modal="false" :modal-append-to-body="false" center>
+      <div>
+        <el-table :data="tableData" style="width: 100%; margin-bottom: 20px" border>
+          <el-table-column prop="SubjectName" align="center" label="申请标的"></el-table-column>
+          <el-table-column prop="RealName" align="center" label="申请人"></el-table-column>
+          <el-table-column prop="CompanyName" align="center" label="公司名称"></el-table-column>
+          <el-table-column prop="SellerName" align="center" label="所属销售"></el-table-column>
+          <el-table-column width="160" prop="CreateTime" align="center" label="申请时间"></el-table-column>
+        </el-table>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { raiInterface } from "@/api/api.js";
+
+export default {
+  name: "",
+  components: {},
+  props: {
+    isRadshowApplyShow: {
+      type: Boolean,
+      default: false,
+    },
+    radshowApplyId: {
+      type: Number,
+      default: 0,
+    },
+  },
+  data() {
+    return {
+      tableData: [],
+    };
+  },
+  computed: {},
+  watch: {
+    isRadshowApplyShow: {
+      handler(newVal) {
+        newVal && this.getTableList();
+      },
+    },
+  },
+  created() {},
+  mounted() {},
+  methods: {
+    // 关闭弹框
+    handleClose() {
+      this.$emit("update:isRadshowApplyShow", false);
+      this.$emit("update:radshowApplyId", 0);
+    },
+    // 获取表格数据
+    async getTableList() {
+      const res = await raiInterface.reportSelectionTarryList({
+        ArticleId: this.radshowApplyId,
+      });
+      if (res.Ret === 200) {
+        this.tableData = res.Data.List || [];
+      }
+    },
+  },
+};
+</script>
+<style scoped lang="scss"></style>

+ 15 - 1
src/views/rai_manage/reportManage/reportChoiceness.vue

@@ -37,6 +37,11 @@
             </div>
           </template>
         </el-table-column>
+        <el-table-column prop="Periods" align="center" label="路演申请" width="100">
+          <template slot-scope="{ row }">
+            <span class="editsty" @click="roadshowApplyHandler(row)">{{ row.ApplyTotal }}</span>
+          </template>
+        </el-table-column>
         <el-table-column key="VisibleRange" width="156" label="可见范围" align="center">
           <template slot-scope="{ row }" v-if="row.PublishStatus === 1">
             <el-radio-group v-model="row.VisibleRange" @input="reportVisibleRange(row)">
@@ -61,6 +66,7 @@
       </el-col>
     </el-card>
     <CompanyDetail :isCompanyDetailShow.sync="isCompanyDetailShow" :companyDetailId.sync="companyDetailId" />
+    <roadshow-apply-dlg :isRadshowApplyShow.sync="isRadshowApplyShow" :radshowApplyId.sync="radshowApplyId" />
   </div>
 </template>
 
@@ -68,9 +74,10 @@
 import mPage from "@/components/mPage.vue";
 import { raiInterface } from "@/api/api.js";
 import CompanyDetail from "../components/reportComponents/CompanyDetail.vue";
+import RoadshowApplyDlg from "./components/roadshowApplyDlg.vue";
 export default {
   name: "",
-  components: { mPage, CompanyDetail },
+  components: { mPage, CompanyDetail, RoadshowApplyDlg },
   props: {},
   data() {
     return {
@@ -88,6 +95,8 @@ export default {
       tableData: [], //表格
       isCompanyDetailShow: false, //公司点击详情弹框
       companyDetailId: 0,
+      isRadshowApplyShow: false, // 路演申请
+      radshowApplyId: 0, // 路演申请查看的ID
     };
   },
   computed: {
@@ -217,6 +226,11 @@ export default {
         this.getList();
       }
     },
+    // 路演申请的弹框
+    roadshowApplyHandler(item) {
+      this.radshowApplyId = item.ArticleId;
+      this.isRadshowApplyShow = true;
+    },
   },
   /* 页面跳转前记录参数 */
   beforeRouteLeave(to, form, next) {

+ 13 - 3
src/views/report_manage/dayilyNews.vue

@@ -14,10 +14,17 @@
       <div class="list-item" v-for="(item,index) in newsList" :key="item.MsgId">
         <div class="item-cont">
           <p class="news">
-            <span style="font-weight: bold;margin-right: 10px;" v-if="item.MsgTime">{{item.MsgTime.substr(10)}}</span>
+            <span style="font-weight: bold;margin-right: 10px;" v-if="item.MsgTime">
+              {{transformTimeType(item.MsgTime)}}
+            </span>
             {{item.Content}} 
           </p>
-          <p class="news-en" :style="item.showEn ? 'display:block' : 'display:none'">{{item.ContentEn}}</p>
+          <p class="news-en" :style="item.showEn ? 'display:block' : 'display:none'">
+            <span style="font-weight: bold;margin-right: 10px;" v-if="item.MsgTime">
+              {{transformTimeType(item.MsgTime)}}
+            </span>
+            {{item.ContentEn}}
+          </p>
         </div>
 
         <div class="item-bot">
@@ -389,7 +396,10 @@ export default {
         this.page_no++;
         this.getList()
       }
-    },300)
+    },300),
+    transformTimeType(date){
+      return date.replaceAll('-','/').substr(0,16)
+    }
   },
 
   mounted() {

+ 201 - 112
src/views/resetpassword.vue

@@ -1,118 +1,207 @@
 <template>
-	<div>
-		<el-card class="box-card">
-			<div slot="header" class="clearfix">
-				<b>修改密码</b>
-			</div>
-			<el-form :model="addForm" :rules="rules" label-width="120px" ref="addForm" style="width:500px;">
-				<el-form-item label="原密码" prop="OldPwd">
-		          	<el-input type="text" v-model="addForm.OldPwd" placeholder="请输入不超过20个字符" clearable autocomplete="new-password"></el-input>
-		        </el-form-item>
-		        <el-form-item label="新密码" prop="NewPwd" v-if="visible">
-					<el-input type="password" v-model="addForm.NewPwd" placeholder="请输入长度不超过20个字符" maxlength="20" autocomplete="new-password">
-		            	<i slot="suffix" class="el-icon-view el-input__icon" title="显示密码" @click="changePass('show')" style="cursor:pointer;"></i>
-		          	</el-input>
-				</el-form-item>
-				<el-form-item label="新密码" prop="NewPwd" v-else>
-		          	<el-input type="text" v-model="addForm.NewPwd" placeholder="请输入长度不超过20个字符" maxlength="20" autocomplete="new-password">
-		            	<i slot="suffix" class="el-icon-more el-input__icon" title="隐藏密码" @click="changePass('hide')" style="cursor:pointer;"></i>
-		          	</el-input>
-		        </el-form-item>
-				<el-form-item label="确认新密码" prop="twoNewPwd" v-if="twovisible">
-					<el-input type="password" v-model="addForm.twoNewPwd" placeholder="请输入长度不超过20个字符" maxlength="20">
-				    	<i slot="suffix" class="el-icon-view el-input__icon" title="显示密码" @click="changetwoPass('show')" style="cursor:pointer;"></i>
-				  	</el-input>
-				</el-form-item>
-				<el-form-item label="确认新密码" prop="twoNewPwd" v-else>
-				  	<el-input type="text" v-model="addForm.twoNewPwd" placeholder="请输入长度不超过20个字符" maxlength="20">
-				    	<i slot="suffix" class="el-icon-more el-input__icon" title="隐藏密码" @click="changetwoPass('hide')" style="cursor:pointer;"></i>
-				  	</el-input>
-				</el-form-item>
-				<el-form-item style="text-align:center; padding-top:20px;">
-					<el-button type="primary" size="medium" @click.native="addSubmit">确定</el-button>
-					<el-button type="primary" size="medium" plain @click.native="historyBack">返回</el-button>
-				</el-form-item>
-			</el-form>
-		</el-card>
-	</div>
+  <div>
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <b>修改密码</b>
+      </div>
+      <el-form
+        :model="addForm"
+        :rules="rules"
+        label-width="120px"
+        ref="addForm"
+        style="width: 500px"
+      >
+        <el-form-item label="原密码" prop="OldPwd">
+          <el-input
+            type="text"
+            v-model="addForm.OldPwd"
+            placeholder="请输入不超过20个字符"
+            clearable
+            autocomplete="new-password"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="新密码" prop="NewPwd" v-if="visible">
+          <el-input
+            type="password"
+            v-model="addForm.NewPwd"
+            placeholder="请输入长度不超过20个字符"
+            maxlength="20"
+            autocomplete="new-password"
+          >
+            <i
+              slot="suffix"
+              class="el-icon-view el-input__icon"
+              title="显示密码"
+              @click="changePass('show')"
+              style="cursor: pointer"
+            ></i>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="新密码" prop="NewPwd" v-else>
+          <el-input
+            type="text"
+            v-model="addForm.NewPwd"
+            placeholder="请输入长度不超过20个字符"
+            maxlength="20"
+            autocomplete="new-password"
+          >
+            <i
+              slot="suffix"
+              class="el-icon-more el-input__icon"
+              title="隐藏密码"
+              @click="changePass('hide')"
+              style="cursor: pointer"
+            ></i>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="确认新密码" prop="twoNewPwd" v-if="twovisible">
+          <el-input
+            type="password"
+            v-model="addForm.twoNewPwd"
+            placeholder="请输入长度不超过20个字符"
+            maxlength="20"
+          >
+            <i
+              slot="suffix"
+              class="el-icon-view el-input__icon"
+              title="显示密码"
+              @click="changetwoPass('show')"
+              style="cursor: pointer"
+            ></i>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="确认新密码" prop="twoNewPwd" v-else>
+          <el-input
+            type="text"
+            v-model="addForm.twoNewPwd"
+            placeholder="请输入长度不超过20个字符"
+            maxlength="20"
+          >
+            <i
+              slot="suffix"
+              class="el-icon-more el-input__icon"
+              title="隐藏密码"
+              @click="changetwoPass('hide')"
+              style="cursor: pointer"
+            ></i>
+          </el-input>
+        </el-form-item>
+        <el-form-item style="text-align: center;">
+          <el-button type="primary" size="medium" @click.native="addSubmit"
+            >确定</el-button
+          >
+          <el-button
+            type="primary"
+            size="medium"
+            plain
+            @click.native="historyBack"
+            >返回</el-button
+          >
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
 </template>
 
 <script>
-	import { modifyPwd } from '@/api/api.js';
-	import http from "@/api/http.js";
-	import md5 from "@/utils/md5.js";
-	export default {
-		data() {
-			return {
-				visible:true,
-				twovisible:true,
-				addForm:{
-					OldPwd:'',
-					NewPwd:'',
-					twoNewPwd:''
-				},
-				rules: {
-					OldPwd: [{
-						required:true,
-						message:'请输入原密码',
-						trigger:'blur'
-					}],
-					NewPwd: [{
-						required:true,
-						message:'请输入确认密码',
-						trigger:'blur'
-					}],
-					twoNewPwd: [{
-						required:true,
-						message:'请输入确认密码',
-						trigger:'blur'
-					}]
-				}
-			}
-		},
-		mounted() {
-			
-		},
-		methods: {
-			changePass(value){
-	        	this.visible = !(value === 'show');
-	     	},
-			changetwoPass(value){
-				this.twovisible = !(value === 'show');
-			},
-	     	addSubmit(){
-	     		this.$refs.addForm.validate((valid) => {
-					if( valid ){
-						let that=this;
-						if( that.addForm.NewPwd!=that.addForm.twoNewPwd ){
-							that.$message.warning("新密码两次输入不一致,请核对!");
-							return false;
-						}
-						modifyPwd({OldPwd:md5.hex_md5(that.addForm.OldPwd),NewPwd:md5.hex_md5(that.addForm.NewPwd)}).then((res) => {
-							if( res.Ret == 200 ){
-								that.$message.success("修改密码成功,请重新登录!");
-								setTimeout(function(){
-									// http.setCookie({rddp_admin_access_token:'',rddp_user_name:''},function(){},0);
-									localStorage.setItem('auth','');
-									localStorage.setItem('userName','');
-									localStorage.setItem('Role','');
-									localStorage.setItem('RoleType','');
-									localStorage.setItem('AdminId','');
-                  localStorage.setItem('AdminName','')
-									localStorage.setItem('RoleIdentity','')
-									localStorage.setItem('ManageType','');
-									that.$router.push({path:'/login'});
-								},1000);
-							}
-						});
-					}
-				});
-	     	},
-	     	historyBack(){  //返回上一页
-		    	history.back();
-		    }
-		}
-	}
+import { modifyPwd } from "@/api/api.js";
+import http from "@/api/http.js";
+import md5 from "@/utils/md5.js";
+import{checkPassWord} from '@/utils/commonOptions';
+export default {
+  data() {
+    return {
+      visible: true,
+      twovisible: true,
+      addForm: {
+        OldPwd: "",
+        NewPwd: "",
+        twoNewPwd: "",
+      },
+      rules: {
+        OldPwd: [
+          {
+            required: true,
+            message: "请输入原密码",
+            trigger: "blur",
+          },
+        ],
+        NewPwd: [
+            {
+                validator:(rule,value,callback)=>{
+                    if(!checkPassWord(value)){
+                        callback(new Error('密码要求8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型'))
+                    }else{
+                        callback()
+                    }
+                }
+            },
+          {
+            required: true,
+            message: "请输入确认密码",
+            trigger: "blur",
+          },
+        ],
+        twoNewPwd: [
+          {
+            required: true,
+            message: "请输入确认密码",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
+  },
+  mounted() {},
+  methods: {
+    changePass(value) {
+      this.visible = !(value === "show");
+    },
+    changetwoPass(value) {
+      this.twovisible = !(value === "show");
+    },
+    addSubmit() {
+      this.$refs.addForm.validate((valid) => {
+        if (valid) {
+          let that = this;
+          if (that.addForm.NewPwd != that.addForm.twoNewPwd) {
+            that.$message.warning("新密码两次输入不一致,请核对!");
+            return false;
+          }
+          modifyPwd({
+            OldPwd: md5.hex_md5(that.addForm.OldPwd),
+            NewPwd: md5.hex_md5(that.addForm.NewPwd),
+          }).then((res) => {
+            if (res.Ret == 200) {
+              that.$message.success("修改密码成功,请重新登录!");
+              setTimeout(function () {
+                localStorage.setItem("auth", "");
+                localStorage.setItem("userName", "");
+                localStorage.setItem("Role", "");
+                localStorage.setItem("RoleType", "");
+                localStorage.setItem("AdminId", "");
+                localStorage.setItem("AdminName", "");
+                localStorage.setItem("RoleIdentity", "");
+                localStorage.setItem("ManageType", "");
+                that.$router.push({ path: "/login" });
+              }, 1000);
+            }
+          });
+        }
+      });
+    },
+    historyBack() {
+      //返回上一页
+      history.back();
+    },
+  },
+};
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.box-card{
+    .el-form-item{
+        margin-bottom: 40px;
+    }
+}
+</style>

+ 1 - 0
src/views/roadshow_manage/statistics/index.scss

@@ -35,6 +35,7 @@
 
 		.table-body-wrapper {
 			max-height: calc(100vh - 340px);
+			margin-right: -6px;
 			overflow-y: scroll;
 			overflow-x: auto;
 			border-bottom: 1px solid #dcdfe6;

+ 1 - 1
src/views/roadshow_manage/statistics/researcher.vue

@@ -155,7 +155,7 @@ export default {
 				}
 				this.$nextTick(() => {
 					this.dataLoading = true;
-					$('table').find('td').css({ width: dynamic_width[this.default_tab]&&dynamic_width[this.default_tab]})
+					$('table').find('td').css({ width: dynamic_width[this.default_tab]?dynamic_width[this.default_tab]:'25%'})
 					$('table').find('.thead-rs').css({ width: dynamic_width[this.default_tab] ? dynamic_width[this.default_tab] : '120px' })
 					$('table').find('.head-column').css({ width: dynamic_width[this.default_tab] ? dynamic_width[this.default_tab] : '25%' })
 				})

+ 1 - 0
src/views/system_manage/assistance_center/assistanceDocAdd.vue

@@ -99,6 +99,7 @@ import {createBottomHref} from "./utils/common"
           fileUploadURL: process.env.API_ROOT + "/report/uploadImg", //上传url 更多上传介绍 请访问https://www.froala.com/wysiwyg-editor/docs/options
           imageEditButtons:['imageAlign', 'imageCaption', 'imageRemove',  '-', 'imageDisplay',  'imageSize'],
           quickInsertButtons: ["image","video","hr"], //快速插入项
+          quickInsertEnabled:false, // 是否启用快速插入功能
           toolbarVisibleWithoutSelection: false, //是否开启 不选中模式
           // disableRightClick:true,//是否屏蔽右击
           toolbarSticky: false, //操作栏是否自动吸顶

+ 53 - 7
src/views/system_manage/components/addUserDialog.vue

@@ -13,22 +13,29 @@
                 </el-input>
             </el-form-item>
             <el-form-item label="登录密码" prop="pwd" v-if="userForm.title == '添加用户'">
-                <el-input v-model="userForm.pwd" placeholder="6-12位数字与字母的组合" 
+                <el-input v-model.trim="userForm.pwd" placeholder="6-12位数字与字母的组合" 
                     :type="userForm.title == '添加用户' ? 'text' : 'password' " clearable></el-input>
             </el-form-item>
             <el-form-item label="姓名" prop="name">
                 <el-input v-model="userForm.name" placeholder="请输入用户名称"  clearable>
                 </el-input>
             </el-form-item>
-            <el-form-item label="手机号码" prop="mobile">
-                <el-input v-model="userForm.mobile" placeholder="请输入手机号码" clearable>
+            <el-form-item label="手机号码" prop="mobile" class="mobile-input-item">
+                <el-input v-model.trim="userForm.mobile" placeholder="请输入手机号码" clearable class="mobile-input">
                 </el-input>
+                <el-select v-model="userForm.areacode" class="mobile-select" placeholder="请选择">
+                    <el-option v-for="item in areaCode" :key="item.Value"
+                        :label="item.Name" :value="item.Value" />
+                </el-select>
             </el-form-item>
             <el-form-item label="所属部门" prop="depart" v-if="userForm.title == '添加用户'">
                 <el-cascader :options="departArr" v-model="userForm.depart" :props="form_departProp"
                     placeholder="请选择部门分组" clearable>
                 </el-cascader>
             </el-form-item>
+            <el-form-item label="邮箱" prop="email">
+                <el-input v-model="userForm.email" placeholder="请输入邮箱"></el-input>
+            </el-form-item>
             <el-form-item label="工号" prop="employeeNumber">
                 <el-input :disabled="hasEmployeeNo" v-model="userForm.employeeNumber" placeholder="请输入工号"></el-input>
             </el-form-item>
@@ -69,6 +76,7 @@
 
 <script>
 import searchDistPicker from '@/components/searchDistPicker.vue'
+import {patternEmail,isMobileNo,checkPassWord} from '@/utils/commonOptions'
     export default {
         props: {
             isAddUserDialogShow: {
@@ -96,6 +104,10 @@ import searchDistPicker from '@/components/searchDistPicker.vue'
             researchGroup:{
                 type:Array,
                 default:()=>{return []}
+            },
+            areaCode:{
+                type:Array,
+                default:()=>{return []}
             }
         },
         components:{searchDistPicker},
@@ -103,13 +115,33 @@ import searchDistPicker from '@/components/searchDistPicker.vue'
             return {
                 userRule: {
                     account:[{required: true, message: '登录账号不能为空', trigger: 'blur'}],
-                    pwd:[{ required: true, message: '登录密码不能为空', trigger: 'blur' }],
+                    pwd:[{validator:(rule,value,callback)=>{
+                        if(value===''){
+                            callback(new Error('请输入新密码'))
+                        }
+                        if(!checkPassWord(value)){
+                            callback(new Error('密码要求8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型'))
+                        }else{
+                            callback()
+                        }
+                    }}],
                     name:[{ required: true, message: '姓名不能为空', trigger: 'blur' }],
                     mobile:[{ validator: (rule, value, callback) => {
-                        if (value === '') {
-                            callback(new Error('手机号码不能为空'));
-                        }else if(isNaN(value.trim())) {
+                        if (value === ''&&!this.userForm.email) {
+                            callback(new Error('手机号码和邮箱至少填一个'));
+                        }else if(value&&this.userForm.areacode==='86'&&!isMobileNo(value)) {
                             callback(new Error('请输入正确的手机号格式'));
+                        } else if(this.userForm.areacode!=='86'&&isNaN(value.trim())){
+                            callback(new Error('请输入正确的手机号格式'));
+                        }else {
+                            callback();
+                        }
+                    }, trigger: 'blur'}],
+                    email:[{ validator: (rule, value, callback) => {
+                        if (value === ''&&!this.userForm.mobile) {
+                            callback(new Error('手机号码和邮箱至少填一个'));
+                        }else if(value&&!patternEmail.test(value)) {
+                            callback(new Error('请输入正确的邮箱格式'));
                         } else {
                             callback();
                         }
@@ -163,6 +195,20 @@ import searchDistPicker from '@/components/searchDistPicker.vue'
             width:145px;
         }
     }
+    .mobile-input-item{
+        position:relative;
+        .mobile-select{
+            position:absolute;
+            top:0;
+            left:0;
+            width:115px !important;
+        }
+        .mobile-input{
+            .el-input__inner{
+                padding-left: 125px !important;
+            }
+        }
+    }
 }
 </style>
 <style scoped lang="scss">

+ 39 - 132
src/views/system_manage/departManage.vue

@@ -3,7 +3,7 @@
 		<div class="left_cont">
 			<div class="company_top" @click="initDepart">
 				<img src="~@/assets/img/set_m/home_ico.png" alt="" style="width:30px;height:30px;">
-				<span :class="!defaultGroup&&!defaultDepart?'act':''">弘则研究</span>
+				<span :class="!defaultGroup&&!defaultDepart?'act':''">部门信息</span>
 			</div>
 			<el-tree
 				ref="departTree"
@@ -12,7 +12,6 @@
 				:data="departArr"
 				node-key="unicodeKey"
 				:props="defaultProp"
-				default-expand-all
 				draggable 
 				:allow-drag="checkAllowDrag"
 				:allow-drop="checkAllowDrop"
@@ -80,6 +79,11 @@
 							<span style="position: relative;">{{scope.row.RealName}}</span>
 						</template>
 					</el-table-column>
+					<el-table-column 
+						prop="AdminName"
+						label="账号"
+						align="center"
+					/>
 					<el-table-column
 					prop="Mobile"
 					label="手机号"
@@ -275,128 +279,6 @@
 				<el-button  style="width:80px;" @click="cancelHandle(2)">取消</el-button>
 			</div>
 		</el-dialog>
-		<!-- 添加用户
-			研报后台5.9后拆成组件重写了,这块没实际用到,留着参考
-		 -->
-		<!-- <el-dialog
-		:title="userForm.title"
-		:visible.sync="isAddUser"
-		:close-on-click-modal="false"
-		:modal-append-to-body='false'
-		@close="cancelHandle(3)"
-		center
-		width="700px"
-		top="5vh"
-		v-dialogDrag>
-			<div slot="title" style="display:flex;alignItems:center;">
-				<img :src="userForm.title=='添加用户'?$icons.add:$icons.edit" style="color:#fff;width:16px;height:16px;marginRight:5px;">
-				<span style="fontSize:16px;">{{userForm.title}}</span>
-			</div>
-			<el-form @submit.native.prevent :model="userForm" :rules="userRule" ref="userForm" label-width="100px" class="demo-ruleForm" style="marginTop:15px;">
-				<el-form-item label="登录账号" prop="account">
-					<el-input
-					v-model="userForm.account"
-					placeholder="建议使用邮箱前缀或者手机号码"
-					style="width:90%"
-					clearable>
-					</el-input>
-				</el-form-item>
-				<el-form-item label="登录密码" prop="pwd">
-					<el-input 
-					v-model="userForm.pwd"
-					placeholder="6-12位数字与字母的组合"
-					style="width:90%"
-					:type="userForm.title == '添加用户' ? 'text' : 'password' "
-					clearable></el-input>
-				</el-form-item>
-				<el-form-item label="工号" prop="employeeNumber">
-					<el-input :disabled="hasEmployeeNo"
-					v-model="userForm.employeeNumber"
-					placeholder="请输入工号"
-					style="width:90%"></el-input>
-				</el-form-item>
-				<el-form-item label="姓名" prop="name">
-					<el-input
-					v-model="userForm.name"
-					placeholder="请输入用户名称"
-					style="width:90%"
-					clearable>
-					</el-input>
-				</el-form-item>
-				<el-form-item label="所属部门" prop="depart">
-					<el-cascader
-						:options="departArr"
-						v-model="userForm.depart"
-						:props="form_departProp"
-						placeholder="请选择部门分组"
-						:key="cascaderIdx"
-						style="width:90%"
-						clearable
-						></el-cascader>
-				</el-form-item>
-				<el-form-item label="分配角色" prop="role">
-					<el-select v-model="userForm.role" placeholder="分配角色" @change="roleChange" style="width:90%">
-						<el-option
-							v-for="item in roleArr"
-							:key="item.RoleId"
-							:label="item.RoleName"
-							:value="item.RoleId">
-						</el-option>
-					</el-select>
-				</el-form-item>
-					<el-form-item label="研究方向" prop="direct">
-						<el-cascader
-						collapse-tags
-						:show-all-levels="false"
-						:options="researchGroup"
-						v-model="userForm.direct"
-						:props="form_directProp"
-						placeholder="请选择研究方向"
-						style="width:90%"
-						clearable
-						></el-cascader>
-					</el-form-item>
-					<el-form-item label="工作地点" prop="city"
-					:rules="[2,6,18].includes(userForm.role)?{ required: true, message: '工作地点不能为空', trigger: 'change' }:{}">
-						<v-distpicker 
-              :province-source="province_sorce"
-              :city-source="city_sorce"
-							:province="userForm.province"
-							:city="userForm.city"
-							hide-area 
-							@selected="selectRegion"
-							@province="provinceChange"
-						></v-distpicker>
-					</el-form-item>
-				<el-form-item label="职务" prop="post">
-					<el-input
-					v-model="userForm.post"
-					placeholder="请输入职务"
-					style="width:90%"
-					clearable>
-					</el-input>
-				</el-form-item>
-				<el-form-item label="手机号码" prop="mobile">
-					<el-input
-					v-model="userForm.mobile"
-					placeholder="请输入手机号码"
-					style="width:90%"
-					clearable>
-					</el-input>
-				</el-form-item>
-				<el-form-item label="状态" prop="status">
-					<el-radio-group v-model="userForm.status">
-						<el-radio :label="1">启用</el-radio>
-						<el-radio :label="0">禁用</el-radio>
-					</el-radio-group>
-				</el-form-item>
-			</el-form>	
-			<div style="display:flex;justify-content:center;margin:75px 0 26px;">
-				<el-button type="primary" style="width:80px;marginRight:24px;" @click="saveUser">保存</el-button>
-				<el-button  style="width:80px;" @click="cancelHandle(3)">取消</el-button>
-			</div>
-		</el-dialog> -->
-		<!-- 编辑分组 -->
 		<el-dialog
 		title="编辑分组"
 		:visible.sync="isEditGroup"
@@ -438,6 +320,7 @@
 			:roleArr="roleArr"
 			:hasEmployeeNo="hasEmployeeNo"
 			:researchGroup="researchGroup"
+			:areaCode="areaCode"
 			@close="cancelHandle(3)"
 			@save="saveUser"
 			@selectRegion="selectRegion"
@@ -453,6 +336,9 @@
 		>
 			<div class="dialog-container">
 				<el-form ref="resetForm" :model="resetForm" :rules="resetRules" label-width="100px">
+					<el-form-item label="账号">
+						<span>{{modifyAdminName}}</span>
+					</el-form-item>
 					<el-form-item label="新密码" prop="password">
 						<el-input v-model="resetForm.password" style="width:100%" :show-password="true"></el-input>
 					</el-form-item>
@@ -475,6 +361,10 @@
 			@close="isMoveDepartShow=false" center width="460px" v-dialogDrag
 		>
 			<div class="dialog-cotainer">
+				<div class="form-item" style="display: flex;align-items: center;margin-bottom:20px">
+					<p style="width:90px">账号</p>
+					<span>{{modifyAdminName}}</span>
+				</div>
 				<div class="form-item" style="display: flex;align-items: center;">
 					<p style="width:90px">选择分组</p>
 					<el-cascader :options="departArr" v-model="resetDepart" :props="form_departProp" style="width:100%"
@@ -586,6 +476,8 @@ export default {
 				mobile:'',
 				auth:0,
 				status:1,//状态 1启用 0禁用
+				email:'',
+				areacode:'86',
 			},//用户弹框表单
 			// 是否有工号
 			hasEmployeeNo:false,
@@ -692,6 +584,7 @@ export default {
 		}else if(process.env.NODE_ENV == 'production'){
 			this.shareCustomDepartmentId = 37
 		}
+		this.getAreaCode()
 	},
 	mounted() {
 		this.getDepartArr();
@@ -1035,7 +928,7 @@ export default {
 			this.userForm = {
 				title:'添加用户',
 				account:'',
-				pwd:'123456a',
+				pwd:'',
 				employeeNumber:'',
 				name:'',
 				depart:'',
@@ -1046,7 +939,9 @@ export default {
 				post:'',
 				mobile:'',
 				auth:0,
-				status:1
+				status:1,
+				email:'',
+				areacode:'86',
 			}
 		},
 		// 同步每刻
@@ -1100,6 +995,8 @@ export default {
 							ResearchGroupIds:ResearchGroupIds.join(','),
 							Province:this.userForm.province,
 							City:this.userForm.city,
+							Email:this.userForm.email,
+							TelAreaCode:this.userForm.areacode,
 						}
 						//console.log('testAdd',params)
 						departInterence.addUser(params).then(res => {
@@ -1120,7 +1017,9 @@ export default {
 									post:'',
 									mobile:'',
 									auth:0,
-									status:1
+									status:1,
+									email:'',
+									areacode:'86'
 								}
 								this.getTableUser();
 							}
@@ -1147,7 +1046,9 @@ export default {
 							Enabled:Number(this.userForm.status),
 							ResearchGroupIds:ResearchGroupIds.join(','),
 							Province:this.userForm.province,
-							City:this.userForm.city
+							City:this.userForm.city,
+							Email:this.userForm.email,
+							TelAreaCode:this.userForm.areacode||'86',
 						}
 						//console.log('testEdit',params)
 						departInterence.editUser(params).then(res => {
@@ -1168,7 +1069,9 @@ export default {
 									post:'',
 									mobile:'',
 									auth:0,
-									status:1
+									status:1,
+									email:'',
+									areacode:'86',
 								}
 								this.getTableUser();
 							}
@@ -1208,7 +1111,9 @@ export default {
 					post:'',
 					mobile:'',
 					auth:'无',
-					status:1
+					status:1,
+					email:'',
+					areacode:'86',
 				},
 				this.$refs.addUserDialog.$refs.userForm.resetFields();//重置校验
 				this.isAddUser = false;
@@ -1300,14 +1205,16 @@ export default {
 				mobile:item.Mobile,
 				auth:item.Authority,
 				status:item.Enabled,
-				direct:direct
+				direct:direct,
+				email:item.Email,
+				areacode:item.TelAreaCode||'86'
 			}
 			this.hasEmployeeNo=!!item.EmployeeId
 			this.isAddUser = true;
 		},
 		/* 删除用户 */
 		delUser(item) {
-			this.$confirm('是否确认删除该用户?','提示',{
+			this.$confirm(`是否确认删除用户【${item.AdminName}】`,'提示',{
 				type:'warning'
 			}).then(() => {
 				departInterence.delUser({

+ 132 - 0
src/views/system_manage/etaMenu_manage/components/ChoosedIconDialog.vue

@@ -0,0 +1,132 @@
+<template>
+    <div class="choosed-icon-wrap">
+        <el-dialog
+            :visible.sync="isShowIconDialog"
+            :close-on-click-modal="false"
+            :modal-append-to-body='false'
+            title="选择图标"
+            @close="$emit('close')"
+            width="420px"
+            v-dialogDrag
+            center
+        >
+            <div class="dialog-container-wrap">
+                <div class="top">
+                    <el-upload action="" accept="image/*" 
+                        :http-request="handleUploadImg" 
+                        :show-file-list="false"
+                    >
+                        <el-button size="small">选择文件</el-button>
+                        <span>支持上传图标</span>
+                    </el-upload>
+                    
+                    
+                </div>
+                <div class="icon-box">
+                    <div class="icon-item" :class="{'active':icon.IconPath===choosedIcon}" 
+                        v-for="icon in iconList" :key="icon.IconId"
+                        @click.stop="choosedIcon = icon.IconPath">
+                        <img :src="icon.IconPath">
+                    </div>
+                </div>
+                <div class="btn-wrap" style="text-align: center;margin-bottom: 25px;">
+                    <el-button type="primary" plain  @click="$emit('close')">取消</el-button>
+                    <el-button type="primary"  style="margin-left:50px;" @click="saveIcon">保存</el-button>
+                </div>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import {menuConfigInterface} from '@/api/modules/etaMenuApi';
+import {bannerupload} from '@/api/api.js';
+export default {
+    props:{
+        isShowIconDialog:{
+            type:Boolean,
+            default:false
+        }
+    },
+    data() {
+        return {
+            iconList:[],
+            choosedIcon:''
+        };
+    },
+    watch:{
+        isShowIconDialog(newVal){
+            if(newVal){
+                this.getIconList()
+            }
+        }
+    },
+    methods: {
+        getIconList(){
+            menuConfigInterface.getMenuIconList().then(res=>{
+                if(res.Ret!==200) return 
+                this.iconList = res.Data||[]
+            })
+        },
+        async handleUploadImg(e){
+            if(!['image/png','image/jpeg'].includes(e.file.type)){
+                this.$message.warning('仅支持png、jpg格式的图片')
+                return
+            }
+            if(e.file.size>50*1024){
+                this.$message.warning('图标文件大小不能超过50kb')
+                return 
+            }
+            let form = new FormData()
+            form.append("file", e.file)
+            const res = await bannerupload(form)
+            if(res.Ret===200){
+                await menuConfigInterface.addMenuIcon({
+                    IconPath:res.Data.ResourceUrl
+                })
+                this.getIconList()
+            }
+        },
+        saveIcon(){
+            if(!this.choosedIcon){
+                this.$message.warning('请选择图标')
+                return
+            }
+            this.$emit('save',this.choosedIcon)
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.choosed-icon-wrap{
+    .top{
+        span{
+            margin-left: 15px;
+            color: #DCDCDC;
+        }
+    }
+    .icon-box{
+        margin: 20px 0;
+        border:1px dashed #DCDCDC;
+        padding:20px;
+        display: flex;
+        flex-wrap: wrap;
+        gap:20px;
+        max-height: 256px;
+        overflow-y: auto;
+        .icon-item{
+            width:30px;
+            height:30px;
+            cursor: pointer;
+            img{
+                width: 100%;
+            }
+            &:hover,&.active{
+                background-color: antiquewhite;
+                border-radius: 50%;
+            }
+        }
+    }
+}
+</style>

+ 247 - 0
src/views/system_manage/etaMenu_manage/components/ModifyMenuDialog.vue

@@ -0,0 +1,247 @@
+<template>
+    <div class="modify-menu-wrap">
+        <el-dialog
+            :visible.sync="isShowMenuDialog"
+            :close-on-click-modal="false"
+            :modal-append-to-body='false'
+            :title="form.MenuId?'编辑菜单':'添加菜单'"
+            @close="$emit('close')"
+            width="820px"
+            v-dialogDrag
+            center
+        >
+            <div class="dialog-container-wrap">
+                <el-form :model="form" :rules="rules" label-width="80px" :hide-required-asterisk="true" ref="menuForm">
+                    <el-form-item label="菜单类型" prop="MenuType">
+                        <el-radio-group v-model="form.MenuType" :disabled="form.MenuId">
+                            <el-radio :label="0" :disabled="isMenuDisabled">菜单</el-radio>
+                            <el-radio :label="1" :disabled="isbtnDisabled">按钮</el-radio>
+                            <el-radio :label="2" :disabled="isbtnDisabled">字段</el-radio>
+                        </el-radio-group>
+                    </el-form-item>
+                    <el-form-item label="上级菜单" prop="ParentId">
+                        <el-cascader v-model="form.ParentId"
+                            :options="menuList"
+                            :props="menuProps"
+                            :disabled="openType!=='add'"
+                        >
+                        </el-cascader>
+                    </el-form-item>
+                    <el-form-item :label="nameLabel" prop="Name">
+                        <el-input v-model="form.Name"></el-input>
+                    </el-form-item>
+                    <template v-if="form.MenuType===0">
+                        <el-form-item label="菜单图标" prop="Name" v-if="form.treeLevel===0">
+                            <div class="icon-wrap">
+                                <img :src="form.IconPath" v-if="form.IconPath">
+                                <el-button @click="isShowIconDialog = true">选择图标</el-button>
+                            </div>
+                        </el-form-item>
+                        <el-form-item label="路由地址" prop="Path">
+                            <el-input v-model="form.Path"></el-input>
+                            <el-tooltip effect="dark" content="页面跳转路径" placement="right">
+                                <span class="hint-text">
+                                    <i class="el-icon-warning-outline"></i>
+                                </span>
+                            </el-tooltip>
+                        </el-form-item>
+                        <el-form-item label="组件地址" prop="Component">
+                            <el-input v-model="form.Component"></el-input>
+                            <el-tooltip effect="dark" content="代码中页面地址" placement="right">
+                                <span class="hint-text">
+                                    <i class="el-icon-warning-outline"></i>
+                                </span>
+                            </el-tooltip>
+                        </el-form-item>
+                    </template>
+                    <el-form-item label="按钮ID" prop="ButtonCode" v-if="form.MenuType!==0">
+                        <el-input v-model="form.ButtonCode"></el-input>
+                    </el-form-item>
+                    <el-form-item label="显示排序" prop="Sort">
+                        <el-input v-model="form.Sort" type="number" :min="0"></el-input>
+                    </el-form-item>
+                    <el-form-item label="是否隐藏" prop="Hidden">
+                        <el-radio-group v-model="form.Hidden">
+                            <el-radio :label="0">显示</el-radio>
+                            <el-radio :label="1">隐藏</el-radio>
+                        </el-radio-group>
+                    </el-form-item>
+                </el-form>
+                <div class="btn-wrap" style="text-align: center;margin-bottom: 25px;">
+                    <el-button type="primary" plain style="width:200px;" @click="$emit('close')">取消</el-button>
+                    <el-button type="primary"  style="margin-left:50px;width:200px;" @click="saveMenu">保存</el-button>
+                </div>
+            </div>
+        </el-dialog>
+        <ChoosedIconDialog 
+            :isShowIconDialog="isShowIconDialog"
+            @save="(e)=>{form.IconPath = e;isShowIconDialog = false}"
+            @close="isShowIconDialog = false"
+        />
+    </div>
+</template>
+
+<script>
+import ChoosedIconDialog from './ChoosedIconDialog.vue';
+
+export default {
+    props: {
+        formData: {
+            type: Object,
+            default: {}
+        },
+        isShowMenuDialog: {
+            type: Boolean,
+            default: false
+        },
+        etaMenu: {
+            type: Array,
+            default: []
+        },
+        openType: {
+            type: String,
+            default: 'add'
+        }
+    },
+    data() {
+        return {
+            form: {
+                MenuType: 0,
+                ParentId: 0,
+                Name: '',
+                IconPath: '',
+                Path: '',
+                Component: '',
+                Sort: 0,
+                Hidden: 0,
+                ButtonCode: '',
+                treeLevel: 0
+            },
+            rules: {
+                ParentId:[{required:true,message:'请选择上级菜单'}],
+                Name:[{required:true,message:'请输入菜单标题'}],
+                IconPath:[{required:true,message:'请选择菜单图标'}],
+                Path:[{required:true,message:'请输入路由地址'}],
+                Component:[{required:true,message:'请输入组件地址'}],
+                Sort:[{required:true,message:'请输入显示排序'}],
+                ButtonCode:[{required:true,message:'请输入按钮ID'}]
+            },
+            menuList: [{
+                    MenuId: -1,
+                    Name: '无'
+                }],
+            menuProps: {
+                value: 'MenuId',
+                label: 'Name',
+                children: 'Children',
+                checkStrictly: true,
+                emitPath: false,
+            },
+            isShowIconDialog: false,
+        };
+    },
+    watch: {
+        isShowMenuDialog(newVal) {
+            if (newVal) {
+                this.form = this.$options.data().form;
+                this.menuList = this.$options.data().menuList;
+                this.initForm();
+                this.$nextTick(()=>{
+                    this.$refs.menuForm&&this.$refs.menuForm.clearValidate();
+                })
+            }
+        },
+        'form.MenuType': {
+            handler(newVal) {
+                this.changeListLevel(newVal);
+            },
+            deep: true
+        }
+    },
+    computed: {
+        //菜单类型-菜单 是否禁用
+        isMenuDisabled() {
+            return this.form.treeLevel > 1 && this.openType !== 'add';
+        },
+        //菜单类型-按钮、字段 是否禁用
+        isbtnDisabled() {
+            return this.form.treeLevel === 1 && this.openType !== 'add';
+        },
+        nameLabel(){
+            const nameMap = {
+                0:'菜单标题',
+                1:'按钮名称',
+                2:'字段名称'
+            }
+            return nameMap[this.form.MenuType]||'菜单标题'
+        },
+    },
+    methods: {
+        initForm() {
+            this.menuList = [...this.menuList, ..._.cloneDeep(this.etaMenu)];
+            if (this.openType === 'addNext') {
+                this.form.ParentId = this.formData.ParentId;
+                this.form.treeLevel = this.formData.treeLevel;
+            }
+            if (this.openType === 'edit') {
+                this.form = _.cloneDeep(this.formData);
+            }
+            if (this.form.treeLevel > 1 && this.openType !== 'edit') {
+                this.form.MenuType = 1;
+            }
+            if(this.form.treeLevel===0 && this.openType !== 'add'){
+                this.form.ParentId = -1
+            }
+        },
+        saveMenu() {
+            //检验表单
+            this.$refs.menuForm.validate((valid)=>{
+                if(valid){
+                    this.$emit(this.form.MenuId ? 'edit' : 'add', this.form);
+                }
+            })
+            
+        },
+        changeListLevel(level) {
+            if (level === 0) {
+                this.menuList = this.menuList.map(m => {
+                    if (m.Children) {
+                        delete m.Children;
+                    }
+                    return m;
+                });
+            }
+            else {
+                this.menuList = [...this.$options.data().menuList, ..._.cloneDeep(this.etaMenu)];
+            }
+        }
+    },
+    components: { ChoosedIconDialog }
+};
+</script>
+
+<style lang="scss">
+.modify-menu-wrap{
+    .dialog-container-wrap{
+        display: flex;
+        flex-direction: column;
+        .el-form{
+            align-self: center;
+            .el-form-item{
+                .el-input{
+                    width: 315px;
+                }
+                .icon-wrap{
+                    display: flex;
+                    align-items: center;
+                    img{
+                        width:24px;
+                        height: 24px;
+                        margin-right: 15px;
+                    }
+                }
+            }
+        }
+    }
+}
+</style>

+ 205 - 0
src/views/system_manage/etaMenu_manage/etaMenuConfig.vue

@@ -0,0 +1,205 @@
+<template>
+    <div class="eta-menu-config-wrap">
+        <div class="menu-top">
+            <el-button type="primary" @click="handleModifyMenu('add',{})">添加菜单</el-button>
+            <el-input placeholder="请输入菜单名称" prefix-icon="el-icon-search" clearable
+                v-model="Keyword" @input="getMenuData"></el-input>
+        </div>
+        <div class="menu-table">
+            <el-table border
+                :data="tableData"
+                row-key="MenuId"
+                :tree-props="{children:'Children'}"
+            >
+                <el-table-column v-for="column in tableColumns" :key="column.key"
+                    header-align="center"
+                    :align="column.key==='Name'?'':'center'"
+                    :prop="column.key"
+                    :label="column.label">
+                    <template slot-scope="{row}">
+                        <!-- 菜单名称 -->
+                        <div class="menu-name" v-if="column.key==='Name'">
+                            <span>{{row[column.key]}}</span>
+                        </div>
+                        <!-- 图标 -->
+                        <div class="menu-icon" v-else-if="column.key==='IconPath'">
+                            <img :src="row[column.key]" v-if="row[column.key]" style="width:24px;height:24px;">
+                            <span v-else>-</span>
+                        </div>
+                        <!-- 状态 -->
+                        <div class="menu-status" v-else-if="column.key==='Hidden'">
+                            <span>{{row[column.key]===0?'显示':'隐藏'}}</span>
+                        </div>
+                        <div v-else>
+                            <span>{{row[column.key]}}</span>
+                        </div>
+                    </template>
+                </el-table-column>
+                <el-table-column align="center" prop="操作">
+                    <template slot-scope="{row}">
+                        <el-button type="text" @click="handleModifyMenu('addNext',row)">添加子项</el-button>
+                        <el-button type="text" @click="handleModifyMenu('edit',row)">编辑</el-button>
+                        <el-button type="text" style="color:#FF0000;" @click="deleteMenu(row)">删除</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </div>
+        <ModifyMenuDialog 
+            :isShowMenuDialog="isShowMenuDialog"
+            :formData="formData"
+            :etaMenu="tableData"
+            :openType="openType"
+            @add="(params)=>{modifyMenu(params,'addMenu')}"
+            @edit="(params)=>{modifyMenu(params,'editMenu')}"
+            @close="()=>{formData = {};isShowMenuDialog = false;}"
+        />
+    </div>
+</template>
+
+<script>
+import {menuConfigInterface} from '@/api/modules/etaMenuApi';
+import ModifyMenuDialog from './components/ModifyMenuDialog.vue';
+export default {
+    data() {
+        return {
+            Keyword: '',
+            tableColumns: [{
+                    label: '菜单名称',
+                    key: 'Name',
+                }, {
+                    label: '图标',
+                    key: 'IconPath',
+                }, {
+                    label: '状态',
+                    key: 'Hidden',
+                }, {
+                    label: '创建时间',
+                    key: 'CreateTime',
+                }],
+            tableData: [{}],
+            formData: {},
+            openType:'add',
+            isShowMenuDialog: false,
+        };
+    },
+    methods: {
+        getMenuData() {
+            menuConfigInterface.getMenuList({
+                Keyword: this.Keyword
+            }).then(res => {
+                if (res.Ret !== 200)
+                    return;
+                this.tableData = res.Data.List || [];
+                this.tableData.forEach(d=>{
+                    this.formatData(d,0)
+                })
+            });
+        },
+        //给data加上层级
+        formatData(data,level){
+            data.treeLevel = level
+            if(data.Children && data.Children.length){
+                data.Children = data.Children.map(i=>{
+                    return this.formatData(i,level+1)
+                })
+            }
+            return data
+        },
+        handleModifyMenu(type, data) {
+            if (type === 'addNext') {
+                this.formData.ParentId = data.MenuId;
+                this.formData.treeLevel = data.treeLevel+1
+            }
+            else if (type === 'edit') {
+                this.formData = data;
+            }
+            else {
+                this.formData = {treeLevel:0};
+            }
+            this.openType = type
+            this.isShowMenuDialog = true;
+        },
+        deleteMenu(data){
+            const hintTextMap = {
+                0:'菜单及子项',
+                1:'按钮',
+                2:'字段'
+            }
+            this.$confirm(`删除后不可恢复,确认删除该${hintTextMap[data.MenuType]}吗?`,'提示',{
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(()=>{
+                menuConfigInterface.removeMenu({MenuId:data.MenuId}).then(res=>{
+                    if(res.Ret!==200) return 
+                    this.$message.success('删除成功')
+                    this.getMenuData()
+                })
+            }).catch(()=>{})
+            
+        },
+        modifyMenu(params,type){
+            let InterfaceParams = {}
+            if(params.MenuType===0){
+                const {ParentId,MenuType,Name,IconPath,Sort,Path,Component,Hidden} = params
+                InterfaceParams = {
+                    ParentId:ParentId===-1?0:ParentId,
+                    MenuType,
+                    Name,
+                    IconPath,
+                    Sort:Number(Sort),
+                    Path,
+                    Component,
+                    Hidden
+                }
+            }else{
+                const {ParentId,MenuType,Name,Sort,Hidden,ButtonCode} = params
+                InterfaceParams = {
+                    ParentId:ParentId===-1?0:ParentId,
+                    MenuType,
+                    Name,
+                    Sort:Number(Sort),
+                    Hidden,
+                    ButtonCode
+                }
+            }
+            if(type==='editMenu'){
+                InterfaceParams = {...{MenuId:params.MenuId},...InterfaceParams}
+            }
+            menuConfigInterface[type](InterfaceParams).then(res=>{
+                    if(res.Ret!==200) return 
+                    this.$message.success(`${type==='addMenu'?'添加':'编辑'}成功`)
+                    this.getMenuData()
+                    this.isShowMenuDialog = false
+                })
+        },
+        editMenu(params){}
+    },
+    mounted() {
+        this.getMenuData();
+    },
+    components: { ModifyMenuDialog }
+};
+</script>
+
+<style scoped lang="scss">
+.eta-menu-config-wrap{
+    .menu-top{
+        padding:20px;
+        background-color: #fff;
+        display: flex;
+        justify-content: space-between;
+        .el-input{
+            width:260px;
+        }
+    }
+    .menu-table{
+        margin-top: 20px;
+        padding:20px;
+        background-color: #fff;
+        .menu-name{
+            display: inline-block;
+        }
+    }
+}
+</style>

+ 22 - 6
src/views/system_manage/mixin/departManageMixin.js

@@ -5,7 +5,8 @@
  */
 import { departInterence } from '@/api/api.js';
 import http from '@/api/http.js';
-import AddUserDialog from '../components/addUserDialog.vue'
+import AddUserDialog from '../components/addUserDialog.vue';
+import{checkPassWord} from '@/utils/commonOptions';
 
 export default {
     components:{AddUserDialog},
@@ -13,10 +14,13 @@ export default {
         const validatePass = (rule,value,callback)=>{
             if(value===''){
                 callback(new Error('请输入新密码'))
+            }
+            if(this.resetForm.check!==''){
+                this.$refs.resetForm.validateField('check')
+            }
+            if(!checkPassWord(value)){
+                callback(new Error('密码要求8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型'))
             }else{
-                if(this.resetForm.check!==''){
-                    this.$refs.resetForm.validateField('check')
-                }
                 callback()
             }
         }
@@ -25,8 +29,9 @@ export default {
                 callback(new Error('请输入确认密码'))
             }else if(value!==this.resetForm.password){
                 callback(new Error('两次输入的密码不一致'))
+            }else{
+                callback()
             }
-            callback()
         }
         return {
             isExtraUserFormItemShow: false, //是否显示额外的用户表单项
@@ -53,7 +58,10 @@ export default {
                 check:''
             },
             resetDepart:'',
-            modifyAdminId:0
+            modifyAdminId:0,
+            areaCode:[],
+            modifyAdminName:'',
+
 
         }
     },
@@ -175,6 +183,7 @@ export default {
             if(type==='show'){
                 this.$refs.resetForm&&this.$refs.resetForm.clearValidate()
                 this.modifyAdminId = data.AdminId
+                this.modifyAdminName=data.AdminName
                 this.isResetPasswordShow = true
             }else{
                 this.$refs.resetForm.validate((valid)=>{
@@ -208,6 +217,7 @@ export default {
                 data.TeamId ?departArr.push(data.TeamId):''
                 this.resetDepart = departArr
                 this.modifyAdminId = data.AdminId
+                this.modifyAdminName=data.AdminName
                 this.isMoveDepartShow = true
             }else{
                 //选择分组接口
@@ -223,6 +233,12 @@ export default {
                     this.getTableUser();
                 })
             }
+        },
+        getAreaCode(){
+            departInterence.getPhoneAreaCode().then(res=>{
+                if(res.Ret!==200) return 
+                this.areaCode = res.Data||[]
+            })
         }
     }