瀏覽代碼

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_scrm_companyUI

ct 1 天之前
父節點
當前提交
e39a793e4e

+ 12 - 0
src/api/company/companyUser.js

@@ -238,3 +238,15 @@ export function setIsRegisterMember(status, data) {
     data: data
   })
 }
+
+// 开关是否允许所有方式注册会员
+export function isAllowedAllRegister(status, data) {
+  return request({
+    url: '/company/user/allowedAllRegister',
+    method: 'put',
+    params: status,
+    data: data
+  })
+}
+
+

+ 28 - 1
src/api/company/pay.js

@@ -9,4 +9,31 @@ export function weixinPay(query) {
     params: query
   })
 }
- 
+
+/**
+ * 微信二维码支付
+ * @param query
+ * @returns {*}
+ */
+export function wxQrPay(query) {
+  return request({
+    url: '/company/companyRecharge/wxRecharge',
+    method: 'post',
+    data: query
+  })
+}
+
+/**
+ * 查询订单
+ * @param orderNo
+ * @returns {*}
+ */
+export function queryOrder(orderNo){
+  return request({
+    url: '/company/companyRecharge/queryOrder',
+    method: 'get',
+    params: {
+      orderNo: orderNo
+    }
+  })
+}

+ 9 - 0
src/api/course/courseAnswerlogs.js

@@ -60,3 +60,12 @@ export function exportLogs(query) {
     params: query
   })
 }
+
+// 导出我的答题日志
+export function exportMyLogs(query) {
+  return request({
+    url: '/course/courseAnswerLog/myExport',
+    method: 'get',
+    params: query
+  })
+}

+ 8 - 0
src/api/crm/customer.js

@@ -218,3 +218,11 @@ export function allOperation(data) {
   })
 }
 
+
+
+export function switchToTop(customerId) {
+  return request({
+    url: '/crm/customer/switchToTop/' + customerId,
+    method: 'post'
+  })
+}

+ 9 - 0
src/api/crm/customerLevel.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export const customerLevelOptions = (query) => {
+  return request({
+    url: "/crm/customerLevel/getCustomerLevelOption",
+    method: "get",
+    params: query,
+  });
+};

+ 53 - 0
src/api/store/userOnlineState.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询用户上线情况列表
+export function listUserOnlineState(query) {
+  return request({
+    url: '/store/userOnlineState/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询用户上线情况详细
+export function getUserOnlineState(userId) {
+  return request({
+    url: '/store/userOnlineState/' + userId,
+    method: 'get'
+  })
+}
+
+// 新增用户上线情况
+export function addUserOnlineState(data) {
+  return request({
+    url: '/store/userOnlineState',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改用户上线情况
+export function updateUserOnlineState(data) {
+  return request({
+    url: '/store/userOnlineState',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除用户上线情况
+export function delUserOnlineState(userId) {
+  return request({
+    url: '/store/userOnlineState/' + userId,
+    method: 'delete'
+  })
+}
+
+// 导出用户上线情况
+export function exportUserOnlineState(query) {
+  return request({
+    url: '/store/userOnlineState/export',
+    method: 'get',
+    params: query
+  })
+}

+ 10 - 1
src/api/user/fsUser.js

@@ -1,7 +1,7 @@
 import request from '@/utils/request'
 import {params} from "svgo/plugins/prefixIds";
 
-// 查询用户列表
+// 查询用户列表(公司的会员)
 export function listUser(query) {
   return request({
     url: '/user/fsUser/list',
@@ -10,6 +10,15 @@ export function listUser(query) {
   })
 }
 
+// 查询用户列表(销售的会员)
+export function myListUser(query) {
+  return request({
+    url: '/user/fsUser/myList',
+    method: 'post',
+    data: query
+  })
+}
+
 // 查询用户详细
 export function getUser(userId) {
   return request({

+ 104 - 51
src/views/company/companyRecharge/doRecharge.vue

@@ -7,26 +7,22 @@
              <span style="font-size:20px;color:red;">{{money}}</span>元
           </el-form-item>
           <el-form-item label="充值金额" prop="money">
-            <el-input v-model="form.money" style="width:200px" placeholder="请输入充值金额" />
+            <el-input-number  v-model="form.money" style="width:200px" placeholder="请输入充值金额" />
           </el-form-item>
           <el-form-item label="支付方式" prop="payType">
                <div class="radio">
                  <div class="radio-item">
                      <el-radio v-model="form.payType" :label=1><img class="radio-img" src="../../../assets/image/WeChat_icon30.png">微信</el-radio>
                  </div>
-                 <div class="radio-item">
-                     <el-radio v-model="form.payType" :label=2><img class="radio-img" src="../../../assets/image/alipay_icon30.png">支付宝</el-radio>
-                 </div>
                </div>
             </el-form-item>
             <div class="footer-btn">
               <el-button type="primary" @click="submitForm">充值</el-button>
             </div>
-            
         </el-form>
       </el-tab-pane>
     </el-tabs>
-    <el-dialog :title="payTitle" :visible.sync="payVisible" top="10vh" width="550px" class="my-dialog">
+    <el-dialog :title="payTitle" :visible.sync="payVisible" top="10vh" width="550px" class="my-dialog" @close="handleDialogClose">
       <div class="pay-dialog-cont">
         <div class="price">
           <span class="label">应付金额</span>
@@ -36,7 +32,6 @@
         <div class="order-sn">订单编号:{{orderNo}}</div>
         <div class="code-box">
           <div class="qrcode" ref="qrCodeUrl"></div>
-          <!-- <img src="../../assets/image/qr.png" alt=""> -->
         </div>
         <div class="tip-box">
           <span>请使用<span class="orange">微信</span>扫一扫</span>
@@ -44,40 +39,68 @@
         </div>
       </div>
     </el-dialog>
-     
+
   </div>
 </template>
 
 <script>
 import { listCompanyRecharge, getCompanyRecharge, delCompanyRecharge, addCompanyRecharge, updateCompanyRecharge, exportCompanyRecharge } from "@/api/company/companyRecharge";
 import { getCompanyInfo } from "@/api/company/company";
-import { weixinPay } from "@/api/company/pay";
+import {queryOrder, weixinPay, wxQrPay} from "@/api/company/pay";
 import QRCode from 'qrcodejs2'
 
 export default {
   name: "CompanyRecharge",
   data() {
     return {
+      qrLoading: false,
+      qrPayUrl: '',
       orderNo:"",
-      payVisible: false, // 支付弹窗
+      payVisible: false,
       payTitle: '微信支付',
       toPayFlag:true,
       activeName:"first",
+      timer: null,
       money:0,
-      // 表单参数
       form: {
         payType:1,
       },
-      // 表单校验
       rules: {
         money: [
           { required: true, message: "金额不能为空", trigger: "blur" },
+          {
+            validator: (rule, value, callback) => {
+              if (value === '' || value === undefined || value === null) {
+                callback();
+                return;
+              }
+              const numValue = Number(value);
+              if (isNaN(numValue)) {
+                callback(new Error('请输入有效的金额'));
+                return;
+              }
+              if (numValue < 0.01) {
+                callback(new Error('最小充值金额为0.01元'));
+                return;
+              }
+              if (numValue > 10000) {
+                callback(new Error('最大充值金额为10000元'));
+                return;
+              }
+              if (!/^\d+(\.\d{1,2})?$/.test(value.toString())) {
+                callback(new Error('金额最多支持两位小数'));
+                return;
+              }
+              callback();
+            },
+            trigger: 'blur'
+          }
         ],
       }
     };
   },
   created() {
-     
+
     this.getDicts("company_pay_status").then((response) => {
       this.statusOptions = response.data;
     });
@@ -88,53 +111,83 @@ export default {
       this.money = response.data.money;
     });
   },
+  beforeDestroy() {
+    this.clearTimer();
+  },
   methods: {
-    creatQrCode(url) {
-      var qrcode = new QRCode(this.$refs.qrCodeUrl, {
-          text: url, // 需要转换为二维码的内容
-          width: 200,
-          height: 200,
-          colorDark: '#000000',
-          colorLight: '#ffffff',
-          correctLevel: QRCode.CorrectLevel.H
-      })
+    clearTimer() {
+      if (this.timer) {
+        clearInterval(this.timer);
+        this.timer = null;
+      }
     },
-    toPay(orderNo) {
-      if(this.form.payType == 1) {
-        this.payTitle = '微信支付'
-        var param={orderNo:orderNo,orderType:1};
-        weixinPay(param).then(response => {
-          this.creatQrCode(response.qr)
-        });
-        this.payVisible = true
-        
-      } else {
-        this.payTitle = '支付宝支付'
+    /**
+     * 创建二维码
+     * @param {string} url - 二维码内容URL
+     */
+    creatQrCode(url) {
+      // 首先清空容器,避免重复创建
+      if (this.$refs.qrCodeUrl) {
+        this.$refs.qrCodeUrl.innerHTML = '';
       }
-      
+
+      // 使用nextTick确保DOM已更新
+      this.$nextTick(() => {
+        try {
+          if (this.$refs.qrCodeUrl) {
+            new QRCode(this.$refs.qrCodeUrl, {
+              text: url, // 需要转换为二维码的内容
+              width: 200,
+              height: 200,
+              colorDark: '#000000',
+              colorLight: '#ffffff',
+              correctLevel: QRCode.CorrectLevel.H
+            });
+            console.log('二维码创建成功');
+          } else {
+            console.error('二维码容器不存在');
+            this.$message.error('二维码生成失败:容器不存在');
+          }
+        } catch (error) {
+          console.error('二维码创建失败:', error);
+          this.$message.error('二维码生成失败,请重试');
+        }
+      });
+    },
+    handleDialogClose(){
+      clearInterval(this.timer);
+      this.timer=null;
     },
     /** 提交按钮 */
     submitForm() {
-      this.msgError("未开放此功能");
-      return;
       var that=this;
-       if(this.orderNo!=""){
-        this.payVisible = true
-        return;
-      }
-      if(!this.toPayFlag){
-        return;
-      }
       this.$refs["form"].validate(valid => {
         if (valid) {
           that.toPayFlag=false;
-            addCompanyRecharge(this.form).then(response => {
-              if (response.code === 200) {
-                
-                that.orderNo=response.rechargeNo
-                that.toPay(response.rechargeNo);
-              }
-            });
+          wxQrPay({
+            amount: this.form.money
+          }).then(res=>{
+            if(res.code === 200) {
+              this.payVisible = true;
+              this.creatQrCode(res.data.qrLink);
+              this.orderNo = res.data.orderNo;
+
+
+              // 轮询订单是否完成
+              this.timer = setInterval(()=>{
+                queryOrder(res.data.orderNo).then(res=>{
+                  if(res.code === 200 && res.data.transactionId != null) {
+                    this.$message.success("支付成功!");
+                    clearInterval(this.timer);
+                    this.timer=null;
+                    setTimeout(()=>{
+                      window.location.reload()
+                    },2000)
+                  }
+                })
+              },1000)
+            }
+          })
         }
       });
     },
@@ -148,7 +201,7 @@ export default {
 .radio{
   display: flex;
   align-items: center;
-   
+
 
 }
 .radio-item{

+ 57 - 2
src/views/company/companyUser/index.vue

@@ -91,6 +91,15 @@
               @click="handleSetRegister"
             >设置单独注册会员</el-button>
           </el-col>
+          <el-col :span="1.5">
+            <el-button
+              type="primary"
+              plain
+              size="mini"
+              :disabled="multiple"
+              @click="handleAllowedAllRegister"
+            >允许注册会员开关</el-button>
+          </el-col>
           <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
         </el-row>
 
@@ -155,6 +164,12 @@
               <span>{{ parseTime(scope.row.createTime) }}</span>
             </template>
           </el-table-column>
+          <el-table-column label="允许注册会员" align="center" prop="isNeedRegisterMember" width="80px">
+            <template slot-scope="scope">
+              <el-tag
+                :type="scope.row.isAllowedAllRegister === 1 ? 'success' : 'info'">{{scope.row.isAllowedAllRegister === 1 ? '是' : '否' }}</el-tag>
+            </template>
+          </el-table-column>
           <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
             <template slot-scope="scope">
               <el-button
@@ -347,7 +362,7 @@
         </el-row>
         <el-row>
           <el-col :span="24">
-            <el-form-item label="数据权限">
+            <el-form-item label="数据权限" prop="userType">
               <el-radio-group v-model="form.userType">
                 <el-radio v-for="dict in userTypeOptions" :key="dict.dictValue" :label="dict.dictValue">{{dict.dictLabel}}</el-radio>
               </el-radio-group>
@@ -406,6 +421,19 @@
         <el-button @click="registerOpen = false">取 消</el-button>
       </div>
     </el-dialog>
+
+    <!-- 是否允许所有方式注册会员弹窗 -->
+    <el-dialog title="允许注册会员" :visible.sync="allowedAllRegisterOpen" width="400px" append-to-body>
+      <el-form ref="registerForm" :model="allowedAllRegisterForm" label-width="180px">
+        <el-form-item label="是否允许注册会员">
+          <el-switch v-model="allowedAllRegisterForm.status" active-value="true" inactive-value="false"></el-switch>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitAllowedAllRegisterForm">确 定</el-button>
+        <el-button @click="allowedAllRegisterOpen = false">取 消</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -422,7 +450,8 @@ import {
   importTemplate,
   generateSubDomain,
   getCitysAreaList, updateCompanyUserAreaList,
-  setIsRegisterMember
+  setIsRegisterMember,
+  isAllowedAllRegister
 } from '@/api/company/companyUser'
 import { getToken } from "@/utils/auth";
 import { treeselect } from "@/api/company/companyDept";
@@ -560,6 +589,9 @@ export default {
             trigger: "blur",
           },
         ],
+        userType: [
+          { required: true, message: "数据权限不能为空", trigger: "change" },
+        ],
         domain: [
           {
             pattern: /^(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,})|(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))$/,
@@ -572,6 +604,11 @@ export default {
       registerForm: {
         status: false
       },
+      // 是否允许注册会员开关
+      allowedAllRegisterOpen: false,
+      allowedAllRegisterForm: {
+        status: true
+      },
     };
   },
   watch: {
@@ -850,6 +887,7 @@ export default {
         this.open = true;
         this.title = "添加员工";
         this.form.password = null;
+        this.form.userType = "01"; //普通用户
       });
     },
     qwBind(row){
@@ -1122,6 +1160,23 @@ export default {
         }
       });
     },
+
+    /** 开关是否允许所有方式注册会员 */
+    handleAllowedAllRegister() {
+      this.allowedAllRegisterOpen = true;
+      // this.allowedAllRegisterForm.status = true;
+    },
+    // 提交
+    submitAllowedAllRegisterForm(){
+      isAllowedAllRegister({status: this.allowedAllRegisterForm.status}, this.ids).then(response => {
+        if (response.code === 200) {
+          this.msgSuccess("操作成功");
+          this.allowedAllRegisterOpen = false;
+          this.getList();
+        }
+      });
+    },
+
   },
 };
 </script>

+ 27 - 16
src/views/course/courseAnswerlogs/index.vue

@@ -1,6 +1,15 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+      <el-form-item label="用户" prop="userName">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="请输入用户昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
       <el-form-item label="项目" prop="courseId">
         <el-select filterable  v-model="queryParams.project" placeholder="请选择项目"  clearable size="small">
           <el-option
@@ -32,7 +41,7 @@
         </el-select>
       </el-form-item>
       <el-form-item label="销售名称" prop="companyUserName">
-        <el-select v-model="queryParams.companyUserId" remote placeholder="请选择" filterable clearable  style="width: 100%;" @keyup.enter.native="handleQuery">
+        <el-select v-model="queryParams.companyUserId" remote placeholder="请输入" filterable clearable  style="width: 100%;" @keyup.enter.native="handleQuery">
           <el-option
             v-for="dict in companyUserList"
             :key="`${dict.nickName} - ${dict.userName}`"
@@ -72,20 +81,20 @@
       </el-form-item>
     </el-form>
 
-<!--    <el-row :gutter="10" class="mb8">-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="warning"-->
-<!--          plain-->
-<!--          icon="el-icon-download"-->
-<!--          size="mini"-->
-<!--          :loading="exportLoading"-->
-<!--          @click="handleExport"-->
-<!--          v-hasPermi="['course:courseAnswerLog:export']"-->
-<!--        >导出</el-button>-->
-<!--      </el-col>-->
-<!--      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>-->
-<!--    </el-row>-->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['course:courseAnswerLog:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
 
     <el-table border v-loading="loading" :data="logsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
@@ -170,6 +179,7 @@ export default {
         isRight: null,
         sTime:null,
         eTime:null,
+        userName: null,
       },
       //选择时间
       createTime:null,
@@ -260,6 +270,7 @@ export default {
         companyId: null,
         sTime:null,
         eTime:null,
+        userName: null,
       };
       this.resetForm("form");
     },
@@ -335,7 +346,7 @@ export default {
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有答题日志数据项?', "警告", {
+      this.$confirm('是否确认导出当前答题日志数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"

+ 28 - 17
src/views/course/courseAnswerlogs/myCourseAnswerlogs.vue

@@ -1,6 +1,15 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+      <el-form-item label="用户" prop="userName">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="请输入用户昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
       <el-form-item label="项目" prop="courseId">
         <el-select filterable  v-model="queryParams.project" placeholder="请选择项目"  clearable size="small">
           <el-option
@@ -52,20 +61,20 @@
       </el-form-item>
     </el-form>
 
-<!--    <el-row :gutter="10" class="mb8">-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="warning"-->
-<!--          plain-->
-<!--          icon="el-icon-download"-->
-<!--          size="mini"-->
-<!--          :loading="exportLoading"-->
-<!--          @click="handleExport"-->
-<!--          v-hasPermi="['course:courseAnswerLog:export']"-->
-<!--        >导出</el-button>-->
-<!--      </el-col>-->
-<!--      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>-->
-<!--    </el-row>-->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['course:courseAnswerLog:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
 
     <el-table border v-loading="loading" :data="logsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
@@ -95,7 +104,7 @@
 </template>
 
 <script>
-import { myListLogs, getLogs, delLogs, addLogs, updateLogs, exportLogs } from "@/api/course/courseAnswerlogs";
+import { myListLogs, getLogs, delLogs, addLogs, updateLogs, exportMyLogs } from "@/api/course/courseAnswerlogs";
 import { courseList, videoList } from '@/api/course/courseRedPacketLog'
 import {allListTagGroup} from "@/api/qw/tagGroup";
 import {listTag} from "@/api/qw/tag";
@@ -150,6 +159,7 @@ export default {
         isRight: null,
         sTime:null,
         eTime:null,
+        userName: null,
       },
       //选择时间
       createTime:null,
@@ -237,6 +247,7 @@ export default {
         companyId: null,
         sTime:null,
         eTime:null,
+        userName: null,
       };
       this.resetForm("form");
     },
@@ -312,13 +323,13 @@ export default {
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有答题日志数据项?', "警告", {
+      this.$confirm('是否确认导出当前答题日志数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(() => {
           this.exportLoading = true;
-          return exportLogs(queryParams);
+          return exportMyLogs(queryParams);
         }).then(response => {
           this.download(response.msg);
           this.exportLoading = false;

+ 2 - 1
src/views/course/courseWatchLog/index.vue

@@ -232,7 +232,8 @@ export default {
     });
     this.getList();
     this.getDicts("sys_course_watch_log_type").then(response => {
-      this.logTypeOptions = response.data;
+      console.log(response.data);
+      this.logTypeOptions = response.data.filter(item => item.dictLabel !== "待看课");
     });
     getUserList().then(res=>{
       if(res.code === 200) {

+ 30 - 5
src/views/course/courseWatchLog/statistics.vue

@@ -71,11 +71,11 @@
       <el-table-column label="发课时间" align="center" prop="createTime"/>
       <el-table-column label="项目" align="center" prop="projectName" />
       <el-table-column label="课程名称" align="center" prop="courseName" />
-      <el-table-column label="小节名称" align="center" prop="videoName" />
-      <el-table-column label="待看课" align="center" prop="type3" />
-      <el-table-column label="看课中" align="center" prop="type1" />
-      <el-table-column label="已完课" align="center" prop="type2" />
-      <el-table-column label="看课中断" align="center" prop="type4" />
+      <el-table-column label="小节名称" align="center" prop="videoName" width="260px"/>
+      <el-table-column label="待看课" align="center" prop="type3"  width="100px"/>
+      <el-table-column label="看课中" align="center" prop="type1"  width="100px"/>
+      <el-table-column label="已完课" align="center" prop="type2"  width="100px"/>
+      <el-table-column label="看课中断" align="center" prop="type4"  width="100px"/>
 
 
     </el-table>
@@ -157,6 +157,27 @@ export default {
     };
   },
   created() {
+    // 设置默认时间范围为今天到最近7天
+    const today = new Date();
+    const sevenDaysAgo = new Date();
+    sevenDaysAgo.setDate(today.getDate() - 7);
+
+    // 格式化日期为年-月-日格式
+    const formatDate = (date) => {
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, '0');
+      const day = String(date.getDate()).padStart(2, '0');
+      return `${year}-${month}-${day}`;
+    };
+    this.createTime = [
+      formatDate(sevenDaysAgo), // 7天前
+      formatDate(today)         // 今天
+    ];
+
+    // 设置查询参数的时间
+    this.queryParams.sTime = this.createTime[0];
+    this.queryParams.eTime = this.createTime[1];
+
     courseList().then(response => {
       this.courseLists = response.list;
     });
@@ -238,6 +259,10 @@ export default {
     },
     /** 查询短链课程看课记录列表 */
     getList() {
+      if (!this.queryParams.sTime || !this.queryParams.eTime) {
+        this.$message.error("请选择创建时间");
+        return;
+      }
       this.loading = true;
       statisticsList(this.queryParams).then(response => {
         this.courseWatchLogList = response.rows;

+ 2 - 1
src/views/course/courseWatchLog/watchLog.vue

@@ -371,7 +371,8 @@ export default {
     });
     this.getList();
     this.getDicts("sys_course_watch_log_type").then(response => {
-      this.logTypeOptions = response.data;
+      console.log(response.data);
+      this.logTypeOptions = response.data.filter(item => item.dictLabel !== "待看课");
     });
 
     this.getDicts("sys_company_or").then(response => {

+ 13 - 2
src/views/course/userWatchCourseStatistics/index.vue

@@ -45,6 +45,17 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['course:userWatchCourseStatistics:export']"
+        >导出</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -61,10 +72,10 @@
       <el-table-column label="会员数量" align="center" prop="userNum" />
       <el-table-column label="观看人数" align="center" prop="watchNum" />
       <el-table-column label="完播人数" align="center" prop="completeWatchNum" />
-      <el-table-column label="完播率(%)" align="center" prop="completeWatchRate" />
+      <el-table-column label="完播率" align="center" prop="completeWatchRatePercent" />
       <el-table-column label="答题人数" align="center" prop="answerNum" />
       <el-table-column label="正确人数" align="center" prop="answerRightNum" />
-      <el-table-column label="正确率(%)" align="center" prop="answerRightRate" />
+      <el-table-column label="正确率" align="center" prop="answerRightRatePercent" />
       <el-table-column label="红包领取数量" align="center" prop="redPacketNum" />
       <el-table-column label="红包领取总额" align="center" prop="redPacketAmount" />
     </el-table>

+ 1 - 2
src/views/course/userWatchCourseTotalStatistics/index.vue

@@ -72,7 +72,6 @@
           size="mini"
           :loading="exportLoading"
           @click="handleExport"
-          v-hasPermi="['course:userWatchCourseStatistics:export']"
         >导出</el-button>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
@@ -91,7 +90,7 @@
       <el-table-column label="会员数量" align="center" prop="userNum" />
       <el-table-column label="观看人数" align="center" prop="watchNum" />
       <el-table-column label="完播人数" align="center" prop="completeWatchNum" />
-      <el-table-column label="完播率(%)" align="center" prop="completeWatchRate" />
+      <el-table-column label="完播率" align="center" prop="completeWatchRatePercent" />
       <el-table-column label="红包领取个数" align="center" prop="redPacketNum" />
     </el-table>
 

+ 22 - 20
src/views/crm/components/addCustomerType.vue

@@ -1,10 +1,10 @@
 <template>
     <div>
             <el-form ref="form" :model="form" :rules="rules" label-width="100px">
-                <el-form-item label="客户类型" prop="customerType">
-                    <el-select v-model="form.customerType" placeholder="请选择客户类型" clearable size="small">
+                <el-form-item label="客户类型" prop="customerLevel">
+                    <el-select v-model="form.customerLevel" placeholder="请选择客户类型" clearable size="small">
                         <el-option
-                                v-for="item in typeOptions"
+                                v-for="item in customerLevelOptions"
                                 :key="item.dictValue"
                                 :label="item.dictLabel"
                                 :value="item.dictValue"
@@ -15,42 +15,45 @@
             <div class="footer">
                 <el-button type="primary" @click="submitForm">确 定</el-button>
             </div>
-       
+
     </div>
 </template>
-  
+
 <script>
      import { getCustomerDetails,updateCustomer  } from "@/api/crm/customer";
+     import {customerLevelOptions} from "@/api/crm/customerLevel";
     export default {
         name: "visit",
         data() {
             return {
-                 
-                typeOptions:[],
+
                 form: {
                     customerId:null,
-                    customerType:null,
-                 
+                    customerLevel:null,
                 },
                 // 表单校验
                 rules: {
-                    customerType: [
+                    customerLevel: [
                         { required: true, message: "类型不能为空", trigger: "change" }
                     ],
-         
-                }
-                 
+
+                },
+              customerLevelOptions: []
+
             };
         },
         created() {
-            this.getDicts("crm_customer_type").then((response) => {
-                this.typeOptions = response.data;
-            });
+            this.getCustomerLevelOptions()
         },
         methods: {
+          getCustomerLevelOptions(){
+            customerLevelOptions({status: 0}).then((response) => {
+              this.customerLevelOptions = response.data;
+            });
+          },
             reset(customer) {
                 this.form.customerId=customer.customerId;
-                this.form.customerType=customer.customerType.toString();
+                this.form.customerLevel=customer.customerLevel;
             },
             submitForm() {
                 this.$refs["form"].validate(valid => {
@@ -58,7 +61,7 @@
                         updateCustomer(this.form).then(response => {
                             if (response.code === 200) {
                                 this.msgSuccess("操作成功");
-                                
+
                                 this.$emit('close');
                             }
                         });
@@ -73,7 +76,7 @@
     height: 100%;
     background-color: #fff;
     padding: 20px;
-        
+
 }
 .footer{
     display: flex;
@@ -82,4 +85,3 @@
 }
 </style>
 
- 

+ 24 - 17
src/views/crm/components/addOrEditCustomer.vue

@@ -28,10 +28,10 @@
                 <el-form-item label="详细地址" prop="detailAddress">
                     <el-input v-model="form.detailAddress" placeholder="请输入详细地址" />
                 </el-form-item>
-                <el-form-item label="客户类型" prop="customerType">
-                    <el-select v-model="form.customerType" placeholder="请选择客户类型" clearable size="small">
+                <el-form-item label="客户类型" prop="customerLevel">
+                    <el-select v-model="form.customerLevel" placeholder="请选择客户类型" clearable size="small">
                         <el-option
-                            v-for="item in typeOptions"
+                            v-for="item in customerLevelOptions"
                             :key="item.dictValue"
                             :label="item.dictLabel"
                             :value="item.dictValue"
@@ -129,11 +129,12 @@
             </div>
     </div>
 </template>
-  
+
 <script>
     import { listCustomerExt } from "@/api/crm/customerExt";
     import { updateCustomer,addCustomer,addMyCustomer,getCustomerDetails   } from "@/api/crm/customer";
     import {getCitys} from "@/api/store/city";
+    import {customerLevelOptions} from "@/api/crm/customerLevel";
     export default {
         name: "remark",
         data() {
@@ -156,7 +157,7 @@
                     province:null,
                     city:null,
                     district:null,
-                    
+                    customerLevel: null
                 },
                 exts:[],
                 // 表单校验
@@ -170,8 +171,9 @@
                     source: [
                     { required: true, message: "客户来源不能为空", trigger: "blur" }
                     ],
-                }
-                 
+                },
+              customerLevelOptions: []
+
             };
         },
         created() {
@@ -190,10 +192,16 @@
             this.getDicts("crm_customer_type").then((response) => {
                 this.typeOptions = response.data;
             });
-            
+
             this.getCitys()
+          this.getCustomerLevelOptions()
         },
         methods: {
+          getCustomerLevelOptions(){
+            customerLevelOptions({status: 0}).then((response) => {
+              this.customerLevelOptions = response.data;
+            });
+          },
             tagsChange(e){
                 var item=this.tagsOptions.find(val => val.dictValue === e);
                 console.log(item);
@@ -210,7 +218,7 @@
                 setTimeout(() => {
                     that.$refs.tag.reset(this.item);
                 }, 500);
-                
+
             },
             handleCityChange(value) {
                 console.log(value);
@@ -276,7 +284,7 @@
                     isLine: null,
                     source: null,
                     tags: null,
-                    
+                    customerLevel: null
                 };
                 this.exts=[];
                 this.tags=[];
@@ -294,9 +302,9 @@
                         var data={extId:element.extId,name:element.name,value:""};
                         this.exts.push(data)
                     });
-                
+
                 });
-                
+
                 console.log(this.exts)
             },
             /** 修改按钮操作 */
@@ -343,10 +351,10 @@
                                         item.value=element.value
                                     }
                                 });
-                            
+
                             });
                         }
-                    
+
                     });
                     this.open = true;
                     this.title = "修改客户";
@@ -382,7 +390,7 @@
                                     }
                                 });
                             }
-                            
+
                         }
                     }
                 });
@@ -395,7 +403,7 @@
     height: 100%;
     background-color: #fff;
     padding: 20px;
-        
+
 }
 .footer{
     display: flex;
@@ -406,4 +414,3 @@
 
 
 
- 

+ 9 - 2
src/views/crm/components/customerDetails.vue

@@ -47,7 +47,7 @@
             </el-descriptions-item>
             <el-descriptions-item label="客户类型" >
                 <span v-if="item!=null">
-                    <el-tag  v-for="(dict, index) in typeOptions"    v-if="item.customerType==dict.dictValue">{{dict.dictLabel}}</el-tag>
+                    <el-tag  v-for="(dict, index) in customerLevelOptions"    v-if="item.customerLevel===dict.dictValue">{{dict.dictLabel}}</el-tag>
                 </span>
             </el-descriptions-item>
             <el-descriptions-item label="客户状态" >
@@ -221,6 +221,7 @@
     import addSms from './addSms.vue';
     import addOrEditCustomer from '../components/addOrEditCustomer.vue';
     import addPackage from "@/views/store/components/addOrder";
+    import {customerLevelOptions} from "@/api/crm/customerLevel";
     export default {
         name: "customer",
         components: {addPackage,customerHisOrderList,addOrEditCustomer,addSms,addTag,addRemark, customerContacts,customerVisitList,customerLogsList,customerVoiceLogsList,customerStoreOrderList,customerSmsLogsList,duplicateCustomer },
@@ -270,6 +271,7 @@
                 item:null,
                 showDuplicate:false,
                 dCustomerId:null,
+              customerLevelOptions: []
 
             };
         },
@@ -292,12 +294,17 @@
             this.getDicts("crm_customer_is_receive").then((response) => {
                 this.receiveOptions = response.data;
             });
-
+          this.getCustomerLevelOptions()
         },
         mounted(){
 
         },
         methods: {
+          getCustomerLevelOptions(){
+            customerLevelOptions().then((response) => {
+              this.customerLevelOptions = response.data;
+            });
+          },
             addPackageOrder(){
 
                this.addPackageOpen=true;

+ 22 - 13
src/views/crm/customer/assist.vue

@@ -41,10 +41,10 @@
               />
         </el-select>
       </el-form-item>
-      <el-form-item label="客户类型" prop="customerType">
-        <el-select style="width:220px" multiple filterable  v-model="ctsTypeArr" placeholder="请选择客户类型" clearable size="small">
+      <el-form-item label="客户类型" prop="customerLevel">
+        <el-select style="width:220px" filterable  v-model="queryParams.customerLevel" placeholder="请选择客户类型" clearable size="small">
            <el-option
-                v-for="item in typeOptions"
+                v-for="item in customerLevelOptions"
                 :key="item.dictValue"
                 :label="item.dictLabel"
                 :value="item.dictValue"
@@ -106,7 +106,7 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-      
+
       <el-col :span="1.5">
         <el-button
           type="success"
@@ -116,9 +116,9 @@
           @click="handleAssist"
           v-hasPermi="['crm:customer:assistToUser']"
         >客户协作</el-button>
-      </el-col>  
-      
-      
+      </el-col>
+
+
       <el-col :span="1.5">
         <el-button
           type="success"
@@ -157,7 +157,7 @@
 <!--          @click="addPackageOrder"-->
 <!--        >创建订单</el-button>-->
       </el-col>
-      
+
       <!-- <el-col :span="1.5">
         <el-button
           type="warning"
@@ -197,9 +197,9 @@
             <el-button  v-hasPermi="['crm:customer:addVisitStatus']"  type="text" size="mini" @click="handleVisitStatus(scope.row)">修改</el-button>
           </template>
       </el-table-column>
-      <el-table-column  label="客户类型"  width="200" align="center" prop="customerType">
+      <el-table-column  label="客户类型"  width="200" align="center" prop="customerLevel">
         <template slot-scope="scope">
-            <el-tag prop="status" v-for="(item, index) in typeOptions"    v-if="scope.row.customerType==item.dictValue">{{item.dictLabel}}</el-tag>
+            <el-tag prop="status" v-for="(item, index) in customerLevelOptions"    v-if="scope.row.customerLevel===item.dictValue">{{item.dictLabel}}</el-tag>
             <el-button   v-hasPermi="['crm:customer:addCustomerType']"  type="text" size="mini" @click="handleCustomerType(scope.row)">修改</el-button>
           </template>
       </el-table-column>
@@ -243,7 +243,7 @@
             @click="handleRecover(scope.row)"
             v-hasPermi="['crm:customer:recover']"
           >回收公海</el-button>
-          
+
         </template>
       </el-table-column>
     </el-table>
@@ -278,7 +278,7 @@
     <el-dialog :title="assist.title" :visible.sync="assist.open" width="800px" append-to-body>
         <assist-user  ref="assistUser" @close="closeAssist"   />
     </el-dialog>
-    
+
     <el-dialog :title="addTag.title" :visible.sync="addTag.open" width="600px" append-to-body>
         <add-tag ref="tag" @close="closeTag()"></add-tag>
     </el-dialog>
@@ -317,6 +317,7 @@ import addCustomerType from '../components/addCustomerType.vue';
 import addVisitStatus from '../components/addVisitStatus.vue';
 import addPackage from "@/views/store/components/addOrder";
 import addOrderOffline from "@/views/store/components/addOrderOffline";
+import {customerLevelOptions} from "@/api/crm/customerLevel";
 export default {
   name: "Customer",
   components: {addPackage,addOrderOffline,addVisitStatus,addCustomerType,addRemark,addTag,assignUser,assistUser,addOrEditCustomer,editSource, addBatchSms,customerDetails,addVisit },
@@ -444,7 +445,8 @@ export default {
         companyId: null,
         isLine: null,
         source: null,
-        tags: null
+        tags: null,
+        customerLevel: null,
       },
       // 表单参数
       form: {
@@ -468,6 +470,7 @@ export default {
         ],
       },
       loading:null,
+      customerLevelOptions: []
     };
   },
   created() {
@@ -488,8 +491,14 @@ export default {
     });
     this.getCitys();
     this.getList();
+    this.getCustomerLevelOptions()
   },
   methods: {
+    getCustomerLevelOptions(){
+      customerLevelOptions().then((response) => {
+        this.customerLevelOptions = response.data;
+      });
+    },
     handleCommand(command){
       if (command==="1"){
         this.addOfflineOrder.open = true

+ 16 - 7
src/views/crm/customer/full.vue

@@ -55,10 +55,10 @@
             </el-select>
           </el-form-item>
 
-          <el-form-item label="客户类型" prop="customerType">
-            <el-select multiple filterable v-model="ctsTypeArr" placeholder="请选择客户类型" clearable size="small">
+          <el-form-item label="客户类型" prop="customerLevel">
+            <el-select filterable v-model="queryParams.customerLevel" placeholder="请选择客户类型" clearable size="small">
               <el-option
-                    v-for="item in typeOptions"
+                    v-for="item in customerLevelOptions"
                     :key="item.dictValue"
                     :label="item.dictLabel"
                     :value="item.dictValue"
@@ -172,9 +172,9 @@
                 <el-tag prop="visitStatus" v-for="(item, index) in visitStatusOptions"    v-if="scope.row.visitStatus==item.dictValue">{{item.dictLabel}}</el-tag>
               </template>
           </el-table-column>
-          <el-table-column  label="客户类型"  align="center" prop="customerType">
+          <el-table-column  label="客户类型"  align="center" prop="customerLevel">
             <template slot-scope="scope">
-                <el-tag prop="status" v-for="(item, index) in typeOptions"    v-if="scope.row.customerType==item.dictValue">{{item.dictLabel}}</el-tag>
+                <el-tag v-for="(item, index) in customerLevelOptions"    v-if="scope.row.customerLevel===item.dictValue">{{item.dictLabel}}</el-tag>
             </template>
           </el-table-column>
           <el-table-column label="标签" align="center" prop="tags" />
@@ -253,6 +253,7 @@ import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import customerAssignList from '../components/customerAssignList.vue';
 import assignUser from '../components/assignUser.vue';
+import {customerLevelOptions} from "@/api/crm/customerLevel";
 export default {
   name: "Customer",
   components: {customerAssignList, customerDetails,Treeselect,assignUser },
@@ -352,7 +353,8 @@ export default {
         companyId: null,
         isLine: null,
         source: null,
-        tags: null
+        tags: null,
+        customerLevel: null,
       },
       // 表单参数
       form: {
@@ -374,7 +376,8 @@ export default {
         source: [
           { required: true, message: "客户来源不能为空", trigger: "blur" }
         ],
-      }
+      },
+      customerLevelOptions: []
     };
   },
   watch: {
@@ -414,8 +417,14 @@ export default {
     this.getTreeselect();
     this.getCitys();
     this.getList();
+    this.getCustomerLevelOptions()
   },
   methods: {
+    getCustomerLevelOptions(){
+      customerLevelOptions().then((response) => {
+        this.customerLevelOptions = response.data;
+      });
+    },
     handleAssign(){
       var that=this;
       var ids=this.ids;

+ 57 - 21
src/views/crm/customer/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="app-container">
- 
+
         <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
           <el-form-item label="客户编码" prop="customerCode">
             <el-input
@@ -55,10 +55,10 @@
                   />
             </el-select>
           </el-form-item>
-          <el-form-item label="客户类型" prop="customerType">
-            <el-select style="width:220px" multiple filterable v-model="ctsTypeArr" placeholder="请选择客户类型" clearable size="small">
+          <el-form-item label="客户类型" prop="customerLevel">
+            <el-select style="width:220px" filterable v-model="queryParams.customerLevel" placeholder="请选择客户类型" clearable size="small">
               <el-option
-                    v-for="item in typeOptions"
+                    v-for="item in customerLevelOptions"
                     :key="item.dictValue"
                     :label="item.dictLabel"
                     :value="item.dictValue"
@@ -75,7 +75,7 @@
                   />
             </el-select>
           </el-form-item>
-          
+
           <!-- <el-form-item label="是否认领" prop="isReceive">
             <el-select v-model="queryParams.isReceive" placeholder="请选择是否认领" clearable size="small">
               <el-option
@@ -163,7 +163,7 @@
               v-hasPermi="['crm:customer:editScource']"
             >修改客户来源</el-button>
           </el-col>
-         
+
           <el-col :span="1.5">
             <el-button
               type="success"
@@ -229,9 +229,9 @@
                 <el-tag prop="visitStatus" v-for="(item, index) in visitStatusOptions"    v-if="scope.row.visitStatus==item.dictValue">{{item.dictLabel}}</el-tag>
               </template>
           </el-table-column>
-          <el-table-column  label="客户类型"  width="200" align="center" prop="customerType">
+          <el-table-column  label="客户类型"  width="200" align="center" prop="customerLevel">
             <template slot-scope="scope">
-                <el-tag prop="status" v-for="(item, index) in typeOptions"    v-if="scope.row.customerType==item.dictValue">{{item.dictLabel}}</el-tag>
+                <el-tag v-for="(item, index) in customerLevelOptions"    v-if="scope.row.customerLevel===item.dictValue">{{item.dictLabel}}</el-tag>
             </template>
           </el-table-column>
           <el-table-column label="标签" align="center" prop="tags" />
@@ -275,10 +275,17 @@
                 @click="handleAssign(scope.row)"
                 v-hasPermi="['crm:customer:assign']"
               >分配客户</el-button> -->
+              <el-button
+                size="mini"
+                type="text"
+                icon="el-icon-mouse"
+                @click="handleSwitchToTop(scope.row)"
+                v-hasPermi="['crm:customer:switchToTop']"
+              >{{ scope.row.isTop === 1 ? '取消置顶' : '置顶' }}</el-button>
             </template>
           </el-table-column>
         </el-table>
-        
+
         <pagination
           v-show="total>0"
           :total="total"
@@ -293,15 +300,15 @@
         <customer-details  ref="customerDetails" />
     </el-drawer>
 
-   
-     
+
+
     <el-dialog :title="addSms.title" :visible.sync="addSms.open" width="1000px" append-to-body>
        <add-batch-sms ref="sms" @close="closeSms()"></add-batch-sms>
     </el-dialog>
     <el-dialog :title="source.title" :visible.sync="source.open" width="1000px" append-to-body>
        <edit-source ref="editSource" @close="closeSource()"></edit-source>
     </el-dialog>
-     
+
     <el-dialog :title="customerSource.title" :visible.sync="customerSource.open" width="1000px" append-to-body>
        <customer-source ref="customerSource" @close="closeSource()"></customer-source>
     </el-dialog>
@@ -336,8 +343,19 @@
 </template>
 
 <script>
- 
-import { assignToUser,recover,receive,getCustomerList ,addCustomer,updateCustomer,getCustomerDetails,exportCustomer,importVisitTemplate } from "@/api/crm/customer";
+
+import {
+  assignToUser,
+  recover,
+  receive,
+  getCustomerList,
+  addCustomer,
+  updateCustomer,
+  getCustomerDetails,
+  exportCustomer,
+  importVisitTemplate,
+  switchToTop
+} from "@/api/crm/customer";
 import { getToken } from "@/utils/auth";
 import customerDetails from '../components/customerDetails.vue';
 import {getCitys} from "@/api/store/city";
@@ -349,6 +367,7 @@ import editSource from '../components/editSource.vue';
 import customerSource from '../components/customerSource.vue';
 import customerAssignList from '../components/customerAssignList.vue';
 import assignUser from '../components/assignUser.vue';
+import {customerLevelOptions} from "@/api/crm/customerLevel";
 export default {
   name: "Customer",
   components: {assignUser,customerAssignList,addBatchSms,editSource, customerDetails,Treeselect,customerSource },
@@ -466,6 +485,7 @@ export default {
         tags: null,
         tagList:[],
         visitStatus:null,
+        customerLevel: null,
       },
       // 表单参数
       form: {
@@ -487,7 +507,8 @@ export default {
         source: [
           { required: true, message: "客户来源不能为空", trigger: "blur" }
         ],
-      }
+      },
+      customerLevelOptions: []
     };
   },
   watch: {
@@ -525,12 +546,18 @@ export default {
     this.getDicts("crm_customer_tag").then((response) => {
         this.tagsOptions = response.data;
     });
-    
+
     this.getTreeselect();
     this.getCitys();
     this.getList();
+    this.getCustomerLevelOptions()
   },
   methods: {
+    getCustomerLevelOptions(){
+      customerLevelOptions().then((response) => {
+        this.customerLevelOptions = response.data;
+      });
+    },
     handleShow(row){
       this.show.open=true;
       var that=this;
@@ -555,7 +582,7 @@ export default {
       setTimeout(() => {
         that.$refs.customerSource.getData();
       }, 200);
-      
+
     },
     closeCustomerSource(){
         this.customerSource.open=false;
@@ -571,7 +598,7 @@ export default {
       setTimeout(() => {
         that.$refs.editSource.handleEdit(that.ids);
       }, 200);
-      
+
     },
     closeSource(){
         this.source.open=false;
@@ -637,6 +664,15 @@ export default {
           this.msgSuccess("操作成功");
         }).catch(function() {});
     },
+    handleSwitchToTop(row) {
+      switchToTop(row.customerId).then(response => {
+        const {code} = response
+        if (code === 200) {
+          this.msgSuccess(row.isTop === 0 ? "已置顶" : "已取消置顶");
+          this.getList();
+        }
+      })
+    },
     getTreeselect() {
       treeselect().then((response) => {
         this.deptOptions = response.data;
@@ -689,7 +725,7 @@ export default {
       else{
         this.queryParams.source=null
       }
- 
+
       if(this.tagIds.length>0){
         this.queryParams.tags=this.tagIds.toString();
       }
@@ -760,8 +796,8 @@ export default {
       this.single = selection.length!==1
       this.multiple = !selection.length
     },
-    
-    
+
+
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();

+ 17 - 7
src/views/crm/customer/line.vue

@@ -39,10 +39,10 @@
                 />
           </el-select>
         </el-form-item>
-        <el-form-item   label="客户类型" prop="customerType">
-          <el-select filterable v-model="queryParams.customerType" placeholder="请选择客户类型" clearable size="small">
+        <el-form-item   label="客户类型" prop="customerLevel">
+          <el-select filterable v-model="queryParams.customerLevel" placeholder="请选择客户类型" clearable size="small">
             <el-option
-                  v-for="item in typeOptions"
+                  v-for="item in customerLevelOptions"
                   :key="item.dictValue"
                   :label="item.dictLabel"
                   :value="item.dictValue"
@@ -186,7 +186,7 @@
         </el-table-column>
         <el-table-column  label="客户类型"  align="center" prop="customerType" >
           <template slot-scope="scope">
-              <el-tag prop="status" v-for="(item, index) in typeOptions"    v-if="scope.row.customerType==item.dictValue">{{item.dictLabel}}</el-tag>
+              <el-tag v-for="item in customerLevelOptions"    v-if="scope.row.customerLevel === item.dictValue">{{item.dictLabel}}</el-tag>
           </template>
         </el-table-column>
         <el-table-column label="标签" align="center" prop="tags" />
@@ -279,6 +279,7 @@ import editSource from '../components/editSource.vue';
 import addOrEditCustomer from '../components/addOrEditCustomer.vue';
 import customerAssignList from '../components/customerAssignList.vue';
 import assignUser from '../components/assignUser.vue';
+import {customerLevelOptions} from "@/api/crm/customerLevel";
 export default {
   name: "Customer",
   components: { assignUser,customerAssignList,addOrEditCustomer,customerDetails,Treeselect,editSource },
@@ -393,7 +394,8 @@ export default {
         isLine: 1,
         source: null,
         tags: null,
-        isDuplicate:null
+        isDuplicate:null,
+        customerLevel: null
       },
       // 表单参数
       form: {
@@ -415,7 +417,9 @@ export default {
         source: [
           { required: true, message: "客户来源不能为空", trigger: "blur" }
         ],
-      }
+      },
+      customerLevelOptions: [],
+      customerLevelOpenOptions: []
     };
   },
 
@@ -426,7 +430,7 @@ export default {
     this.getDicts("common_sex").then((response) => {
       this.sexOptions = response.data;
     });
-   
+
     this.getDicts("common_sex").then((response) => {
       this.sexOptions = response.data;
     });
@@ -444,8 +448,14 @@ export default {
     });
 
     this.getList();
+    this.getCustomerLevelOptions()
   },
   methods: {
+    getCustomerLevelOptions(){
+      customerLevelOptions().then((response) => {
+        this.customerLevelOptions = response.data;
+      });
+    },
     handleShow(row){
       this.show.open=true;
       var that=this;

+ 20 - 11
src/views/crm/customer/my.vue

@@ -41,10 +41,10 @@
               />
         </el-select>
       </el-form-item>
-      <el-form-item label="客户类型" prop="customerType">
-        <el-select style="width:220px" multiple filterable  v-model="ctsTypeArr" placeholder="请选择客户类型" clearable size="small">
+      <el-form-item label="客户类型" prop="customerLevel">
+        <el-select style="width:220px" filterable  v-model="queryParams.customerLevel" placeholder="请选择客户类型" clearable size="small">
            <el-option
-                v-for="item in typeOptions"
+                v-for="item in customerLevelOptions"
                 :key="item.dictValue"
                 :label="item.dictLabel"
                 :value="item.dictValue"
@@ -122,9 +122,9 @@
           size="mini"
           :disabled="multiple"
           @click="handleAssist"
-         
+
         >客户协作</el-button>
-      </el-col>  
+      </el-col>
       <el-col :span="1.5">
         <el-button
           type="success"
@@ -184,7 +184,7 @@
           :disabled="multiple"
           @click="handleRemoveAllAssist"
         >删除协作人</el-button>
-      </el-col> 
+      </el-col>
       <el-col :span="1.5">
         <el-button
           type="warning"
@@ -194,7 +194,7 @@
           v-hasPermi="['crm:customer:export']"
         >导出</el-button>
       </el-col>
-     
+
        <!-- 新增选择外呼线路的下拉框 -->
       <el-col :span="2">
         <el-select
@@ -242,9 +242,9 @@
             <el-button  v-hasPermi="['crm:customer:addVisitStatus']"  type="text" size="mini" @click="handleVisitStatus(scope.row)">修改</el-button>
           </template>
       </el-table-column>
-      <el-table-column  label="客户类型"  width="200" align="center" prop="customerType">
+      <el-table-column  label="客户类型"  width="200" align="center" prop="customerLevel">
         <template slot-scope="scope">
-            <el-tag prop="status" v-for="(item, index) in typeOptions"    v-if="scope.row.customerType==item.dictValue">{{item.dictLabel}}</el-tag>
+            <el-tag prop="status" v-for="(item, index) in customerLevelOptions"    v-if="scope.row.customerLevel===item.dictValue">{{item.dictLabel}}</el-tag>
             <el-button   v-hasPermi="['crm:customer:addCustomerType']"  type="text" size="mini" @click="handleCustomerType(scope.row)">修改</el-button>
           </template>
       </el-table-column>
@@ -330,7 +330,7 @@
     <el-dialog :title="assist.title" :visible.sync="assist.open" width="1000px" append-to-body>
         <assist-user  ref="assistUser" @close="closeAssist"   />
     </el-dialog>
-    
+
     <el-dialog :title="addTag.title" :visible.sync="addTag.open" width="600px" append-to-body>
         <add-tag ref="tag" @close="closeTag()"></add-tag>
     </el-dialog>
@@ -370,6 +370,7 @@ import addVisitStatus from '../components/addVisitStatus.vue';
 import addPackage from "@/views/store/components/addOrder";
 import addOrderOffline from "@/views/store/components/addOrderOffline";
 import {getMyCallerApiList} from "@/api/company/companyVoiceCaller"
+import {customerLevelOptions} from "@/api/crm/customerLevel";
 export default {
   name: "Customer",
   components: {addPackage,addOrderOffline,addVisitStatus,addCustomerType,addRemark,addTag,assignUser,assistUser,addOrEditCustomer,editSource, addBatchSms,customerDetails,addVisit },
@@ -504,7 +505,8 @@ export default {
         companyId: null,
         isLine: null,
         source: null,
-        tags: null
+        tags: null,
+        customerLevel: null,
       },
       // 表单参数
       form: {
@@ -528,6 +530,7 @@ export default {
         ],
       },
       loading:null,
+      customerLevelOptions: []
     };
   },
   created() {
@@ -549,8 +552,14 @@ export default {
     this.getCitys();
     this.getList();
     this.getCallerApiList();
+    this.getCustomerLevelOptions()
   },
   methods: {
+    getCustomerLevelOptions(){
+      customerLevelOptions().then((response) => {
+        this.customerLevelOptions = response.data;
+      });
+    },
     getCallerApiList() {
       getMyCallerApiList().then(response => {
         this.callerApis = response.rows;

+ 1 - 1
src/views/member/list.vue

@@ -141,7 +141,7 @@
     </el-row>
 
     <!-- User Table -->
-    <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
+    <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange" border>
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="ID" align="center" prop="userId" />
       <el-table-column label="昵称" align="center" prop="nickname" />

+ 547 - 0
src/views/member/myList.vue

@@ -0,0 +1,547 @@
+<template>
+  <div class="app-container">
+    <!-- Search Form -->
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
+      <el-form-item label="昵称" prop="nickname">
+        <el-input
+          style="width: 200px"
+          v-model="queryParams.nickname"
+          placeholder="请输入昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="手机号码" prop="phone">
+        <el-input
+          style="width: 200px"
+          v-model="queryParams.phone"
+          placeholder="请输入手机号码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+<!--      <el-form-item label="状态" prop="status">-->
+<!--        <el-select style="width: 200px" v-model="queryParams.status" placeholder="请选择状态" clearable size="small">-->
+<!--          <el-option-->
+<!--            v-for="item in statusOptions"-->
+<!--            :key="item.dictValue"-->
+<!--            :label="item.dictLabel"-->
+<!--            :value="item.dictValue"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+<!--      <el-form-item label="看课状态" prop="watchCourseType">-->
+<!--        <el-select style="width: 200px" v-model="queryParams.watchCourseType" placeholder="请选择看课状态" clearable size="small">-->
+<!--          <el-option label="全部" value="0" />-->
+<!--          <el-option label="未看过课" value="1" />-->
+<!--          <el-option label="正常看课" value="2" />-->
+<!--          <el-option label="停止看课" value="3" />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+<!--      <el-form-item label="缺课状态" prop="missCourseStatus">-->
+<!--        <el-select style="width: 200px" v-model="queryParams.missCourseStatus" placeholder="请选择缺课状态" clearable size="small">-->
+<!--          <el-option label="全部" value="0" />-->
+<!--          <el-option label="已缺课" value="1" />-->
+<!--          <el-option label="未缺课" value="2" />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+<!--      <el-form-item label="标签" prop="tagIds">-->
+<!--        <el-select style="width: 200px" v-model="queryParams.tagIds" placeholder="请选择标签" clearable size="small" multiple>-->
+<!--          <el-option-->
+<!--            v-for="item in tagOptions"-->
+<!--            :key="item.tagId"-->
+<!--            :label="item.tagName"-->
+<!--            :value="item.tagId"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+      <el-form-item label="注册时间">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- Tab Selection -->
+<!--    <el-tabs v-model="queryParams.tabValue" @tab-click="handleTabChange">-->
+<!--      <el-tab-pane label="全部" name="0"></el-tab-pane>-->
+<!--      <el-tab-pane label="今日新增" name="1"></el-tab-pane>-->
+<!--      <el-tab-pane label="今日完播" name="2"></el-tab-pane>-->
+<!--      <el-tab-pane label="未看过课" name="3"></el-tab-pane>-->
+<!--    </el-tabs>-->
+
+    <!-- Toolbar -->
+    <el-row :gutter="10" class="mb8">
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          icon="el-icon-plus"-->
+<!--          size="mini"-->
+<!--          @click="handleAdd"-->
+<!--          v-hasPermi="['user:fsUser:add']"-->
+<!--        >新增</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="success"-->
+<!--          plain-->
+<!--          icon="el-icon-edit"-->
+<!--          size="mini"-->
+<!--          :disabled="single"-->
+<!--          @click="handleUpdate"-->
+<!--          v-hasPermi="['user:fsUser:edit']"-->
+<!--        >编辑</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="danger"-->
+<!--          plain-->
+<!--          icon="el-icon-delete"-->
+<!--          size="mini"-->
+<!--          :disabled="multiple"-->
+<!--          @click="handleDelete"-->
+<!--          v-hasPermi="['user:fsUser:remove']"-->
+<!--        >删除</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="warning"-->
+<!--          plain-->
+<!--          icon="el-icon-download"-->
+<!--          size="mini"-->
+<!--          @click="handleExport"-->
+<!--          v-hasPermi="['user:fsUser:export']"-->
+<!--        >导出</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- User Table -->
+    <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="userId" />
+      <el-table-column label="昵称" align="center" prop="nickname" />
+      <el-table-column label="头像" align="center" width="80">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.avatar" width="50">
+            <img :src="scope.row.avatar" style="max-width: 120px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="手机号码" align="center" prop="phone" />
+      <el-table-column label="积分" align="center" prop="integral" v-if="false" />
+      <el-table-column label="看课数量" align="center" prop="watchCourseCount" />
+      <el-table-column label="缺课数量" align="center" prop="missCourseCount" />
+      <el-table-column label="参与营期数量" align="center" prop="partCourseCount" />
+      <el-table-column label="状态" align="center">
+        <template slot-scope="scope">
+          <el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
+            {{ scope.row.status === 1 ? '正常' : '禁止' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="看课状态" align="center">
+        <template slot-scope="scope">
+          <el-tag :type="getCourseStatusType(scope.row.courseCountStatus)">
+            {{ getCourseStatusText(scope.row.courseCountStatus) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="标签" align="center" prop="tag" show-overflow-tooltip />
+      <el-table-column label="最后看课时间" align="center" prop="lastWatchDate" width="160" />
+      <el-table-column label="停课天数" align="center" prop="stopWatchDays" />
+      <el-table-column label="注册时间" align="center" prop="createTime" width="160" />
+      <el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
+      <el-table-column label="所属员工" align="center" prop="companyUserNickName" />
+      <el-table-column label="操作" align="center" width="120" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-check"
+            @click="handleAudit(scope.row)"
+            v-if="scope.row.isCurrentCompanyUser === 1 && scope.row.status === 0"
+          >审核会员</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- Edit User Dialog -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="用户头像" prop="avatar">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="form.avatar" width="80">
+            <img :src="form.avatar" style="max-width: 120px;">
+          </el-popover>
+        </el-form-item>
+        <el-form-item label="昵称" prop="nickname">
+          <el-input v-model="form.nickname" placeholder="请输入昵称" />
+        </el-form-item>
+        <el-form-item label="手机号码" prop="phone">
+          <el-input v-model="form.phone" placeholder="请输入手机号码" />
+        </el-form-item>
+        <el-form-item label="最后登录IP" prop="lastIp" v-if="form.lastIp">
+          <el-input v-model="form.lastIp" disabled placeholder="最后一次登录IP" />
+        </el-form-item>
+        <el-form-item label="看课数量" prop="watchCourseCount" v-if="form.watchCourseCount">
+          <el-input v-model="form.watchCourseCount" disabled placeholder="看课数量" />
+        </el-form-item>
+        <el-form-item label="缺课数量" prop="missCourseCount" v-if="form.missCourseCount">
+          <el-input v-model="form.missCourseCount" disabled placeholder="缺课数量" />
+        </el-form-item>
+        <el-form-item label="标签" prop="tagIds">
+          <el-select v-model="form.tagIds" placeholder="请选择标签" clearable multiple>
+            <el-option
+              v-for="item in tagOptions"
+              :key="item.tagId"
+              :label="item.tagName"
+              :value="item.tagId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="所属员工" prop="companyUserId">
+          <el-select v-model="form.companyUserId" placeholder="请选择所属员工" clearable>
+            <el-option
+              v-for="item in salesOptions"
+              :key="item.userId"
+              :label="item.nickName"
+              :value="item.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="用户备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入用户备注" />
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio :label="1">正常</el-radio>
+            <el-radio :label="0">禁止</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getUser, addUser, updateUser, delUser, exportUser, auditUser, myListUser } from '@/api/user/fsUser'
+
+export default {
+  name: "FsUser",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 用户表格数据
+      userList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 日期范围
+      dateRange: [],
+      // 状态数据字典
+      statusOptions: [],
+      // 标签选项
+      tagOptions: [],
+      // 销售员工选项
+      salesOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        nickname: null,
+        phone: null,
+        // status: null,
+        tagIds: [],
+        tabValue: "0",
+        watchCourseType: "0",
+        missCourseStatus: "0",
+        continueMissCourseSort: "0",
+        registerStartTime: null,
+        registerEndTime: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        nickname: [
+          { required: true, message: "昵称不能为空", trigger: "blur" }
+        ],
+        phone: [
+          { required: true, message: "手机号码不能为空", trigger: "blur" },
+          { pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号码", trigger: "blur" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("user_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getTagOptions();
+    this.getSalesOptions();
+  },
+  methods: {
+    /** 查询用户列表 */
+    getList() {
+      this.loading = true;
+
+      // 处理日期范围
+      if (this.dateRange && this.dateRange.length > 0) {
+        this.queryParams.registerStartTime = this.dateRange[0];
+        this.queryParams.registerEndTime = this.dateRange[1];
+      } else {
+        this.queryParams.registerStartTime = null;
+        this.queryParams.registerEndTime = null;
+      }
+
+      myListUser(this.queryParams).then(response => {
+        this.userList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    /** 获取标签选项 */
+    getTagOptions() {
+      this.tagOptions = [
+        { tagId: "1", tagName: "VIP会员" },
+        { tagId: "2", tagName: "普通会员" },
+        { tagId: "3", tagName: "新用户" },
+        { tagId: "4", tagName: "高频用户" }
+      ];
+    },
+
+    /** 获取销售员工选项 */
+    getSalesOptions() {
+      this.salesOptions = [
+        { userId: 1, nickName: "销售A" },
+        { userId: 2, nickName: "销售B" },
+        { userId: 3, nickName: "销售C" }
+      ];
+    },
+
+    /** 获取看课状态类型 */
+    getCourseStatusType(status) {
+      if (status === 1) return "success";
+      if (status === 2) return "danger";
+      if (status === 3) return "info";
+      return "";
+    },
+
+    /** 获取看课状态文本 */
+    getCourseStatusText(status) {
+      if (status === 1) return "正常看课";
+      if (status === 2) return "停止看课";
+      if (status === 3) return "未看过课";
+      return "未知状态";
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        userId: null,
+        nickname: null,
+        avatar: null,
+        phone: null,
+        status: 1,
+        tagIds: [],
+        companyUserId: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+    /** Tab切换操作 */
+    handleTabChange() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.userId);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
+    },
+
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加用户";
+    },
+
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids[0];
+      getUser(userId).then(response => {
+        this.form = response.data;
+
+        // 处理标签数据,将字符串转为数组
+        if (this.form.tagIds && typeof this.form.tagIds === 'string') {
+          this.form.tagIds = this.form.tagIds.split(',');
+        }
+
+        this.open = true;
+        this.title = "修改用户";
+      });
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          // 处理标签数据,将数组转为字符串
+          if (this.form.tagIds && Array.isArray(this.form.tagIds)) {
+            this.form.tagIds = this.form.tagIds.join(',');
+          }
+
+          if (this.form.userId != null) {
+            updateUser(this.form).then(response => {
+              if (response.code === 200) {
+                this.$message.success("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addUser(this.form).then(response => {
+              if (response.code === 200) {
+                this.$message.success("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return delUser(userIds);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    },
+
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有用户数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return exportUser(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      }).catch(() => {});
+    },
+
+    /** 审核会员操作 */
+    handleAudit(row) {
+      this.$confirm('是否确认将其移除小黑屋?', "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        auditUser([row.userId]).then(response => {
+          if (response.code === 200) {
+            this.msgSuccess("审核成功");
+            this.getList();
+          }
+        });
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+
+<style scoped>
+.el-tag + .el-tag {
+  margin-left: 5px;
+}
+.mb8 {
+  margin-bottom: 8px;
+}
+</style>

+ 393 - 0
src/views/store/userOnlineState/index.vue

@@ -0,0 +1,393 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户昵称" prop="nickname">
+        <el-input
+          v-model="queryParams.nickname"
+          placeholder="请输入用户昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="手机号码" prop="phone">
+        <el-input
+          v-model="queryParams.phone"
+          placeholder="请输入手机号码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="所属公司" prop="companyName">
+        <el-input
+          v-model="queryParams.companyName"
+          placeholder="请输入所属公司"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="所属销售" prop="companyUserNickName">
+        <el-input
+          v-model="queryParams.companyUserName"
+          placeholder="请输入所属销售"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          icon="el-icon-plus"-->
+<!--          size="mini"-->
+<!--          @click="handleAdd"-->
+<!--          v-hasPermi="['store:userOnlineState:add']"-->
+<!--        >新增</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="success"-->
+<!--          plain-->
+<!--          icon="el-icon-edit"-->
+<!--          size="mini"-->
+<!--          :disabled="single"-->
+<!--          @click="handleUpdate"-->
+<!--          v-hasPermi="['store:userOnlineState:edit']"-->
+<!--        >修改</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="danger"-->
+<!--          plain-->
+<!--          icon="el-icon-delete"-->
+<!--          size="mini"-->
+<!--          :disabled="multiple"-->
+<!--          @click="handleDelete"-->
+<!--          v-hasPermi="['store:userOnlineState:remove']"-->
+<!--        >删除</el-button>-->
+<!--      </el-col>-->
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['store:userOnlineState:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="userOnlineStateList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="用户id" align="center" prop="userId" />
+      <el-table-column label="用户昵称" align="center" prop="nickname" />
+      <el-table-column label="用户头像" align="center" width="80">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.avatar" width="50" >
+            <img :src="scope.row.avatar" style="max-width: 120px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="手机号码" align="center" prop="phone" />
+      <el-table-column label="所属公司" align="center" prop="companyName" />
+      <el-table-column label="所属销售" align="center" prop="companyUserName" />
+      <el-table-column label="上线状态" align="center" prop="onlineStatus">
+      <template slot-scope="scope">
+        <el-tag prop="onlineStatus"  v-if="scope.row.onlineStatus === 1" type="success">已上线</el-tag>
+        <el-tag prop="onlineStatus"  v-if="scope.row.onlineStatus === 2" type="primary">未上线</el-tag>
+      </template>
+      </el-table-column>
+<!--      <el-table-column label="上线时间" align="center" prop="onlineTime" width="180">-->
+<!--        <template slot-scope="scope">-->
+<!--          <span>{{ parseTime(scope.row.onlineTime, '{y}-{m}-{d}') }}</span>-->
+<!--        </template>-->
+<!--      </el-table-column>-->
+<!--      <el-table-column label="看课数量" align="center" prop="watchCourseCount" />-->
+<!--      <el-table-column label="参与营期数量" align="center" prop="partCourseCount" />-->
+<!--      <el-table-column label="最后一次看课时间" align="center" prop="lastWatchDate" width="180">-->
+<!--        <template slot-scope="scope">-->
+<!--          <span>{{ parseTime(scope.row.lastWatchDate, '{y}-{m}-{d}') }}</span>-->
+<!--        </template>-->
+<!--      </el-table-column>-->
+<!--      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">-->
+<!--        <template slot-scope="scope">-->
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-edit"-->
+<!--            @click="handleUpdate(scope.row)"-->
+<!--            v-hasPermi="['store:userOnlineState:edit']"-->
+<!--          >修改</el-button>-->
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-delete"-->
+<!--            @click="handleDelete(scope.row)"-->
+<!--            v-hasPermi="['store:userOnlineState:remove']"-->
+<!--          >删除</el-button>-->
+<!--        </template>-->
+<!--      </el-table-column>-->
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+<!--    &lt;!&ndash; 添加或修改用户上线情况对话框 &ndash;&gt;-->
+<!--    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>-->
+<!--      <el-form ref="form" :model="form" :rules="rules" label-width="80px">-->
+<!--        <el-form-item label="用户昵称" prop="nickname">-->
+<!--          <el-input v-model="form.nickname" placeholder="请输入用户昵称" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="用户头像" prop="avatar">-->
+<!--          <el-input v-model="form.avatar" placeholder="请输入用户头像" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="微信小程序OPENID" prop="maOpenId">-->
+<!--          <el-input v-model="form.maOpenId" placeholder="请输入微信小程序OPENID" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="微信公众号OPENID" prop="mpOpenId">-->
+<!--          <el-input v-model="form.mpOpenId" placeholder="请输入微信公众号OPENID" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="关联ID" prop="unionId">-->
+<!--          <el-input v-model="form.unionId" placeholder="请输入关联ID" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="公司id" prop="companyId">-->
+<!--          <el-input v-model="form.companyId" placeholder="请输入公司id" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="销售id" prop="companyUserId">-->
+<!--          <el-input v-model="form.companyUserId" placeholder="请输入销售id" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="上线状态,1-已上线;2-未上线">-->
+<!--          <el-radio-group v-model="form.onlineStatus">-->
+<!--            <el-radio label="1">请选择字典生成</el-radio>-->
+<!--          </el-radio-group>-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="上线时间" prop="onlineTime">-->
+<!--          <el-date-picker clearable size="small"-->
+<!--            v-model="form.onlineTime"-->
+<!--            type="date"-->
+<!--            value-format="yyyy-MM-dd"-->
+<!--            placeholder="选择上线时间">-->
+<!--          </el-date-picker>-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="看课数量" prop="watchCourseCount">-->
+<!--          <el-input v-model="form.watchCourseCount" placeholder="请输入看课数量" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="参与营期数量" prop="partCourseCount">-->
+<!--          <el-input v-model="form.partCourseCount" placeholder="请输入参与营期数量" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="最后一次看课时间" prop="lastWatchDate">-->
+<!--          <el-date-picker clearable size="small"-->
+<!--            v-model="form.lastWatchDate"-->
+<!--            type="date"-->
+<!--            value-format="yyyy-MM-dd"-->
+<!--            placeholder="选择最后一次看课时间">-->
+<!--          </el-date-picker>-->
+<!--        </el-form-item>-->
+<!--      </el-form>-->
+<!--      <div slot="footer" class="dialog-footer">-->
+<!--        <el-button type="primary" @click="submitForm">确 定</el-button>-->
+<!--        <el-button @click="cancel">取 消</el-button>-->
+<!--      </div>-->
+<!--    </el-dialog>-->
+  </div>
+</template>
+
+<script>
+import { listUserOnlineState, getUserOnlineState, delUserOnlineState, addUserOnlineState, updateUserOnlineState, exportUserOnlineState } from "@/api/store/userOnlineState";
+
+export default {
+  name: "UserOnlineState",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 用户上线情况表格数据
+      userOnlineStateList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        nickname: null,
+        avatar: null,
+        phone: null,
+        maOpenId: null,
+        mpOpenId: null,
+        unionId: null,
+        companyId: null,
+        companyUserId: null,
+        onlineStatus: null,
+        onlineTime: null,
+        watchCourseCount: null,
+        partCourseCount: null,
+        lastWatchDate: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询用户上线情况列表 */
+    getList() {
+      this.loading = true;
+      listUserOnlineState(this.queryParams).then(response => {
+        this.userOnlineStateList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        userId: null,
+        nickname: null,
+        avatar: null,
+        phone: null,
+        createTime: null,
+        maOpenId: null,
+        mpOpenId: null,
+        unionId: null,
+        companyId: null,
+        companyUserId: null,
+        onlineStatus: 0,
+        onlineTime: null,
+        watchCourseCount: null,
+        partCourseCount: null,
+        lastWatchDate: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.userId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加用户上线情况";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids
+      getUserOnlineState(userId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改用户上线情况";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.userId != null) {
+            updateUserOnlineState(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUserOnlineState(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$confirm('是否确认删除用户上线情况编号为"' + userIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delUserOnlineState(userIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有用户上线情况数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportUserOnlineState(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>