Explorar o código

Merge remote-tracking branch 'origin/master'

yuhongqi hai 3 días
pai
achega
1d90ae5d23

+ 3 - 0
.env.prod-gzzdy

@@ -43,3 +43,6 @@ VUE_APP_COURSE_DEFAULT = 2
 
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+# 郑多燕
+VUE_APP_FS_USER_INFO = 'gzzdy'

+ 7 - 1
src/api/hisStore/storeOrder.js

@@ -103,7 +103,13 @@ export function updateStoreOrder(data) {
     data: data
   })
 }
-
+// 修改订单ItemJson
+export function updateStoreOrderItemJson(id,backendEditProductType) {
+  return request({
+    url: '/store/store/storeOrder/updateStoreOrderItemJson/'+id + "/" + backendEditProductType,
+    method: 'get'
+  })
+}updateStoreOrderItemJson
 // 修改物流编号
 export function updateDeliveryId(data) {
   return request({

+ 9 - 0
src/api/hisStore/storeOrderItem.js

@@ -51,3 +51,12 @@ export function exportStoreOrderItem(query) {
     params: query
   })
 }
+
+// 修改订单数量
+export function updateNumStoreOrderItem(data) {
+  return request({
+    url: '/store/store/storeOrderItem/updateNum',
+    method: 'put',
+    data: data
+  })
+}

+ 86 - 0
src/api/qw/QwWorkTaskNew.js

@@ -0,0 +1,86 @@
+import request from '@/utils/request'
+
+// 查询企微任务看板列表
+export function listQwWorkTask(query) {
+  return request({
+    url: '/qw/QwWorkTaskNew/list',
+    method: 'get',
+    params: query
+  })
+}
+export function deptListQwWorkTask(query) {
+  return request({
+    url: '/qw/QwWorkTaskNew/deptList',
+    method: 'get',
+    params: query
+  })
+}
+export function allListQwWorkTask(query) {
+  return request({
+    url: '/qw/QwWorkTaskNew/allList',
+    method: 'get',
+    params: query
+  })
+}
+export function glList(query) {
+  return request({
+    url: '/qw/QwWorkTaskNew/glList',
+    method: 'get',
+    params: query
+  })
+}
+// 查询企微任务看板详细
+export function getQwWorkTask(id) {
+  return request({
+    url: '/qw/QwWorkTaskNew/' + id,
+    method: 'get'
+  })
+}
+
+// 新增企微任务看板
+export function addQwWorkTask(data) {
+  return request({
+    url: '/qw/QwWorkTaskNew',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改企微任务看板
+export function updateQwWorkTask(data) {
+  return request({
+    url: '/qw/QwWorkTaskNew',
+    method: 'put',
+    data: data
+  })
+}
+export function updateQwWorkTask2(data) {
+  return request({
+    url: '/qw/QwWorkTaskNew/edit2',
+    method: 'put',
+    data: data
+  })
+}
+export function updateQwWorkTask3(data) {
+  return request({
+    url: '/qw/QwWorkTaskNew/edit3',
+    method: 'put',
+    data: data
+  })
+}
+// 删除企微任务看板
+export function delQwWorkTask(id) {
+  return request({
+    url: '/qw/QwWorkTaskNew/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出企微任务看板
+export function exportQwWorkTask(query) {
+  return request({
+    url: '/qw/QwWorkTaskNew/export',
+    method: 'get',
+    params: query
+  })
+}

+ 62 - 0
src/api/qw/groupChat.js

@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 查询客户群详情列表
+export function listGroupChat(query) {
+  return request({
+    url: '/qw/groupChat/list',
+    method: 'get',
+    params: query
+  })
+}
+export function listGroupChatDeptList(query) {
+  return request({
+    url: '/qw/groupChat/deptList',
+    method: 'get',
+    params: query
+  })
+}
+export function listGroupChatMyList(query) {
+  return request({
+    url: '/qw/groupChat/myList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询客户群详情详细
+export function getGroupChat(chatId) {
+  return request({
+    url: '/qw/groupChat/' + chatId,
+    method: 'get'
+  })
+}
+export function allList(corpId) {
+  return request({
+    url: '/qw/groupChat/allList/' + corpId,
+    method: 'get'
+  })
+}
+// 同步客户群详情
+export function cogradientGroupChat(corpId) {
+  return request({
+    url: '/qw/groupChat/cogradientGroupChat/'+corpId,
+    method: 'get',
+  })
+}
+
+export function cogradientMyGroupChat(corpId) {
+  return request({
+    url: '/qw/groupChat/cogradientMyGroupChat/'+corpId,
+    method: 'get',
+  })
+}
+
+
+
+export function listAll(qwUserIds, corpId, sopId) {
+  return request({
+    url: '/qw/groupChat/listAll',
+    method: 'get',
+    params:{qwUserIds, corpId, sopId}
+  })
+}

+ 74 - 0
src/api/qw/group_chat_user.js

@@ -0,0 +1,74 @@
+import request from '@/utils/request'
+
+// 查询客户群成员列列表
+export function listGroup_chat_user(query) {
+  return request({
+    url: '/qw/group_chat_user/list',
+    method: 'get',
+    params: query
+  })
+}
+
+//获取日星月的入群退群统计
+export function getDataWeekMonthCount(query) {
+  return request({
+    url: '/qw/group_chat_user/getDataWeekMonthCount',
+    method: 'get',
+    params: query
+  })
+}
+
+
+// 查询客户群成员列详细
+export function getGroup_chat_user(id) {
+  return request({
+    url: '/qw/group_chat_user/' + id,
+    method: 'get'
+  })
+}
+
+// 新增客户群成员列
+export function addGroup_chat_user(data) {
+  return request({
+    url: '/qw/group_chat_user',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改客户群成员列
+export function updateGroup_chat_user(data) {
+  return request({
+    url: '/qw/group_chat_user',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除客户群成员列
+export function delGroup_chat_user(id) {
+  return request({
+    url: '/qw/group_chat_user/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出客户群成员列
+export function exportGroup_chat_user(query) {
+  return request({
+    url: '/qw/group_chat_user/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 同步客户群详情
+export function cogradientGroupChatUser(data) {
+  return request({
+    url: '/qw/group_chat_user/cogradientGroupChatUser',
+    method: 'put',
+    data:data
+  })
+}
+
+

+ 5 - 0
src/views/components/his/integralOrderDetails.vue

@@ -93,6 +93,11 @@
             <p>{{ scope.row.goodsName }}</p>
           </template>
         </el-table-column>
+        <el-table-column label="数量" align="center">
+          <template slot-scope="scope">
+            <p>{{ scope.row.num }}</p>
+          </template>
+        </el-table-column>
         <el-table-column label="积分" align="center">
           <template slot-scope="scope">
             <p>¥{{ scope.row.integral }}</p>

+ 18 - 4
src/views/components/his/userDetails.vue

@@ -101,7 +101,7 @@
 
 
 
-  <div class="contentx" v-if="item!=null">
+  <div class="contentx" v-if="item!=null && fsUserInfo !== 'gzzdy'">
         <div class="desct">
           <span v-if="patientInfo">
             {{ patientInfo }}
@@ -121,19 +121,26 @@
  <userAddDetails  ref="userAddDetail" />
 
    </div>
-  <div class="contentx" v-if="item!=null" >
+  <div class="contentx" v-if="item!=null && fsUserInfo !== 'gzzdy'" >
  <div class="desct">
       用户药品订单
  </div>
     <userStorerDetails  ref="userDetails" />
    </div>
-<div class="contentx" v-if="item!=null" >
+<div class="contentx" v-if="item!=null && fsUserInfo !== 'gzzdy'" >
  <div class="desct">
       用户问诊订单
  </div>
     <userInquiryOrderDetails  ref="InquiryDetails" />
    </div>
 
+  <div class="contentx" v-if="item != null && fsUserInfo === 'gzzdy'" >
+    <div class="desct">
+      商城订单
+    </div>
+    <userStoreOrderList  ref="userStoreOrderList" />
+  </div>
+
     <!-- 积分记录 -->
     <div class="contentx" v-if="item!=null" >
       <div class="desct">
@@ -156,10 +163,11 @@ import userPatietDetails from "../his/userPatietDetails.vue";
 import userInquiryOrderDetails from "../his/userInquiryOrderDetails.vue";
 import userAddDetails from "../his/userAddDetails.vue";
     import userIntegralDetails from "../his/userIntegralDetails.vue";
+import userStoreOrderList from "../his/userStoreOrderList.vue";
   export default {
     name: "storedet",
     props:["data"],
-     components: { userStorerDetails ,userInquiryOrderDetails,userPatietDetails,userAddDetails,userIntegralDetails},
+     components: { userStorerDetails ,userInquiryOrderDetails,userPatietDetails,userAddDetails,userIntegralDetails, userStoreOrderList},
     data() {
       return {
         patientInfo: process.env.VUE_APP_PATIENT_INFO,
@@ -183,6 +191,7 @@ import userAddDetails from "../his/userAddDetails.vue";
         actName:"10",
         businessTypeOptions:[],
         couponStatusOptions:[],
+        fsUserInfo: process.env.VUE_APP_FS_USER_INFO
       }
     },
     created() {
@@ -245,6 +254,11 @@ import userAddDetails from "../his/userAddDetails.vue";
               setTimeout(() => {
                   this.$refs.userIntegralDetail.getIntegralLogs(orderId);
               }, 1);
+              setTimeout(() => {
+                if (this.$refs.userStoreOrderList) {
+                  this.$refs.userStoreOrderList.getUserOrderDetails(orderId);
+                }
+              }, 1);
           });
           this.patient=null;
           getPatientByUserId(orderId).then(response => {

+ 275 - 0
src/views/components/his/userStoreOrderList.vue

@@ -0,0 +1,275 @@
+<template>
+  <div class="aacontainer">
+    <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
+      <el-tab-pane label="全部订单" name="10"></el-tab-pane>
+      <el-tab-pane v-for="(item,index) in orderOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+    </el-tabs>
+    <el-table v-loading="loading" :data="storeOrderList">
+      <el-table-column label="订单号" align="center" prop="orderCode" width="180px"/>
+<!--      <el-table-column label="所属店铺" align="center" prop="storeName" width="180px"/>-->
+      <el-table-column label="所属公司" align="center" prop="companyName" width="180px"/>
+      <el-table-column label="所属员工" align="center" prop="companyUserNickName" width="180px"/>
+      <el-table-column label="用户昵称" align="center" prop="userPhone" show-overflow-tooltip width="100px"/>
+      <el-table-column label="收件人" align="center" prop="realName" />
+      <el-table-column label="订单总价" align="center" prop="totalPrice" />
+<!--      <el-table-column label="商品分类" align="center" prop="totalPrice" />-->
+      <el-table-column label="实付金额" align="center" prop="payPrice" />
+      <el-table-column label="代收金额" align="center" prop="payDelivery" />
+      <el-table-column label="订单状态" align="center" prop="status" >
+        <template slot-scope="scope">
+              <dict-tag :options="orderOptions" :value="scope.row.status"/>
+         </template>
+      </el-table-column>
+      <el-table-column label="下单时间" align="center" prop="createTime" width="180" />
+<!--      <el-table-column label="支付状态 " align="center" prop="isPay" >-->
+<!--        <template slot-scope="scope">-->
+<!--              <dict-tag :options="payStatusOptions" :value="scope.row.isPay"/>-->
+<!--            </template>-->
+<!--      </el-table-column>-->
+      <el-table-column label="支付时间" align="center" prop="payTime" width="180" />
+      <el-table-column label="支付方式" align="center" prop="payType" >
+        <template slot-scope="scope">
+              <dict-tag :options="PayOptions" :value="scope.row.payType"/>
+         </template>
+      </el-table-column>
+      <el-table-column label="发货时间" align="center" prop="deliverySendTime" width="180" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+import {listStoreOrder} from "@/api/hisStore/storeOrder";
+export default {
+  name: "userInquir",
+  props:["data"],
+  data() {
+    return {
+      actName:"10",
+      show:{
+              title:"订单详情",
+              open:false,
+            },
+      upload: {
+        // 是否显示弹出层
+        open: false,
+        // 弹出层标题
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        // url: process.env.VUE_APP_BASE_API + "/his/order/importData"
+      },
+      // 遮罩层
+      loading: true,
+      // // 导出遮罩层
+      // exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 订单表格数据
+      storeOrderList: [],
+      // 弹出层标题
+      title: "",
+      createTime:null,
+      payTime:null,
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        storeId: null,
+        orderCode: null,
+        userId: null,
+        userName: null,
+        userPhone: null,
+        userAddress: null,
+        cartId: null,
+        totalNum: null,
+        totalPrice: null,
+        payPrice: null,
+        payMoney: null,
+        isPay: null,
+        payTime: null,
+        payType: null,
+        status: null,
+        refundStatus: null,
+        refundImg: null,
+        refundExplain: null,
+        refundTime: null,
+        refundReason: null,
+        refundMoney: null,
+        deliveryCode: null,
+        deliveryName: null,
+        deliverySn: null,
+        isDel: null,
+        costPrice: null,
+        verifyCode: null,
+        shippingType: null,
+        isChannel: null,
+        isPrescribe: null,
+        prescribeId: null,
+        finishTime: null,
+        patientName: null,
+        doctorName: null,
+        sTime:null,
+        eTime:null,
+        paysTime:null,
+        payeTime:null,
+        deliveryTime: null,
+        tuiMoney: null,
+        tuiMoneyStatus: null,
+        tuiUserId: null,
+        orderCreateType: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+       PayOptions:[],
+       orderOptions:[],
+       payStatusOptions:[],
+       refundOptions:[],
+       channelOptions:[],
+       orderTypeOptions:[],
+       tuiOptions:[],
+       orOptions:[],
+       storeOPtions:[],
+    };
+  },
+  created() {
+    this.getDicts("store_pay_type").then(response => {
+        this.PayOptions = response.data;
+      });
+    this.getDicts("store_order_type").then(response => {
+        this.orderTypeOptions = response.data;
+      });
+    this.getDicts("store_order_status").then(response => {
+        this.orderOptions = response.data;
+      });
+
+    this.getDicts("sys_store_payment_status").then(response => {
+        this.payStatusOptions = response.data;
+      });
+    this.getDicts("sys_refund_status").then(response => {
+        this.refundOptions = response.data;
+      });
+    this.getDicts("sys_channel").then(response => {
+        this.channelOptions = response.data;
+      });
+  },
+  methods: {
+    getUserOrderDetails(id){
+      this.queryParams.userId=id
+      this.getList();
+    },
+
+    /** 查询订单列表 */
+    getList() {
+      this.loading = true;
+      listStoreOrder(this.queryParams).then(response => {
+        this.storeOrderList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        orderId: null,
+        storeId: null,
+        orderCode: null,
+        userId: null,
+        userName: null,
+        userPhone: null,
+        userAddress: null,
+        cartId: null,
+        totalNum: null,
+        totalPrice: null,
+        payPrice: null,
+        payMoney: null,
+        isPay: null,
+        payTime: null,
+        payType: null,
+        createTime: null,
+        updateTime: null,
+        status: null,
+        refundStatus: "0",
+        refundImg: null,
+        refundExplain: null,
+        refundTime: null,
+        refundReason: null,
+        refundMoney: null,
+        deliveryCode: null,
+        deliveryName: null,
+        deliverySn: null,
+        remark: null,
+        isDel: null,
+        costPrice: null,
+        verifyCode: null,
+        shippingType: null,
+        isChannel: null,
+        isPrescribe: null,
+        prescribeId: null,
+        finishTime: null,
+        deliveryTime: null,
+        tuiMoney: null,
+        tuiMoneyStatus: 0,
+        tuiUserId: null,
+        orderCreateType: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+   handleClickX(tab, event) {
+    if(tab.name=="10"){
+      this.queryParams.status=null;
+    }else{
+      this.queryParams.status=tab.name;
+    }
+     this.handleQuery();
+   },
+  changeTime(){
+        if(this.createTime!=null){
+          this.queryParams.sTime=this.createTime[0];
+          this.queryParams.eTime=this.createTime[1];
+        }else{
+          this.queryParams.sTime=null;
+          this.queryParams.eTime=null;
+        }
+      },
+  }
+};
+</script>

+ 67 - 3
src/views/course/courseUserStatistics/qw/statistics.vue

@@ -13,7 +13,9 @@
       <el-form-item label="添加时间" prop="createTime">
         <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
       </el-form-item>
-      <el-form-item label="公司名称" prop="companyId">
+      
+      <el-form-item label="公司名称" prop="companyId" v-if="!showCompanyField"
+      >
         <el-select style="width: 220px" filterable v-model="queryParams.companyId" placeholder="请选择公司名" clearable size="small">
           <el-option
             v-for="item in companys"
@@ -22,7 +24,32 @@
             :value="item.companyId"
           />
         </el-select>
+      </el-form-item> 
+      <el-form-item label="公司" prop="companyId" v-else>
+        <select-tree
+            v-model="selectedCompanyList"
+            :raw-data="deptList"
+            :parentSelectable="true"
+            placeholder="请选择销售"
+            :multiple="true"
+            component-width="300px"
+            :max-display-tags="3"
+            :check-strictly="false"
+            :return-leaf-only="false"
+            @change="handleMultiChange"
+        ></select-tree>
       </el-form-item>
+      <!-- <el-form-item label="公司名称" prop="companyId" v-else
+      >
+        <el-select style="width: 220px" filterable v-model="queryParams.companyId" placeholder="请选择公司名" clearable size="small">
+          <el-option
+            v-for="item in companys"
+            :key="item.companyId"
+            :label="item.companyName"
+            :value="item.companyId"
+          />
+        </el-select>
+      </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>
@@ -462,11 +489,14 @@
 </template>
 
 <script>
+import SelectTree from "@/components/TreeSelect/index.vue";
+import { getDeptData } from '@/api/system/employeeStats'
 import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,statisticsList,qwWatchLogStatisticsList,qwWatchLogAllStatisticsList } from "@/api/course/courseWatchLog";
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getCompanyList} from "@/api/company/company";
 export default {
   name: "CourseWatchLog",
+  components: {SelectTree},
   data() {
     return {
       companys: [],
@@ -513,6 +543,7 @@ export default {
         eTime:null,
         scheduleStartTime: null,
         scheduleEndTime: null,
+        userIds:[],
       },
       // 表单参数
       form: {},
@@ -520,8 +551,18 @@ export default {
       rules: {
       },
       scheduleTime: null,
+       // 选中的公司列表
+    selectedCompanyList: null,
+    // 部门/公司树形数据
+    deptList: [],
     };
   },
+computed: {
+    // 计算属性判断是否显示
+    showCompanyField() {
+      return process.env.VUE_APP_TITLE_INDEX === '挑宝网';
+    },
+  },
   created() {
     getCompanyList().then(response => {
       this.companys = response.data;
@@ -534,6 +575,7 @@ export default {
     this.getDicts("sys_course_watch_log_type").then(response => {
       this.logTypeOptions = response.data;
     });
+    this.initCompanyData();
   },
   methods: {
     courseChange(row){
@@ -566,13 +608,18 @@ export default {
     },
     /** 查询短链课程看课记录列表 */
     getList() {
+    if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = JSON.stringify(this.selectedCompanyList);
+    } else {
+        this.queryParams.userIds = [];
+    }
       this.loading = true;
-      qwWatchLogAllStatisticsList(this.queryParams).then(response => {
+    qwWatchLogAllStatisticsList(this.queryParams).then(response => {
         this.courseWatchLogList = response.rows;
         this.total = response.total;
       }).finally(()=>{
         this.loading = false;
-      })
+      })      
     },
     // 取消按钮
     cancel() {
@@ -604,6 +651,7 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+        this.selectedCompanyList = []; // 清空公司选择
       this.resetForm("queryForm");
       this.createTime = null;
       this.scheduleTime = null;
@@ -671,6 +719,11 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
+        if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+    this.queryParams.userIds = this.selectedCompanyList;
+  } else {
+    this.queryParams.userIds = [];
+  }
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
           confirmButtonText: "确定",
@@ -693,6 +746,17 @@ export default {
         this.queryParams.scheduleEndTime = null;
       }
     },
+    // 公司选择框变化处理
+  handleMultiChange(e) {
+    // 处理公司选择变化
+    // console.log(this.selectedCompanyList)
+  },
+  // 初始化获取公司数据
+  initCompanyData() {
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    });
+  },
   }
 };
 </script>

+ 54 - 2
src/views/course/courseWatchLog/qw/statistics.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="公司名" prop="companyId">
+      <el-form-item label="公司名" prop="companyId" v-if="!showCompanyField">
         <el-select filterable style="width: 220px" v-model="queryParams.companyId" placeholder="请选择公司名" clearable size="small">
           <el-option
             v-for="item in companys"
@@ -11,6 +11,20 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="公司" prop="companyId" v-else>
+        <select-tree
+            v-model="selectedCompanyList"
+            :raw-data="deptList"
+            :parentSelectable="true"
+            placeholder="请选择销售"
+            :multiple="true"
+            component-width="300px"
+            :max-display-tags="3"
+            :check-strictly="false"
+            :return-leaf-only="false"
+            @change="handleMultiChange"
+        ></select-tree>
+      </el-form-item>
       <el-form-item label="课程" prop="courseId">
         <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" @change="courseChange(queryParams.courseId)">
           <el-option
@@ -111,6 +125,8 @@
 </template>
 
 <script>
+  import SelectTree from "@/components/TreeSelect/index.vue";
+import { getDeptData } from '@/api/system/employeeStats'
 import {
   listCourseWatchLog,
   getCourseWatchLog,
@@ -127,6 +143,8 @@ import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getCompanyList} from "@/api/company/company";
 export default {
   name: "CourseWatchLog",
+    components: {SelectTree},
+
   data() {
     return {
       signProjectName:"",
@@ -174,6 +192,7 @@ export default {
         eTime:null,
         scheduleStartTime: null,
         scheduleEndTime: null,
+        userIds:[],
       },
       // 表单参数
       form: {},
@@ -181,8 +200,18 @@ export default {
       rules: {
       },
       scheduleTime: null,
+             // 选中的公司列表
+    selectedCompanyList: null,
+    // 部门/公司树形数据
+    deptList: [],
     };
   },
+  computed: {
+    // 计算属性判断是否显示
+    showCompanyField() {
+      return process.env.VUE_APP_TITLE_INDEX === '挑宝网';
+    },
+  },
   created() {
     getSignProjectName().then(res=>{
       this.signProjectName = res.signProjectName;
@@ -203,10 +232,16 @@ export default {
     this.getDicts("sys_course_watch_log_type").then(response => {
       this.logTypeOptions = response.data;
     });
+    this.initCompanyData();
   },
   methods: {
 
     handleStatisExport(){
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+    this.queryParams.userIds = this.selectedCompanyList;
+  } else {
+    this.queryParams.userIds = [];
+  }
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有会员看课统计数据项?', "警告", {
         confirmButtonText: "确定",
@@ -281,6 +316,11 @@ export default {
     },
     /** 查询短链课程看课记录列表 */
     getList() {
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = JSON.stringify(this.selectedCompanyList);
+    } else {
+        this.queryParams.userIds = [];
+    }
       this.loading = true;
       statisticsList(this.queryParams).then(response => {
         this.courseWatchLogList = response.rows;
@@ -313,7 +353,7 @@ export default {
     },
     /** 搜索按钮操作 */
     handleQuery() {
-      if(this.queryParams.companyId == null) {
+      if(this.queryParams.companyId == null && (this.selectedCompanyList == null ||this.selectedCompanyList.length == 0)) {
         this.$message.warning("公司不能为空!")
         return;
       }
@@ -322,6 +362,7 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.selectedCompanyList = [];
       this.resetForm("queryForm");
       this.createTime = null;
       this.scheduleTime = null;
@@ -411,6 +452,17 @@ export default {
         this.queryParams.scheduleEndTime = null;
       }
     },
+        // 公司选择框变化处理
+  handleMultiChange(e) {
+    // 处理公司选择变化
+    // console.log(this.selectedCompanyList)
+  },
+  // 初始化获取公司数据
+  initCompanyData() {
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    });
+  },
   }
 };
 </script>

+ 20 - 2
src/views/course/videoResource/index.vue

@@ -508,7 +508,21 @@
         </el-table-column>
         <el-table-column label="操作" align="center" width="150">
           <template slot-scope="scope">
-            <el-button size="mini" type="text" icon="el-icon-edit" @click="handleEditVideo(scope.row)">编辑</el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-edit"
+              :disabled="scope.row.progress !== 100"
+              @click="handleEditVideo(scope.row)">
+              编辑
+              <el-tooltip
+                v-if="scope.row.progress !== 100"
+                content="上传完成后可编辑"
+                placement="top"
+              >
+                <i class="el-icon-question"></i>
+              </el-tooltip>
+            </el-button>
             <el-button
               size="mini"
               type="text"
@@ -1677,6 +1691,10 @@ export default {
     },
     /** 编辑视频信息 */
     handleEditVideo(row) {
+      if (row.progress !== 100) {
+        this.$message.warning('请等待上传完成后再编辑');
+        return;
+      }
       this.batchEditDialog.form = Object.assign({}, row)
       this.changeCateType(row.typeId)
       this.batchEditDialog.open = true
@@ -1945,7 +1963,7 @@ export default {
 
         // 检查上传结果
         const line1Success = line1Result.status === 'fulfilled' && line1Result.value.success;
-        const line2Success = line1Result.status === 'fulfilled' && line1Result.value.success;
+        const line2Success = line2Result.status === 'fulfilled' && line2Result.value.success;
 
         const index = this.videoList.findIndex(item => item.tempId === tempVideo.tempId);
         if (index !== -1) {

+ 12 - 1
src/views/his/companyRecharge/index.vue

@@ -112,8 +112,19 @@
       </el-table-column>
       <el-table-column label="余额" align="center" prop="balance" />
       <el-table-column label="提交人" align="center" prop="createUserNickName" />
-
       <el-table-column label="审核人" align="center" prop="auditUserNickName" />
+      <el-table-column label="凭证照片" align="center" prop="imgs" >
+        <template slot-scope="scope">
+          <div v-if="scope.row.imgs != null && scope.row.imgs != undefined && scope.row.imgs != ''">
+            <el-image
+              style="width: 80px; height: 80px"
+              :src="scope.row.imgs.split(',')[0]"
+              :preview-src-list="scope.row.imgs.split(',')">
+            </el-image>
+            <p style="margin: 0">({{scope.row.imgs.split(',').length}} 张)</p>
+          </div>
+        </template>
+      </el-table-column>
       <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="支付时间" align="center" prop="payTime" width="180"/>
       <el-table-column label="审核时间" align="center" prop="auditTime" width="180"/>

+ 178 - 98
src/views/his/integralOrder/index.vue

@@ -157,7 +157,7 @@
           v-hasPermi="['his:integralOrder:export']"
         >导出</el-button>
       </el-col>
-      
+
       <el-col :span="1.5">
           <el-button
             type="info"
@@ -220,17 +220,12 @@
       <el-table-column label="ERP账号" align="center" prop="loginAccount" />
       <el-table-column label="ERP电话" align="center" prop="erpPhone" />
       <el-table-column label="订单编号" align="center" prop="orderCode" />
-      <el-table-column label="商品名称" align="center" width="200">
+      <el-table-column label="商品信息" align="center" width="200">
         <template slot-scope="scope">
           <div style="display: flex; align-items: center; justify-content: center;">
-            <span>{{ scope.row.goodsName }}</span>
-            <el-image
-              v-if="scope.row.goodsImage"
-              :src="scope.row.goodsImage"
-              style="width: 40px; height: 40px; margin-left: 8px;"
-              fit="cover"
-              :preview-src-list="[scope.row.goodsImage]"
-            />
+            <span style="white-space: pre-line; text-align: left;">{{ scope.row.goodsName }}</span>
+            <!-- 这里移除了num显示,因为现在goodsName已经包含数量信息 -->
+            <!-- 如果你还需要显示其他内容,可以放在这里 -->
           </div>
         </template>
       </el-table-column>
@@ -378,9 +373,9 @@
       <div v-loading="erpAccountDialog.loading">
         <el-form :model="erpAccountForm" label-width="100px">
           <el-form-item label="ERP账户" required>
-            <el-select 
-              v-model="erpAccountForm.selectedAccount" 
-              placeholder="请选择ERP账户" 
+            <el-select
+              v-model="erpAccountForm.selectedAccount"
+              placeholder="请选择ERP账户"
               style="width: 100%"
               filterable
             >
@@ -393,9 +388,9 @@
             </el-select>
           </el-form-item>
           <el-form-item label="推送手机号">
-            <el-select 
-              v-model="erpAccountForm.selectedPhones" 
-              multiple 
+            <el-select
+              v-model="erpAccountForm.selectedPhones"
+              multiple
               placeholder="请选择推送手机号,不填默认订单用户电话"
               style="width: 100%"
               filterable
@@ -409,7 +404,7 @@
             </el-select>
           </el-form-item>
         </el-form>
-        
+
         <!-- 订单统计信息 -->
         <div class="order-summary" v-if="orderSummary">
           <el-divider content-position="left">订单统计</el-divider>
@@ -435,11 +430,11 @@
           </el-row>
         </div>
       </div>
-      
+
       <div slot="footer" class="dialog-footer">
         <el-button @click="cancelErpAccountDialog">取 消</el-button>
-        <el-button 
-          type="primary" 
+        <el-button
+          type="primary"
           @click="confirmCreateErpOrder"
           :disabled="!erpAccountForm.selectedAccount"
           :loading="erpAccountDialog.submitting"
@@ -454,9 +449,9 @@
       <el-table :data="phoneList" border style="width: 100%">
         <el-table-column prop="phone" label="手机号" align="center">
           <template slot-scope="scope">
-            <el-input 
-              v-if="scope.row.editing" 
-              v-model="scope.row.phone" 
+            <el-input
+              v-if="scope.row.editing"
+              v-model="scope.row.phone"
               placeholder="请输入手机号"
               @blur="validatePhone(scope.row)"
               @keyup.enter.native="handleSavePhone(scope.$index)"
@@ -466,27 +461,27 @@
         </el-table-column>
         <el-table-column label="操作" align="center" width="300">
           <template slot-scope="scope">
-            <el-button 
-              v-if="scope.row.editing" 
-              type="success" 
-              size="mini" 
+            <el-button
+              v-if="scope.row.editing"
+              type="success"
+              size="mini"
               @click="handleSavePhone(scope.$index)"
             >保存</el-button>
-            <el-button 
-              v-if="scope.row.editing" 
-              type="info" 
-              size="mini" 
+            <el-button
+              v-if="scope.row.editing"
+              type="info"
+              size="mini"
               @click="handleCancelEdit(scope.$index)"
             >取消</el-button>
-            <el-button 
-              v-if="!scope.row.editing" 
-              type="primary" 
-              size="mini" 
+            <el-button
+              v-if="!scope.row.editing"
+              type="primary"
+              size="mini"
               @click="handleEditPhone(scope.$index)"
             >修改</el-button>
-            <el-button 
-              type="danger" 
-              size="mini" 
+            <el-button
+              type="danger"
+              size="mini"
               @click="handleDeletePhone(scope.$index)"
             >删除</el-button>
           </template>
@@ -525,12 +520,12 @@
         <el-button @click="uploadStatus.open = false">取 消</el-button>
       </div>
     </el-dialog>
-    
+
     <!-- 导入结果对话框 -->
-    <el-dialog 
-      title="导入结果" 
-      :visible.sync="importResultDialog.open" 
-      width="80%" 
+    <el-dialog
+      title="导入结果"
+      :visible.sync="importResultDialog.open"
+      width="80%"
       append-to-body
       :close-on-click-modal="false"
     >
@@ -556,12 +551,12 @@
           </el-col>
         </el-row>
       </div>
-      
+
       <el-tabs v-model="importResultTab" type="card">
         <el-tab-pane label="成功列表" name="success">
-          <el-table 
-            :data="displayedSuccessList" 
-            border 
+          <el-table
+            :data="displayedSuccessList"
+            border
             stripe
             height="400"
             style="width: 100%"
@@ -577,9 +572,9 @@
           </div>
         </el-tab-pane>
         <el-tab-pane label="失败列表" name="failure">
-          <el-table 
-            :data="displayedFailureList" 
-            border 
+          <el-table
+            :data="displayedFailureList"
+            border
             stripe
             height="400"
             style="width: 100%"
@@ -596,7 +591,7 @@
           </div>
         </el-tab-pane>
       </el-tabs>
-      
+
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="importResultDialog.open = false">关 闭</el-button>
       </div>
@@ -789,7 +784,7 @@ export default {
       this.uploadStatus.open = false;
       this.uploadStatus.isUploading = false;
       this.$refs.uploadStatus.clearFiles();
-      
+
       // 处理新的返回结果格式
       if (response.code === 200 && response.data) {
         this.importResult = response.data;
@@ -798,32 +793,32 @@ export default {
         this.displayedFailureList = [];
         this.successListCurrentPage = 1;
         this.failureListCurrentPage = 1;
-        
+
         // 加载第一页数据
         this.loadSuccessListPage(1);
         this.loadFailureListPage(1);
-        
+
         // 显示结果对话框
         this.importResultDialog.open = true;
         this.importResultTab = this.importResult.failureNum > 0 ? "failure" : "success";
       } else {
         this.$alert(response.msg || "导入失败", "导入结果", { dangerouslyUseHTMLString: true });
       }
-      
+
       this.getList();
     },
     // 加载成功列表分页数据
     loadSuccessListPage(page) {
       if (this.successListLoading) return;
       this.successListLoading = true;
-      
+
       const start = (page - 1) * this.successListPageSize;
       const end = start + this.successListPageSize;
       const pageData = this.importResult.successList.slice(start, end);
-      
+
       this.displayedSuccessList = this.displayedSuccessList.concat(pageData);
       this.successListCurrentPage = page;
-      
+
       this.$nextTick(() => {
         this.successListLoading = false;
         // 绑定滚动事件
@@ -836,14 +831,14 @@ export default {
     loadFailureListPage(page) {
       if (this.failureListLoading) return;
       this.failureListLoading = true;
-      
+
       const start = (page - 1) * this.failureListPageSize;
       const end = start + this.failureListPageSize;
       const pageData = this.importResult.failureList.slice(start, end);
-      
+
       this.displayedFailureList = this.displayedFailureList.concat(pageData);
       this.failureListCurrentPage = page;
-      
+
       this.$nextTick(() => {
         this.failureListLoading = false;
         // 绑定滚动事件
@@ -861,7 +856,7 @@ export default {
           successTableBody.removeEventListener('scroll', this.handleSuccessListScroll);
           successTableBody.addEventListener('scroll', this.handleSuccessListScroll);
         }
-        
+
         // 失败列表滚动
         const failureTableBody = document.querySelector('.el-dialog__body .el-tabs__content .el-tab-pane:last-child .el-table__body-wrapper');
         if (failureTableBody) {
@@ -876,7 +871,7 @@ export default {
       const scrollTop = container.scrollTop;
       const scrollHeight = container.scrollHeight;
       const clientHeight = container.clientHeight;
-      
+
       // 距离底部50px时加载下一页
       if (scrollHeight - scrollTop - clientHeight < 50) {
         const totalPages = Math.ceil(this.importResult.successList.length / this.successListPageSize);
@@ -891,7 +886,7 @@ export default {
       const scrollTop = container.scrollTop;
       const scrollHeight = container.scrollHeight;
       const clientHeight = container.clientHeight;
-      
+
       // 距离底部50px时加载下一页
       if (scrollHeight - scrollTop - clientHeight < 50) {
         const totalPages = Math.ceil(this.importResult.failureList.length / this.failureListPageSize);
@@ -965,15 +960,98 @@ export default {
         }, 1);
     },
     /** 查询积分商品订单列表 */
+    /** 查询积分商品订单列表 */
     getList() {
       this.loading = true;
-      
+
       // 直接传递订单编号数组给后端
       listIntegralOrder(this.queryParams).then(response => {
         // 解析itemJson字段,提取goodsName和图片
         const processedData = response.rows.map(item => {
           let goodsName = '';
           let goodsImage = '';
+          let num = '';
+          try {
+            if (item.itemJson) {
+              const itemData = JSON.parse(item.itemJson);
+
+              // 如果itemJson是数组格式,遍历数组并用换行分隔每个商品
+              if (Array.isArray(itemData) && itemData.length > 0) {
+                // 提取所有商品的信息,每个商品一行
+                const goodsInfoList = itemData
+                  .filter(goods => goods.goodsName)
+                  .map(goods => {
+                    const name = goods.goodsName || '';
+                    const itemNum = goods.num || 1; // 如果没有数量,默认1
+                    return `${name},数量:${itemNum}个`;
+                  });
+
+                // 如果有多个商品,用换行符分隔
+                if (goodsInfoList.length > 0) {
+                  goodsName = goodsInfoList.join('\n');
+                } else if (itemData[0].goodsName) {
+                  // 如果没有商品名称但有第一个商品对象,使用第一个
+                  const firstItem = itemData[0];
+                  goodsName = `${firstItem.goodsName || ''},数量:${firstItem.num || 1}个`;
+                }
+
+                // 提取第一个商品的图片
+                const firstItem = itemData[0];
+                if (firstItem.imgUrl) {
+                  goodsImage = firstItem.imgUrl;
+                } else if (firstItem.images && firstItem.images.split(',').length > 0) {
+                  goodsImage = firstItem.images.split(',')[0];
+                }
+              }
+              // 如果itemJson是对象格式,直接取goodsName和图片
+              else if (itemData.goodsName) {
+                goodsName = `${itemData.goodsName},数量:${itemData.num || 1}个`;
+
+                // 提取图片,优先使用imgUrl,如果没有则使用images的第一张
+                if (itemData.imgUrl) {
+                  goodsImage = itemData.imgUrl;
+                } else if (itemData.images && itemData.images.split(',').length > 0) {
+                  goodsImage = itemData.images.split(',')[0];
+                }
+              }
+            }
+          } catch (error) {
+            console.error('解析itemJson失败:', error);
+            goodsName = '';
+            goodsImage = '';
+            num = '';
+          }
+
+          return {
+            ...item,
+            goodsName: goodsName,
+            goodsImage: goodsImage,
+            num: num
+          };
+        });
+
+        this.integralOrderList = processedData;
+        this.total = response.total;
+        this.loading = false;
+      }).catch(error => {
+        console.error('查询订单列表失败:', error);
+        this.loading = false;
+        this.$message.error('查询订单列表失败');
+      });
+    },
+
+    /** 查询积分商品订单列表 */
+    //原代码 先留着
+    getList0() {
+      this.loading = true;
+
+      // 直接传递订单编号数组给后端
+      listIntegralOrder(this.queryParams).then(response => {
+        // 解析itemJson字段,提取goodsName和图片
+        const processedData = response.rows.map(item => {
+          let goodsName = '';
+          let goodsImage = '';
+          let num = '';
           try {
             if (item.itemJson) {
               const itemData = JSON.parse(item.itemJson);
@@ -1002,15 +1080,17 @@ export default {
             console.error('解析itemJson失败:', error);
             goodsName = '';
             goodsImage = '';
+            num ='';
           }
-          
+
           return {
             ...item,
             goodsName: goodsName,
-            goodsImage: goodsImage
+            goodsImage: goodsImage,
+            num: num
           };
         });
-        
+
         this.integralOrderList = processedData;
         this.total = response.total;
         this.loading = false;
@@ -1062,12 +1142,12 @@ export default {
       this.queryParams.qwUserId=null;
       this.queryParams.companyId=null;
       this.queryParams.companyUserId=null;
-      
+
       // 清除订单号标签
       this.queryParams.orderCodes = [];
       this.currentInput = '';
       this.inputVisible = false;
-      
+
       this.handleQuery();
 
     },
@@ -1169,7 +1249,7 @@ export default {
       this.getErpPhoneList(); // 加载手机号列表
       this.updateOrderSummary();
     },
-    
+
     // 加载ERP账户数据
     async loadErpAccountData() {
       try {
@@ -1179,7 +1259,7 @@ export default {
         console.error('加载ERP账户失败:', error);
       }
     },
-    
+
     // 更新订单统计
     updateOrderSummary() {
       // 如果没有选择任何数据,则使用查询出来的所有数据
@@ -1191,14 +1271,14 @@ export default {
         this.orderSummary.selectedCount = this.ids.length;
         this.orderSummary.queryCount = this.total;
       }
-      
+
       // 计算总金额(这里需要根据实际数据结构调整)
       this.calculateTotalAmount();
     },
     // 计算总金额
     calculateTotalAmount() {
       let totalAmount = 0;
-      
+
       if (this.ids.length === 0) {
         // 使用所有查询数据计算金额
         this.integralOrderList.forEach(order => {
@@ -1206,28 +1286,28 @@ export default {
         });
       } else {
         // 使用选中的数据计算金额
-        const selectedOrders = this.integralOrderList.filter(order => 
+        const selectedOrders = this.integralOrderList.filter(order =>
           this.ids.includes(order.orderId)
         );
         selectedOrders.forEach(order => {
           totalAmount += parseFloat(order.payMoney || 0);
         });
       }
-      
+
       this.orderSummary.totalAmount = totalAmount.toFixed(2);
     },
-    
+
     // 取消ERP账户对话框
     cancelErpAccountDialog() {
       this.erpAccountDialog.open = false;
       this.erpAccountForm.selectedAccount = null;
     },
-    
+
     // 确认创建ERP订单
     async confirmCreateErpOrder() {
       // 收集选中的orderId
       let selectedOrderIds = [];
-      
+
       if (this.ids.length === 0) {
         // 如果没有选择任何数据,使用查询出来的所有数据的orderId
         selectedOrderIds = this.integralOrderList.map(order => order.orderId);
@@ -1235,11 +1315,11 @@ export default {
         // 如果选择了数据,使用选中的orderId
         selectedOrderIds = this.ids;
       }
-      
+
       // 收集ERP账户和手机号
       const selectedErpAccount = this.erpAccountForm.selectedAccount;
       const selectedPhones = this.erpAccountForm.selectedPhones;
-      
+
       // 准备请求参数
       const params = {
         orderIds: selectedOrderIds,
@@ -1248,7 +1328,7 @@ export default {
       };
       try {
         this.erpAccountDialog.submitting = true;
-        
+
         // 根据弹窗标题判断是数据分拣还是创建ERP
         if (this.erpAccountDialog.title === "数据分拣") {
           // 调用数据分拣接口
@@ -1260,13 +1340,13 @@ export default {
           // console.log("参数:",params)
           this.$message.success('创建ERP成功');
         }
-        
+
         // 关闭弹窗
         this.cancelErpAccountDialog();
-        
+
         // 刷新列表
         this.getList();
-        
+
       } catch (error) {
         console.error('操作失败:', error);
         this.$message.error('操作失败');
@@ -1334,7 +1414,7 @@ export default {
         return;
       }
       // 检查是否重复
-      const duplicateIndex = this.phoneList.findIndex((item, idx) => 
+      const duplicateIndex = this.phoneList.findIndex((item, idx) =>
         idx !== index && item.phone === phone
       );
       if (duplicateIndex !== -1) {
@@ -1390,17 +1470,17 @@ export default {
         this.$message.error('请先保存正在编辑的手机号');
         return;
       }
-      
+
       // 检查是否有空的手机号
       const emptyPhone = this.phoneList.find(item => !item.phone.trim());
       if (emptyPhone) {
         this.$message.error('存在空的手机号,请删除或填写完整');
         return;
       }
-      
+
       // 构造手机号列表
       const phoneList = this.phoneList.map(item => item.phone);
-      
+
       // 调用保存接口
       saveErpPhone(phoneList).then(response => {
         if (response.code === 200) {
@@ -1425,13 +1505,13 @@ export default {
     // 处理键盘按下事件
     handleKeyDown(event) {
       const { key, target } = event
-      
+
       // 处理退格键删除标签
       if (key === 'Backspace' && !target.value && this.queryParams.orderCodes.length > 0) {
         event.preventDefault()
         this.removeOrderCode(this.queryParams.orderCodes.length - 1)
       }
-      
+
       // 处理分隔符
       if ([',', ',', ' ', 'Enter'].includes(key)) {
         event.preventDefault()
@@ -1442,7 +1522,7 @@ export default {
     // 处理键盘抬起事件(实时分割输入)
     handleKeyUp(event) {
       const value = event.target.value
-      
+
       // 检查是否包含分隔符
       if (/[,,\s]/.test(value)) {
         this.handleInputConfirm()
@@ -1452,35 +1532,35 @@ export default {
     // 确认输入
     handleInputConfirm() {
       const inputValue = this.currentInput.trim()
-      
+
       if (inputValue) {
         // 分割多个订单号
         const codes = inputValue.split(/[,,\s]+/).filter(code => code.trim())
-        
+
         codes.forEach(code => {
           this.addOrderCode(code.trim())
         })
       }
-      
+
       this.currentInput = ''
     },
 
     // 添加订单号
     addOrderCode(code) {
       if (!code) return
-      
+
       // 检查数量限制
       if (this.maxOrderCodes > 0 && this.queryParams.orderCodes.length >= this.maxOrderCodes) {
         this.$message.warning(`最多只能添加 ${this.maxOrderCodes} 个订单号`)
         return
       }
-      
+
       // 检查重复
       if (this.queryParams.orderCodes.includes(code)) {
         this.$message.warning(`订单号 "${code}" 已存在`)
         return
       }
-      
+
       // 添加到列表
       this.queryParams.orderCodes.push(code)
     },

+ 781 - 6
src/views/hisStore/components/productOrder.vue

@@ -176,13 +176,34 @@
         </el-dialog>
       <div style="margin-top: 20px">
         <span class="font-small">商品信息</span>
+        <el-button
+          class="select-product-btn"
+          @click="openProductSelection"
+          icon="el-icon-shopping-cart-2"
+          size="small"
+          type="primary"
+          v-hasPermi="['store:storeOrderItem:add']" >
+          新增商品
+        </el-button>
+        <el-button
+          class="remove-product-btn"
+          @click="removeSelectedProduct"
+          icon="el-icon-delete"
+          size="small"
+          type="danger"
+          v-hasPermi="['store:storeOrderItem:remove']">
+          移除商品
+        </el-button>
       </div>
       <el-table
+        ref="itemsTable"
         border
         v-if="items!=null"
         :data="items"
         size="small"
-        style="width: 100%;margin-top: 20px" >
+        style="width: 100%;margin-top: 20px"
+        @selection-change="handleItemsSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="商品图片" width="150" align="center">
           <template slot-scope="scope">
             <img :src="JSON.parse(scope.row.jsonInfo).image" style="height: 80px">
@@ -215,9 +236,23 @@
         </el-table-column>
         <el-table-column label="数量" width="180" align="center">
           <template slot-scope="scope">
-            {{scope.row.num}}
+            <div class="quantity-cell">
+              <div class="quantity-display">
+                <span class="quantity-value">{{scope.row.num}}</span>
+              </div>
+              <el-button
+                size="mini"
+                type="default"
+                icon="el-icon-edit"
+                class="edit-quantity-btn"
+                @click="showQuantityEdit(scope)"
+                v-hasPermi="['store:storeOrderItem:updateNum']">
+                修改数量
+              </el-button>
+            </div>
           </template>
         </el-table-column>
+
         <el-table-column label="处方药" width="240" align="center">
           <template slot-scope="scope">
             {{scope.row.isPrescribe!=null&&scope.row.isPrescribe==1?'是':'否'}}
@@ -235,7 +270,7 @@
       <div style="margin: 60px 0px 20px 0px">
         <span class="font-small">费用信息</span>
       </div>
-      <el-descriptions   :column="4" border  >
+      <el-descriptions v-if="zdyInfo !== 'gzzdy'"   :column="4" border  >
           <el-descriptions-item label="商品合计"  >
               <span v-if="order!=null">
                 ¥{{order.totalPrice.toFixed(2)}}
@@ -273,6 +308,34 @@
           </el-descriptions-item>
       </el-descriptions>
 
+      <el-descriptions v-if="zdyInfo === 'gzzdy'"   :column="4" border  >
+          <el-descriptions-item label="商品合计"  >
+              <span v-if="order!=null">
+                ¥{{order.totalPrice.toFixed(2)}}
+              </span>
+          </el-descriptions-item>
+          <el-descriptions-item label="应付金额"  >
+              <span v-if="order!=null">
+                ¥{{order.payPrice.toFixed(2)}}
+              </span>
+          </el-descriptions-item>
+          <el-descriptions-item label="实付金额"  >
+              <span v-if="order!=null">
+                ¥{{order.payMoney.toFixed(2)}}
+              </span>
+          </el-descriptions-item>
+          <el-descriptions-item label="代收金额"  >
+              <span v-if="order!=null">
+                ¥{{order.payDelivery.toFixed(2)}}
+              </span>
+          </el-descriptions-item>
+          <el-descriptions-item label="优惠券"  >
+              <span v-if="order!=null">
+                ¥{{order.couponPrice.toFixed(2)}}
+              </span>
+          </el-descriptions-item>
+      </el-descriptions>
+
       <div style="margin-top: 20px">
         <span class="font-small">支付信息</span>
       </div>
@@ -495,23 +558,287 @@
       </div>
     </el-dialog>
 
+    <!-- 数量修改弹窗 -->
+    <el-dialog :title="quantityDialog.title" :visible.sync="quantityDialog.open" width="500px" append-to-body>
+      <el-form ref="quantityForm" :model="quantityForm" :rules="quantityRules" label-width="100px">
+        <el-form-item label="商品名称">
+          <span class="dialog-product-name">{{quantityForm.productName}}</span>
+        </el-form-item>
+
+        <el-form-item label="当前单价">
+          <el-tag type="info" size="medium">¥{{ quantityForm.price ? quantityForm.price.toFixed(2) : '0.00' }}</el-tag>
+        </el-form-item>
+
+        <el-form-item label="当前数量">
+          <el-tag type="info" size="medium">{{ quantityForm.originalNum }}</el-tag>
+        </el-form-item>
+
+        <el-form-item label="新数量" prop="newNum">
+          <el-input-number
+            v-model="quantityForm.newNum"
+            :min="1"
+            :max="999999"
+            controls-position="right"
+            style="width: 200px">
+          </el-input-number>
+        </el-form-item>
+
+        <el-form-item label="总金额">
+          <el-tag type="danger" size="medium">
+            ¥{{ (quantityForm.newNum * quantityForm.price).toFixed(2) }}
+          </el-tag>
+        </el-form-item>
+      </el-form>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="quantityDialog.open = false">取 消</el-button>
+        <el-button type="primary" @click="submitQuantityForm">确 定</el-button>
+      </div>
+    </el-dialog>
+    <!-- 新增商品弹窗 -->
+    <el-dialog :title="productOrderDialog.title" :visible.sync="productOrderDialog.open" width="1800px" append-to-body>
+      <div class="app-container">
+        <el-form :model="productOrderQueryParams" ref="productOrderQueryForm" :inline="true" label-width="68px">
+          <el-form-item label="商品分类" prop="cateId">
+            <treeselect  v-model="productOrderQueryParams.cateId"  style="width:205.4px" :options="categoryOptions" :normalizer="normalizer" placeholder="请选择分类" />
+          </el-form-item>
+          <el-form-item label="商品名称" prop="productName">
+            <el-input
+              v-model="productOrderQueryParams.productName"
+              placeholder="请输入商品名称"
+              clearable
+              size="small"
+              @keyup.enter.native="productOrderHandleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="商品编号" prop="barCode">
+            <el-input
+              v-model="productOrderQueryParams.barCode"
+              placeholder="请输入商品编号"
+              clearable
+              size="small"
+              @keyup.enter.native="productOrderHandleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="商品类型" prop="productType">
+            <el-select   v-model="productOrderQueryParams.productType" placeholder="请选择商品类型" clearable size="small" >
+              <el-option
+                v-for="item in productTypeOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="所属公司">
+            <el-select style="width: 240px" v-model="companyId" multiple placeholder="请选择企业" clearable size="small" >
+              <el-option
+                v-for="item in companyOptions"
+                :key="item.companyId"
+                :label="item.companyName"
+                :value="item.companyId"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="所属店铺" v-if="this.isStores">
+            <el-select style="width: 240px" v-model="productOrderQueryParams.storeIds" placeholder="请选择店铺" clearable size="small" >
+              <el-option
+                v-for="item in storeOptions"
+                :key="item.storeId"
+                :label="item.storeName"
+                :value="item.storeId"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="cyan" icon="el-icon-search" size="mini" @click="productOrderHandleQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="productOrderResetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table
+          ref="productOrderTable"
+          height="500"
+          border
+          v-loading="productOrderLoading"
+          :data="storeProductList"
+          @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="ID" align="center" prop="productId" />
+        <el-table-column label="商品图片" align="center" width="120">
+          <template slot-scope="scope">
+            <el-popover
+              placement="right"
+              title=""
+              trigger="hover">
+              <img slot="reference" :src="scope.row.image" width="100">
+              <img :src="scope.row.image" style="max-width: 150px;">
+            </el-popover>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品名称" show-overflow-tooltip align="center" prop="productName" />
+        <el-table-column label="分类" align="center" prop="cateName" />
+        <el-table-column label="所属公司" align="center" prop="companyName" />
+        <el-table-column label="所属店铺" align="center" prop="storeName" v-if="this.isStores"/>
+        <el-table-column label="售价" align="center" prop="price" >
+          <template slot-scope="scope" >
+            <span v-if="scope.row.price!=null">{{scope.row.price.toFixed(2)}}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="原价" align="center" prop="otPrice" >
+          <template slot-scope="scope" >
+            <span v-if="scope.row.otPrice!=null">{{scope.row.otPrice.toFixed(2)}}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="销量" align="center" prop="sales" />
+        <el-table-column label="库存" align="center" prop="stock" />
+        <el-table-column label="类型" align="center" prop="productType" >
+          <template slot-scope="scope">
+            <el-tag prop="productType" v-for="(item, index) in productTypeOptions"    v-if="scope.row.productType==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="状态" align="center" prop="isShow" >
+          <template slot-scope="scope">
+            <el-tag :type="getStatusType(scope.row)" prop="status">
+              {{ getStatusText(scope.row) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="productOrderQueryParams.pageNum"
+        :limit.sync="productOrderQueryParams.pageSize"
+        @pagination="productOrderGetList"
+      />
+
+      <div style="text-align: center; margin-top: 20px;">
+        <el-button
+          type="primary"
+          size="medium"
+          icon="el-icon-plus"
+          @click="handleBatchAdd"
+          v-hasPermi="['store:storeOrderItem:add']"
+          :disabled="!ids || ids.length === 0">
+          批量添加商品
+        </el-button>
+      </div>
+    </div>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import {auditPayRemain,addTuiMoney,syncExpress,updateExpress,getEroOrder,refundOrderMoney, editTuiMoney,getExpress,finishOrder,listStoreOrder, getStoreOrder, delStoreOrder, addStoreOrder, updateStoreOrder, exportStoreOrder,updateDeliveryId, createErpOrder,updateErp,getStoreOrderAddress,getStoreOrderPhone} from "@/api/hisStore/storeOrder";
-import { getTcmScheduleList } from "@/api/company/schedule";
+import {
+  addTuiMoney,
+  auditPayRemain,
+  createErpOrder,
+  editTuiMoney,
+  finishOrder,
+  getEroOrder,
+  getExpress,
+  getStoreOrder,
+  getStoreOrderAddress,
+  getStoreOrderPhone,
+  refundOrderMoney,
+  syncExpress,
+  updateDeliveryId,
+  updateErp,
+  updateExpress,
+  updateStoreOrder,
+  updateStoreOrderItemJson
+} from "@/api/hisStore/storeOrder";
+import {listStoreProduct} from "@/api/hisStore/storeProduct";
+import {getTcmScheduleList} from "@/api/company/schedule";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import {getAllStoreProductCategory} from "@/api/hisStore/storeProductCategory";
+import Editor from '@/components/Editor/wang';
+import Material from '@/components/Material'
+import singleImg from '@/components/Material/single'
+import {getCompanyList} from "@/api/company/company";
+import {listStore} from '@/api/hisStore/store';
+import {addStoreOrderItem, delStoreOrderItem, updateNumStoreOrderItem} from "../../../api/hisStore/storeOrderItem";
+
+
 export default {
   name: "order",
+  components: {
+    Treeselect,
+    Editor,
+    Material,
+    singleImg,
+  },
   data() {
     return {
+      zdyInfo: process.env.VUE_APP_FS_USER_INFO,
+      isMedicalMall: this.$store.state.user.medicalMallConfig.medicalMall,
       dialogVisibleImage: false,
       createTypeOptions:[],
       deliveryStatusOptions:[],
       deliveryTypeOptions:[],
       scheduleOptions:[],
       schedules:[],
+      // 遮罩层
+      productOrderLoading: true,
+      isStores: true,
+      companyId: null,
+      storeId: null,
+      isAudit: null,
+      storeForm: {isAudit:1,status:1},
+      // 总条数
+      total: 0,
+      // 商品表格数据
+      storeProductList: [],
+      productTypeOptions:[],
+      productTuiCateOptions:[],
+      isDisplayOptions:[],
+      isGoodOptions:[],
+      isNewOptions:[],
+      isBestOptions:[],
+      isHotOptions:[],
+      isShowOptions:[],
+      categoryOptions:[],
+      // 企业列表
+      companyOptions:[],
+      storeOptions:[],
       orderId:null,
+      // 选中的商品列表
+      selectedItems: [],
+      // 批量添加时选中的商品ID列表
+      ids: [],
+      // 是否单选
+      single: true,
+      // 是否多选
+      multiple: true,
+      // 查询参数
+      productOrderQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        productName: null,
+        productType: null,
+        isShow: "1",
+        barCode:null,
+        companyIds: null,
+        storeIds: null,
+        drugRegCertNo: null,
+        commonName: null,
+        dosageForm: null,
+        unitPrice: null,
+        batchNumber: null,
+        mah: null,
+        mahAddress: null,
+        manufacturer: null,
+        manufacturerAddress: null,
+        indications: null,
+        dosage: null,
+        adverseReactions: null,
+        contraindications: null,
+        precautions: null,
+        excludeProductIds:[],
+      },
       erpDialog:{
         title:"ERP订单信息",
         open:false,
@@ -528,6 +855,10 @@ export default {
         title:"修改物流单号",
         open:false,
       },
+      productOrderDialog:{
+        title:"商品选择",
+        open:false,
+      },
       editDyForm:{
         deliverySn:null,
         deliveryId:null,
@@ -536,7 +867,6 @@ export default {
         orderType:null,
         status:null,
         userAddress:null,
-        // extendOrderId:null,
         scheduleId:null,
         mark:"",
       },
@@ -570,6 +900,29 @@ export default {
       tuiMoneyLogs:[],
       erpOrder:null,
       auditLogs: [],
+      // 数量修改弹窗相关数据
+      quantityDialog: {
+        title: "修改商品数量",
+        open: false,
+      },
+      quantityForm: {
+        itemId: null,
+        productName: null,
+        price: null,
+        //新数量
+        newNum: null,
+        //原始数量
+        originalNum: null
+      },
+      quantityRules: {
+        newNum: [
+          { required: true, message: "数量不能为空", trigger: "blur" },
+          { type: 'number', min: 1, message: "数量至少为1", trigger: "blur" },
+          { type: 'number', max: 999999, message: "数量不能超过999999", trigger: "blur" }
+        ]
+      },
+      // 删除商品相关
+      removeProductLoading: false
     };
   },
   created() {
@@ -597,6 +950,277 @@ export default {
     });
   },
   methods: {
+    // 显示修改数量弹窗
+    showQuantityEdit(scope) {
+      this.quantityForm.itemId = scope.row.itemId;
+      // 解析商品信息并处理可能的错误
+      let parsedJsonInfo;
+      try {
+        parsedJsonInfo = JSON.parse(scope.row.jsonInfo);
+      } catch (error) {
+        console.error('解析商品信息失败:', error);
+        parsedJsonInfo = {};
+      }
+
+      this.quantityForm.productName = parsedJsonInfo.productName || '';
+      this.quantityForm.originalNum = scope.row.num || 0;
+      this.quantityForm.newNum = scope.row.num || 0;
+
+      // 处理价格,确保不会为null
+      const price = parsedJsonInfo.price || 0;
+      this.quantityForm.price = parseFloat(price) || 0;
+      this.quantityDialog.open = true;
+    },
+
+  // 提交数量修改
+    submitQuantityForm() {
+      this.$refs["quantityForm"].validate(valid => {
+        if (valid) {
+          // 验证数量是否发生变化
+          if (this.quantityForm.newNum === this.quantityForm.originalNum) {
+            this.msgInfo("数量未发生变化,无需修改");
+            return;
+          }
+
+          updateNumStoreOrderItem(this.quantityForm).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("数量修改成功");
+              updateStoreOrderItemJson(this.order.id,1);
+              this.quantityDialog.open = false;
+              this.getOrder(this.order.id);
+            }else{
+              this.msgError(response.message);
+            }
+          }).catch(error => {
+            this.$message.error('请求失败: ' + error.message)
+          });
+        }
+      });
+    },
+
+    openProductSelection(){
+      this.productOrderDialog.open=true;
+
+      // 将已有的productId存入查询参数,用于后端过滤 (返回数组格式)
+      this.productOrderQueryParams.excludeProductIds = this.items.map(item => item.productId).filter(productId => productId);
+
+      // 加载字典和其他数据
+      this.getDicts("store_product_tui_cate").then((response) => {
+        this.productTuiCateOptions = response.data;
+      });
+      this.getDicts("store_product_enable").then((response) => {
+        this.isNewOptions = response.data;
+        this.isBestOptions = response.data;
+        this.isHotOptions = response.data;
+        this.isGoodOptions=response.data;
+        this.isDisplayOptions=response.data;
+      });
+      this.getDicts("store_product_type").then((response) => {
+        this.productTypeOptions = response.data;
+        if(!this.isMedicalMall &&
+        this.productTypeOptions.length === 4){
+          //删除后两项
+          this.productTypeOptions.splice(2,2);
+        }
+      });
+      this.getDicts("store_product_is_show").then((response) => {
+        this.isShowOptions = response.data;
+      });
+      getCompanyList().then(response => {
+        this.companyOptions = response.data;
+      });
+
+      listStore(this.storeForm).then(response => {
+        this.storeOptions = response.rows;
+      });
+      this.getTreeselect();
+      this.productOrderGetList();
+    },
+
+    /** 商品表格选择变化 */
+    handleItemsSelectionChange(selection) {
+      this.selectedItems = selection;
+    },
+
+    /** 移除选中的商品 */
+    removeSelectedProduct() {
+      if (this.selectedItems.length === 0) {
+        this.warning("请先选择要移除的商品");
+        return;
+      }
+
+      const that = this;
+      this.$confirm('确定要移除选中的 ' + this.selectedItems.length + ' 个商品吗?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        that.removeProductLoading = true;
+        // 收集所有要删除的商品ID
+        const deletePromises = that.selectedItems.map(item => {
+          return delStoreOrderItem(item.itemId);
+        });
+
+        // 并行删除所有选中的商品
+        Promise.all(deletePromises).then(responses => {
+          // 检查所有删除操作是否成功
+          const allSuccess = responses.every(response => response.code === 200);
+          if (allSuccess) {
+            that.msgSuccess("商品移除成功");
+            // 清除选择并刷新订单数据
+            that.selectedItems = [];
+            updateStoreOrderItemJson(this.order.id,1);
+            that.getOrder(that.order.id);
+          } else {
+            that.msgError("商品移除失败: " + (responses.message));
+          }
+        }).catch(error => {
+          that.msgError("移除商品失败: " + (error.message || "网络错误"));
+        })
+      }).catch(() => {
+        // 用户取消操作
+      });
+    },
+
+    /** 查询商品列表 */
+    productOrderGetList() {
+      this.productOrderLoading = true;
+      listStoreProduct(this.productOrderQueryParams).then(response => {
+        this.storeProductList = response.rows;
+        this.total = response.total;
+        this.productOrderLoading = false;
+      }).catch(error => {
+        console.error('获取商品列表失败:', error);
+        this.productOrderLoading = false;
+        this.storeProductList = [];
+        this.total = 0;
+      });
+    },
+
+    /** 批量添加商品到订单 */
+    handleBatchAdd() {
+      if (!this.order || !this.order.id) {
+        this.msgInfo("请先选择订单");
+        return;
+      }
+
+      if (!this.ids || this.ids.length === 0) {
+        this.msgInfo("请先选择要添加的商品");
+        return;
+      }
+
+      const that = this;
+      this.$confirm(`确定要将选中的 ${this.ids.length} 个商品添加到订单中吗?`, "确认添加", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "info"
+      }).then(() => {
+        // 获取选中的商品列表
+        const selectedProducts = this.storeProductList.filter(product =>
+          this.ids.includes(product.productId)
+        );
+
+        // 创建批量添加的订单项数据
+        const batchAddPromises = selectedProducts.map(product => {
+          const orderItemData = {
+            orderId: this.order.id,
+            orderCode: this.order.orderCode,
+            cartId: null,
+            productId: product.productId,
+            num: 1, // 默认数量为1
+            jsonInfo: JSON.stringify({
+              image: product.image,
+              productId: product.productId,
+              num: 1, // 默认数量为1
+              productName: product.productName,
+              barCode: product.barCode,
+              price: product.price,
+              sku: product.sku || '默认'
+            })
+          };
+          return addStoreOrderItem(orderItemData);
+        });
+
+        // 并行添加所有选中的商品
+        Promise.all(batchAddPromises)
+          .then(responses => {
+            // 检查所有添加操作是否成功
+            const allSuccess = responses.every(response => response.code === 200);
+            if (allSuccess) {
+              that.msgSuccess(`成功添加 ${responses.length} 个商品`);
+
+              // 更新过滤列表,包含新添加的商品ID
+              const newIds = selectedProducts.map(p => p.productId);
+              const currentIds = this.productOrderQueryParams.excludeProductIds || [];
+              const updatedIds = [...new Set([...currentIds, ...newIds])]; // 去重
+              this.productOrderQueryParams.excludeProductIds = updatedIds;
+              updateStoreOrderItemJson(this.order.id,1);
+              this.productOrderDialog.open = false;
+              that.getOrder(that.order.id);
+            } else {
+              const failedCount = responses.filter(r => r.code !== 200).length;
+              that.msgError(`添加失败 ${failedCount} 个商品`);
+            }
+          })
+          .catch(error => {
+            that.msgError("批量添加商品失败: " + (error.message || "网络错误"));
+          });
+      }).catch(() => {
+        // 用户取消操作
+      });
+    },
+
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.productId).filter(id => id); // 过滤空值
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length
+    },
+    /** 搜索按钮操作 */
+    productOrderHandleQuery() {
+      this.productOrderQueryParams.pageNum = 1;
+      this.productOrderQueryParams.isShow = 1;
+      this.productOrderQueryParams.companyIds = this.companyId +''
+      this.productOrderGetList();
+    },
+    /** 重置按钮操作 */
+    productOrderResetQuery() {
+      this.resetForm("productOrderQueryForm");
+      // 重置所属公司
+      this.companyId = null;
+      // 重置所属店铺
+      this.productOrderQueryParams.storeIds = null;
+      this.productOrderQueryParams.isShow = 1;
+      this.productOrderQueryParams.companyIds = null;
+      this.productOrderGetList();
+    },
+
+    /** 转换商品分类数据结构 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.cateId,
+        label: node.cateName,
+        children: node.children
+      };
+    },
+    getStatusType(row) {
+      if (row.isAudit == 0) {
+        return 'warning';
+      }
+      // 根据你的业务逻辑返回不同的类型,如:success, danger, info等
+      return row.isShow == 1 ? 'success' : 'info';
+    },
+    getStatusText(row) {
+      if (row.isAudit == 0) {
+        return '待审核';
+      }
+      const option = this.isShowOptions.find(item => item.dictValue == row.isShow);
+      return option ? option.dictLabel : '未知状态';
+    },
+
     handleAddress(){
         const id = this.order.id;
         getStoreOrderAddress(id).then(response =>{
@@ -678,6 +1302,12 @@ export default {
       });
 
     },
+    getTreeselect() {
+      getAllStoreProductCategory().then(response => {
+      this.categoryOptions = [];
+        this.categoryOptions=this.handleTree(response.data, "cateId", "pid");
+      });
+    },
     submitEditForm(){
         this.$refs["editForm"].validate(valid => {
         if (valid) {
@@ -861,4 +1491,149 @@ export default {
   float: right;
   margin-right: 20px
 }
+.container {
+  position: relative;
+}
+.select-product-btn {
+  float: right;
+  margin-top: -5px;
+  margin-right: 15px;
+  background: linear-gradient(135deg, #409EFF, #337AB7);
+  border: none;
+  color: white;
+  border-radius: 6px;
+  padding: 8px 16px;
+  font-weight: 500;
+  box-shadow: 0 3px 6px rgba(64, 158, 255, 0.2);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.select-product-btn:hover {
+  background: linear-gradient(135deg, #66b1ff, #409EFF);
+  transform: translateY(-2px);
+  box-shadow: 0 5px 12px rgba(64, 158, 255, 0.35);
+}
+
+.select-product-btn:active {
+  transform: translateY(0);
+  box-shadow: 0 2px 4px rgba(64, 158, 255, 0.2);
+}
+
+.select-product-btn:focus {
+  outline: none;
+  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.3);
+}
+
+.select-product-btn:disabled {
+  background: linear-gradient(135deg, #a0cfff, #b3d8ff);
+  cursor: not-allowed;
+  transform: none;
+  box-shadow: none;
+}
+
+.remove-product-btn {
+  float: right;
+  margin-top: -5px;
+  margin-right: 15px;
+  background: linear-gradient(135deg, #ff6b6b, #ee5a52);
+  border: none;
+  color: white;
+  border-radius: 6px;
+  padding: 8px 16px;
+  font-weight: 500;
+  box-shadow: 0 3px 6px rgba(255, 107, 107, 0.15);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.remove-product-btn:hover {
+  background: linear-gradient(135deg, #ff5252, #e74c3c);
+  transform: translateY(-2px);
+  box-shadow: 0 5px 12px rgba(255, 107, 107, 0.25);
+}
+
+.remove-product-btn:active {
+  transform: translateY(0);
+  box-shadow: 0 2px 4px rgba(255, 107, 107, 0.2);
+}
+
+.remove-product-btn:focus {
+  outline: none;
+  box-shadow: 0 0 0 3px rgba(255, 107, 107, 0.3);
+}
+
+.remove-product-btn:disabled {
+  background: linear-gradient(135deg, #ffcccc, #f8d7da);
+  cursor: not-allowed;
+  transform: none;
+  box-shadow: none;
+}
+
+
+
+.quantity-cell {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  padding: 0 5px;
+}
+
+.quantity-display {
+  display: flex;
+  align-items: center;
+  gap: 4px; /* 缩小数量与按钮之间的间距 */
+}
+
+.quantity-value {
+  font-weight: 600;
+  color: #606266;
+  background-color: #f5f7fa;
+  padding: 4px 8px;
+  border-radius: 4px;
+  min-width: 40px;
+  text-align: center;
+}
+
+.edit-quantity-btn {
+  margin-left: 4px; /* 缩小左边距 */
+  padding: 4px 8px;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  color: #409eff;
+  background: transparent;
+  cursor: pointer;
+  transition: all 0.2s ease;
+}
+
+.edit-quantity-btn:hover {
+  background-color: #ecf5ff;
+  border-color: #b3d8ff;
+  color: #66b1ff;
+  transform: translateY(-1px);
+}
+
+.edit-quantity-btn i {
+  margin-right: 2px;
+  font-size: 12px;
+}
+
+.edit-quantity-btn:hover {
+  background-color: #ecf5ff;
+  border-color: #b3d8ff;
+  color: #66b1ff;
+  transform: translateY(-1px);
+}
+
+.edit-quantity-btn i {
+  margin-right: 2px;
+  font-size: 12px;
+}
+.dialog-product-name {
+  font-weight: 500;
+  color: #303133;
+  word-break: break-all;
+  max-width: 350px;
+  display: inline-block;
+  vertical-align: middle;
+}
 </style>

+ 15 - 1
src/views/hisStore/shippingTemplates/index.vue

@@ -1,6 +1,20 @@
 <template>
   <div class="app-container">
-
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="模板名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入模板名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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

+ 6 - 5
src/views/hisStore/storeOrder/dimensionStatistics/index.vue

@@ -134,11 +134,11 @@
       <el-table-column label="总金额" align="center" prop="totalPrice"/>
       <el-table-column label="成交单数" align="center" prop="dealNum"/>
       <el-table-column label="成交金额" align="center" prop="dealPrice"/>
-      <el-table-column label="取消单数" align="center" prop="cancelNum"/>
-      <el-table-column label="取消金额" align="center" prop="cancelPrice"/>
-      <el-table-column label="待发货单数" align="center" prop="pendingNum"/>
-      <el-table-column label="待发货金额" align="center" prop="pendingPrice"/>
-      <el-table-column label="发货单数" align="center" prop="invoiceNum"/>
+      <el-table-column v-if="zdyInfo !== 'gzzdy'" label="取消单数" align="center" prop="cancelNum"/>
+      <el-table-column v-if="zdyInfo !== 'gzzdy'" label="取消金额" align="center" prop="cancelPrice"/>
+      <el-table-column v-if="zdyInfo !== 'gzzdy'" label="待发货单数" align="center" prop="pendingNum"/>
+      <el-table-column v-if="zdyInfo !== 'gzzdy'" label="待发货金额" align="center" prop="pendingPrice"/>
+      <el-table-column v-if="zdyInfo !== 'gzzdy'" label="发货单数" align="center" prop="invoiceNum"/>
       <el-table-column label="发货金额" align="center" prop="invoicePrice"/>
       <el-table-column label="签收单数" align="center" prop="signForNum"/>
       <el-table-column label="签收金额" align="center" prop="signFPrice"/>
@@ -166,6 +166,7 @@ export default {
   name: 'HisCompanyBindUser',
   data() {
     return {
+      zdyInfo: process.env.VUE_APP_FS_USER_INFO,
       activeName: '1',
       // 遮罩层
       loading: true,

+ 5 - 1
src/views/hisStore/storeOrder/healthStoreList.vue

@@ -473,7 +473,11 @@
             <el-tooltip content="按应收金额排序" placement="top"/>
           </template>
         </el-table-column>
-
+      <el-table-column align="center" label="代收金额" prop="payDelivery">
+        <template slot-scope="scope">
+          <span v-if="scope.row.payDelivery!=null">{{ scope.row.payDelivery.toFixed(2) }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="成本价格" align="center" prop="cost" v-if="showFinanceTableField"/>
       <!-- <el-table-column label="结算价格" align="center" prop="fprice"  v-if="showFinanceTableField"/> -->
        <el-table-column label="实付金额" align="center" prop="payMoney"  v-if="showFinanceTableField"/>

+ 1 - 0
src/views/hisStore/storeOrder/index.vue

@@ -536,6 +536,7 @@
           </template>
       </el-table-column>
       <el-table-column label="下单时间" align="center" prop="createTime" />
+      <el-table-column label="审核时间" align="center" prop="auditTime" />
       <!-- <el-table-column label="支付状态" align="center" prop="paid" /> -->
       <el-table-column label="支付时间" align="center" prop="payTime" width="180" />
       <el-table-column label="发货时间" align="center" prop="deliverySendTime" width="180"></el-table-column>

+ 1 - 0
src/views/live/components/productAfterSalesOrder.vue

@@ -171,6 +171,7 @@
           <div>商品金额:¥{{ goodsTotal.toFixed(2) }}</div>
           <div>运费金额:¥{{ (order.payPostage || 0).toFixed(2) }}</div>
           <div>优惠券金额:¥{{ order.discountMoney }}</div>
+          <div>小计:¥{{(order.totalPrice-order.discountMoney).toFixed(2)}}</div>
         </div>
         <div style="margin-top: 20px">
           <span class="font-small">操作信息</span>

+ 16 - 1
src/views/live/liveVideo/index.vue

@@ -1,6 +1,20 @@
 <template>
   <div class="app-container">
-
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="视频名称" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入视频名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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
@@ -124,6 +138,7 @@ export default {
       queryParams: {
         pageNum: 1,
         pageSize: 10,
+        remark: null,
         liveId: -1,
         videoUrl: null,
         videoType: -1,

+ 2 - 2
src/views/live/order/liveDetail.vue

@@ -182,8 +182,8 @@
         <el-button size="mini" circle icon="el-icon-search" @click="showListD()" />
       </el-tooltip>
       <el-descriptions :column="3" border  >
-        <el-descriptions-item label="商品合计"  ><span v-if="item!=null">{{item.totalPrice-item.payPostage}}</span></el-descriptions-item>
-        <el-descriptions-item label="应付金额"><span v-if="item.totalPrice!=null">{{item.totalPrice-item.payPostage}}</span></el-descriptions-item>
+        <el-descriptions-item label="商品合计"  ><span v-if="item!=null">{{(item.totalPrice-item.payPostage).toFixed(2)}}</span></el-descriptions-item>
+        <el-descriptions-item label="应付金额"><span v-if="item.totalPrice!=null">{{(item.totalPrice-item.payPostage).toFixed(2)}}</span></el-descriptions-item>
 <!--        <el-descriptions-item label="运费"><span v-if="item.payDelivery!=null">{{item.payDelivery}}</span></el-descriptions-item>-->
         <el-descriptions-item label="运费"><span v-if="item.payDelivery!=null">{{item.payPostage}}</span></el-descriptions-item>
         <el-descriptions-item label="优惠券"  ><span v-if="item.discountMoney!=null"/>{{item.discountMoney}}</el-descriptions-item>

+ 691 - 0
src/views/qw/QwWorkTaskNew/qwWorkTask.vue

@@ -0,0 +1,691 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+	 <el-form-item label="部门" prop="type">
+	    <treeselect style="width: 220px" :clearable="false"  v-model="queryParams.deptId"  :options="deptOptions" clearable :show-count="true" placeholder="请选择归属部门"  />
+	 </el-form-item>
+     <el-form-item label="企微账号" prop="qwUserName">
+             <el-input
+               v-model="queryParams.qwUserName"
+               placeholder="请输入企微昵称"
+               clearable
+               size="small"
+               @keyup.enter.native="handleQuery"
+             />
+      </el-form-item>
+	  <el-form-item label="所属销售" prop="companyUserId">
+	    <el-select v-model="queryParams.companyUserId" clearable filterable remote
+	               placeholder="请输入关键词" :remote-method="loadCompanyUserOptions"
+	               v-select-load-more="loadMoreCompanyUserOptions"
+	               :loading="companyUserOptionsLoading">
+	      <el-option
+	        v-for="item in companyUserOptions"
+	        :key="item.value"
+	        :label="item.dictLabel"
+	        :value="item.dictValue">
+	      </el-option>
+	    </el-select>
+	  </el-form-item>
+      <el-form-item label="类别" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择类别" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+	  <el-form-item label="处理状态" prop="trackType">
+	    <el-select v-model="queryParams.trackType" placeholder="处理状态" clearable size="small">
+	      <el-option
+	        v-for="dict in trackTypeOptions"
+	        :key="dict.dictValue"
+	        :label="dict.dictLabel"
+	        :value="dict.dictValue"
+	      />
+	    </el-select>
+	  </el-form-item>
+      <el-form-item label="sop编号" prop="sopId">
+        <el-input
+          v-model="queryParams.sopId"
+          placeholder="请输入sopid"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="标题" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          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-button icon="el-icon-refresh" size="mini" @click="sm()">色盲模式</el-button>
+      </el-form-item>
+    </el-form>
+
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+	<el-tabs type="card" v-model="actName" @tab-click="handleClickX">
+	  <el-tab-pane v-for="(item,index) in statusOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+	</el-tabs>
+    <el-table border v-loading="loading" :data="QwWorkTaskList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="客户昵称" align="center" prop="name" />
+      <el-table-column label="企微账号" align="center" prop="qwUserName" />
+	  <el-table-column label="企微昵称" align="center" prop="nickName" />
+      <el-table-column label="状态" align="center" prop="status">
+		 <template slot-scope="scope">
+		   <dict-tag :options="statusOptions" :value="scope.row.status"/>
+		 </template>
+      </el-table-column>
+      <el-table-column label="类别" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+	  <el-table-column label="处理状态" align="center" prop="trackType">
+	    <template slot-scope="scope">
+	      <dict-tag :options="trackTypeOptions" :value="scope.row.trackType"/>
+	    </template>
+	  </el-table-column>
+      <el-table-column label="标题" align="center" prop="title" />
+      <el-table-column label="描述" align="center" prop="description" />
+      <el-table-column label="分值" align="center" prop="score">
+        <template slot-scope="scope">
+          <span :style="getScoreStyle(scope.row.score)">{{ scope.row.score }}</span>
+        </template>
+      </el-table-column>
+	  <el-table-column label="用户过往看课记录" align="center" width="200px">
+	    <template slot-scope="scope">
+	    	<div style="display: flex; gap: 4px; justify-content: center;" v-if="!isSM">
+	    	  <span
+	    		v-for="(log, index) in scope.row.logs"
+	    		:key="index"
+	    		:style="{
+	    		  display: 'inline-block',
+	    		  width: '16px',
+	    		  height: '16px',
+	    		  borderRadius: '2px',
+	    		  backgroundColor:
+	    			log === 2 ? '#67C23A' :
+	    					  log === 3 ? '#f55a4f' :
+	    					  log === 4 ? '#FFD700' :
+	    					  log === 1 ? '#0bc6ff' :
+	    					  '#909399'
+	    		}"
+	    	  ></span>
+	    	</div>
+
+	      <div style="display: flex; gap: 4px; justify-content: center;" v-if="isSM">
+	        <span
+	          v-for="(log, index) in scope.row.logs"
+	          :key="index"
+	          :style="{
+	            display: 'inline-block',
+	            width: '16px',
+	            height: '16px',
+	            borderRadius: log === 2 ? '50%' : log === 4 ? '2px 8px' : '2px',
+	            backgroundColor: log === 3 ? 'transparent' : '#f0f0f0',
+	            border: log === 3 ? '2px solid #666' : '1px solid #ddd',
+	            position: 'relative',
+	            transform: log === 4 ? 'rotate(45deg)' : 'none'
+	          }"
+	        >
+	          <!-- 已完成 - 圆形 + 对勾 -->
+	          <span v-if="log === 2" style="
+	            position: absolute;
+	            top: 45%;
+	            left: 50%;
+	            width: 6px;
+	            height: 3px;
+	            border: solid #333;
+	            border-width: 0 0 2px 2px;
+	            transform: translate(-50%, -50%) rotate(-45deg);
+	          "></span>
+
+	          <!-- 未完成 - 方框 + 叉 -->
+	          <span v-if="log === 3" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #666;
+	            transform: translate(-50%, -50%) rotate(45deg);">
+				</span>
+
+
+	          <span v-if="log === 1" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #666;
+	            transform: translate(-50%, -10%) rotate(-15deg);
+	          "></span>
+
+	          <!-- 部分完成 - 菱形 -->
+	          <span v-if="log === 4" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 6px;
+	            height: 6px;
+	            border: 2px solid #333;
+	            transform: translate(-50%, -50%) rotate(-45deg);
+	          "></span>
+
+	          <!-- 未开始 - 减号 -->
+	          <span v-if="!log" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #999;
+	            transform: translate(-50%, -50%);
+	          "></span>
+
+	          <!-- 图像 - 使用img标签 -->
+	          <img v-if="log === 5" src="/path/to/your-image.png" alt="Custom icon" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 12px;
+	            height: 12px;
+	            transform: translate(-50%, -50%);
+	          ">
+	        </span>
+	      </div>
+	    </template>
+	  </el-table-column>
+	    <el-table-column label="最晚看课时间" align="center">
+	        <template slot-scope="scope">
+	          {{ formatTime(scope.row.lastWatchTime) }}
+	        </template>
+	      </el-table-column>
+
+      <el-table-column label="sopId" align="center" prop="sopId" />
+      <el-table-column label="创建时间" align="center" prop="createTime" />
+      <el-table-column label="修改时间" align="center" prop="updateTime" />
+<!--      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button v-if="scope.row.status==0"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+          >处理</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"
+    />
+	<div style="margin-top: 20px; padding: 12px; background: #f8f8f8; border-radius: 4px;" v-if="!isSM">
+	  <div style="display: flex; gap: 20px; flex-wrap: wrap;">
+	    <div style="display: flex; align-items: center; gap: 8px;">
+	      <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #67C23A;"></span>
+	      <span>完课</span>
+	    </div>
+	    <div style="display: flex; align-items: center; gap: 4px;">
+	      <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #f55a4f;"></span>
+	      <span>待看课</span>
+	    </div>
+	    <div style="display: flex; align-items: center; gap: 4px;">
+	      <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #FFD700;"></span>
+	      <span>看课中断</span>
+	    </div>
+	    <div style="display: flex; align-items: center; gap: 4px;">
+	      <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #909399;"></span>
+	      <span>没发课</span>
+	    </div>
+		<div style="display: flex; align-items: center; gap: 4px;">
+		  <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #0bc6ff;"></span>
+		  <span>看课中</span>
+		</div>
+	  </div>
+	</div>
+
+	<!-- 新增的解释说明区域 -->
+	<div style="margin-top: 20px; padding: 12px; background: #f8f8f8; border-radius: 4px;" v-if="isSM">
+	    <div style="display: flex; gap: 20px; flex-wrap: wrap;">
+	      <div style="display: flex; align-items: center; gap: 8px;">
+	        <span style="
+	          display: inline-block;
+	          width: 16px;
+	          height: 16px;
+	          border-radius: 50%;
+	          background-color: #f0f0f0;
+	          position: relative;
+	        ">
+	          <span style="
+	            position: absolute;
+	            top: 45%;
+	            left: 50%;
+	            width: 6px;
+	            height: 3px;
+	            border: solid #333;
+	            border-width: 0 0 2px 2px;
+	            transform: translate(-50%, -50%) rotate(-45deg);
+	          "></span>
+	        </span>
+	        <span>完课</span>
+	      </div>
+
+	      <div style="display: flex; align-items: center; gap: 8px;">
+	        <span style="
+	          display: inline-block;
+	          width: 16px;
+	          height: 16px;
+	          border-radius: 2px;
+	          border: 2px solid #666;
+	          background-color: transparent;
+	          position: relative;
+	        ">
+	          <span style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #666;
+	            transform: translate(-50%, -50%) rotate(45deg);
+	          "></span>
+	          <span style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #666;
+	            transform: translate(-50%, -50%) rotate(-45deg);
+	          "></span>
+	        </span>
+	        <span>待看课</span>
+	      </div>
+
+	      <div style="display: flex; align-items: center; gap: 8px;">
+	        <span style="
+	          display: inline-block;
+	          width: 16px;
+	          height: 16px;
+	          border-radius: 2px 8px;
+	          background-color: #f0f0f0;
+	          border: 1px solid #ddd;
+	          position: relative;
+	          transform: rotate(45deg);
+	        ">
+	          <span style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 6px;
+	            height: 6px;
+	            border: 2px solid #333;
+	            transform: translate(-50%, -50%) rotate(-45deg);
+	          "></span>
+	        </span>
+	        <span>看课中断</span>
+	      </div>
+
+	      <div style="display: flex; align-items: center; gap: 8px;">
+	        <span style="
+	          display: inline-block;
+	          width: 16px;
+	          height: 16px;
+	          border-radius: 2px;
+	          background-color: #f0f0f0;
+	          border: 1px solid #ddd;
+	          position: relative;
+	        ">
+	          <span style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #999;
+	            transform: translate(-50%, -50%);
+	          "></span>
+	        </span>
+	        <span>没发课</span>
+	      </div>
+
+		  <div style="display: flex; align-items: center; gap: 8px;">
+		    <span style="
+		      display: inline-block;
+		      width: 16px;
+		      height: 16px;
+		      border-radius: 2px;
+		      background-color: #f0f0f0;
+		      border: 1px solid #ddd;
+		      position: relative;
+		    ">
+		      <span  style="
+		        position: absolute;
+		        top: 50%;
+		        left: 50%;
+		        width: 8px;
+		        height: 2px;
+		        background: #666;
+		        transform: translate(-50%, -10%) rotate(-15deg);
+		      "></span>
+		    </span>
+		    <span>看课中</span>
+		  </div>
+
+
+	    </div>
+	  </div>
+    <!-- 添加或修改企微任务看板对话框 -->
+    <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="remark">
+          <el-input  v-model="form.remark" placeholder="请输入备注"  type="textarea" :rows="3"/>
+        </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 { listQwWorkTask, getQwWorkTask, delQwWorkTask, addQwWorkTask, updateQwWorkTask, exportQwWorkTask,glList} from "@/api/qw/QwWorkTaskNew";
+import {getMyQwUserList, getMyQwCompanyList, handleInputAuthAppKey, updateUser} from "@/api/qw/user";
+import { treeselect } from "@/api/company/companyDept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { getCompanyUserListLikeName } from "@/api/company/companyUser";
+export default {
+  name: "QwWorkTaskNew",
+  components: { Treeselect  },
+  data() {
+    return {
+	  actName:"0",
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+	  companyUserOptionsParams: {
+	    name: undefined,
+	    hasNextPage: false,
+	    pageNum: 1,
+	    pageSize: 10
+	  },
+	  isSM:false,
+
+	  companyUserOptionsLoading: false,
+	  companyUserOptions: [],
+      // 选中数组
+      ids: [],
+	  deptOptions:[],
+	  myQwUserList:[],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企微任务看板表格数据
+      QwWorkTaskList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 状态 0 待处理 1 已处理 3 过期字典
+      statusOptions: [],
+      // 类别 1先导 2 课程 3 大小转 4 转人工字典
+      typeOptions: [],
+	  trackTypeOptions:[],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        extId: null,
+        qwUserId: null,
+        status: 0,
+        type: null,
+        title: null,
+        score: null,
+        sopId: null,
+        companyId: null,
+        companyUserId: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+	this.handleGetMyQwUserList();
+    this.getDicts("sys_qw_work_task_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_qw_work_task_type").then(response => {
+      this.typeOptions = response.data;
+    });
+	this.getDicts("sys_qw_work_task_track_type").then(response => {
+	  this.trackTypeOptions = response.data;
+	});
+	this.getTreeselect();
+  },
+  methods: {
+	getScoreStyle(score) {
+	let backgroundColor = '';
+	  if (score >= 15) {
+		backgroundColor = '#ff4d4f';    // 红色
+	  } else if (score >= 9) {
+		backgroundColor = '#ff7d45';    // 橘红
+	  } else if (score >= 4) {
+		backgroundColor = '#ffec3d';    // 黄色
+	  } else {
+		backgroundColor = '#ffffff';    // 白色
+	  }
+	  return {
+		'background-color': backgroundColor,
+		'padding': '5px 10px',
+		'border-radius': '4px'
+	  };
+	},
+	getTreeselect() {
+	  var that=this;
+	  var param={companyId:this.companyId}
+	  treeselect(param).then((response) => {
+	    this.deptOptions = response.data;
+	    console.log(this.deptOptions)
+	    if(response.data!=null&&response.data.length>0){
+	      //this.queryParams.deptId=response.data[0].id;
+	    }
+	  });
+	},
+	loadCompanyUserOptions(query) {
+	  this.companyUserOptions = [];
+	  if (query === '') {
+	    return;
+	  }
+
+	  this.companyUserOptionsParams.pageNum = 1
+	  this.companyUserOptionsParams.name = query
+	  this.companyUserOptionsLoading = true;
+	  this.getCompanyUserListLikeName()
+	},
+	getCompanyUserListLikeName() {
+	  getCompanyUserListLikeName(this.companyUserOptionsParams).then(response => {
+	    this.companyUserOptions = [...this.companyUserOptions, ...response.data.list]
+		console.log(this.companyUserOptions);
+	    this.companyUserOptionsParams.hasNextPage = response.data.hasNextPage
+	    this.companyUserOptionsLoading = false;
+	  });
+	},
+	loadMoreCompanyUserOptions() {
+	  if (!this.companyUserOptionsParams.hasNextPage) {
+	    return;
+	  }
+
+	  this.companyUserOptionsParams.pageNum += 1
+	  this.getCompanyUserListLikeName()
+	},
+	formatTime(timeStr) {
+	      if (!timeStr && timeStr !== 0) return '';
+
+	      // 处理数字和字符串输入
+	      const str = String(timeStr).padStart(4, '0');
+
+	      // 提取有效部分
+	      const hours = str.substring(0, 2);
+	      const minutes = str.substring(2, 4);
+
+	      // 简单验证
+	      if (hours > 23 || minutes > 59) return '无效时间';
+
+	      return `${hours}:${minutes}`;
+	    },
+    /** 查询企微任务看板列表 */
+    getList() {
+      this.loading = true;
+      glList(this.queryParams).then(response => {
+        this.QwWorkTaskList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+	handleClickX(tab, event) {
+	  this.queryParams.status=tab.name;
+	  this.handleQuery();
+	},
+	sm(){
+		this.isSM = this.isSM ? false : true;
+	},
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        extId: null,
+        qwUserId: null,
+        status: 0,
+        type: null,
+        title: null,
+        remark: null,
+        score: null,
+        sopId: null,
+        companyId: null,
+        companyUserId: null,
+        createTime: null,
+        updateTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+	handleGetMyQwUserList(){
+
+		this.getList();
+	},
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加企微任务看板";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+        this.form = row;
+        this.open = true;
+        this.title = "处理任务";
+
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateQwWorkTask(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addQwWorkTask(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企微任务看板编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delQwWorkTask(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企微任务看板数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportQwWorkTask(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 626 - 0
src/views/qw/externalContactTransfer/index.vue

@@ -0,0 +1,626 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="110px">
+
+<!--      <el-form-item label="外部联系人账号" prop="externalUserId">-->
+<!--        <el-input-->
+<!--          v-model="queryParams.externalUserId"-->
+<!--          placeholder="外部联系人账号"-->
+<!--          clearable-->
+<!--          size="small"-->
+<!--          @keyup.enter.native="handleQuery"-->
+<!--        />-->
+<!--      </el-form-item>-->
+      <el-form-item label="企微公司" prop="corpId">
+            <el-select v-model="queryParams.corpId" placeholder="企微公司"  size="small" @change="updateCorpId()">
+              <el-option
+                v-for="dict in myQwCompanyList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+      </el-form-item>
+      <el-form-item label="客户名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入客户名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="所属员工" prop="qwUserName">
+        <el-input
+          v-model="queryParams.qwUserName"
+          placeholder="请输入所属员工名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="用户类别" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择用户类别" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="客户等级" prop="level">
+        <el-select v-model="queryParams.level" placeholder="客户等级" clearable size="small">
+          <el-option
+            v-for="dict in ratingType"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="性别" prop="gender">
+        <el-input
+          v-model="queryParams.gender"
+          placeholder="请输入性别"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="转接状态" prop="addWay">
+        <el-select v-model="queryParams.transferStatus" placeholder="转接状态" clearable size="small">
+          <el-option
+            v-for="dict in transferStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标签" prop="tagIds">
+        <el-select v-model="selectTags" remote multiple placeholder="请选择" filterable  style="width: 100%;">
+          <el-option
+            v-for="dict in tagList"
+            :label="dict.name"
+            :value="dict.tagId">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+<!--      <el-form-item label="添加时间" prop="createTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.createTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择添加时间">
+        </el-date-picker>
+      </el-form-item>-->
+      <el-form-item label="添加时间" prop="createTime">
+        <el-date-picker
+          style="width:225.4px"
+          clearable size="small"
+          v-model="dateRange"
+          type="daterange"
+          @change="changeTime"
+          value-format="yyyy-MM-dd"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期">
+        </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>
+
+    <el-row :gutter="10" class="mb8">
+   <!--   <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:externalContact:add']"
+        >同步</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="['qw:externalContact:export']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="handleTransfer"
+          v-hasPermi="['qw:externalContact:transfer']"
+        >分配客户</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+
+      <el-table-column label="所属员工" align="center" prop="qwUserName" width="120px"/>
+      <el-table-column label="员工部门" align="center" prop="departmentName" width="120px"/>
+<!--      <el-table-column label="外部联系人账号" align="center" prop="externalUserId" width="120px"/>-->
+      <el-table-column label="客户名称" align="center" prop="name" />
+      <el-table-column label="头像" align="center" prop="avatar" width="100px">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.avatar" width="60px">
+            <img :src="scope.row.avatar" style="max-width: 200px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="用户类别" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="性别" align="center" prop="gender">
+        <template slot-scope="scope">
+          <dict-tag :options="genderOptions" :value="scope.row.gender"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="描述信息" align="center" prop="description" />
+      <el-table-column label="标签" align="center" prop="tagIds" width="300px">
+        <template slot-scope="scope">
+          <div class="tag-container">
+            <div class="tag-list">
+              <div v-for="i in JSON.parse(scope.row.tagIds)" :key="i" style="display: inline;">
+              <el-tag type="success" v-for="ii in tagList" :key="ii.id" style="margin: 3px;" v-if="ii.tagId==i">{{ii.name}}</el-tag>
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="客户等级" align="center" prop="level" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingType" :value="scope.row.level"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="添加时间" align="center" prop="createTime" width="100px"/>
+      <el-table-column label="状态" align="center" prop="status" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="转接状态" align="center" prop="transferStatus" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="transferStatusOptions" :value="scope.row.transferStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="企业id" align="center" prop="corpId" />
+      <el-table-column label="备注电话号码" align="center" prop="remarkMobiles" width="150px">
+        <template slot-scope="scope">
+          <span v-for="i in JSON.parse(scope.row.remarkMobiles)" :key="i">{{i}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注企业名称" align="center" prop="remarkCorpName" />
+      <el-table-column label="来源" align="center" prop="addWay" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="addWayOptions" :value="scope.row.addWay"/>
+        </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="['qw:externalContact:edit']"
+          >修改</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"
+    />
+
+    <!-- 添加或修改企业微信客户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <div style="background-color: rgb(239, 250, 255); margin: 10px;padding: 15px;">
+          <div>可将选中的客户转接给其他员工,进行后续服务</div>
+          <div>注意:90天内客户只能被转接一次,一个客户最多只能被转接两次</div>
+        </div>
+
+        <el-form-item label="接替员工" prop="userId">
+<!--          <el-button type="success" v-if="this.nickName">{{ nickName }}</el-button>-->
+          <el-input style="width: 150px" disabled>
+            <template slot="prefix">
+              <el-button
+                plain
+                size="small"
+                type="success"
+                v-if="this.nickName">
+                {{ nickName }}
+              </el-button>
+            </template>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="清除标签" prop="needClearTag">
+          <el-radio v-model="form.needClearTag" :label="0">不清除</el-radio>
+          <el-radio v-model="form.needClearTag" :label="1">清除</el-radio>
+          <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
+            <i class="el-icon-info"></i>
+            <span v-if="form.needClearTag === 0">不清除标签:客户转接后会保留原标签,不会被清除。</span>
+            <span v-else>清除标签:客户转接后原标签不会保留,仅会存在自动添加的标签。</span>
+          </div>
+        </el-form-item>
+		<el-form-item label="消息内容" prop="content">
+		  <el-input v-model="form.content" placeholder="请输入内容" />
+      <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
+        <i class="el-icon-info"></i>
+        自定义转接的时候发给客户的消息内容(选填)ps:不填则是官方默认话术
+      </div>
+		</el-form-item>
+
+        <el-card>
+          <qwUserSelectOne ref="qwUserSelectOne" @selectUser="selectUser"></qwUserSelectOne>
+        </el-card>
+
+
+      </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 { transfer,listExternalContact, getExternalContact, delExternalContact, addExternalContact, updateExternalContact, exportExternalContact } from "@/api/qw/externalContact";
+import { listTag, getTag, delTag, addTag, updateTag, exportTag } from "@/api/qw/tag";
+import { qwUserList,getMyQwCompanyListAll } from "@/api/qw/user";
+import qwUserSelectOne from '@/views/qw/user/qwUserSelectOne.vue'
+
+export default {
+  name: "ExternalContact",
+  components: { qwUserSelectOne },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      myQwCompanyList:[],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业微信客户表格数据
+      externalContactList: [],
+      dateRange: null,
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      filter: false,
+      // 用户类别字典
+      typeOptions: [],
+      ratingType: [],
+      selectTags:[],
+      // 性别字典
+      genderOptions: [],
+      // 来源字典
+      addWayOptions: [],
+      nickName:null,
+      qwUserList:[],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        remark:null,
+        gender: null,
+        description: null,
+        tagIds: null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        status:0,
+        transferStatus:null
+      },
+      // 表单参数
+      form: {
+        needClearTag: 0
+      },
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+        userId: [{ required: true, message: '请选择接替员工', trigger: 'blur' }],
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyListAll().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+              listTag({corpId:this.queryParams.corpId}).then(response => {
+                this.tagList = response.rows;
+              });
+              qwUserList(this.queryParams.corpId).then(response => {
+                this.qwUserList = response.rows;
+              });
+
+              this.getList();
+            }
+    });
+
+    this.getDicts("sys_qw_externalContact_type").then(response => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("sys_user_sex").then(response => {
+      this.genderOptions = response.data;
+    });
+    this.getDicts("sys_qw_externalContact_addWay").then(response => {
+      this.addWayOptions = response.data;
+    });
+    this.getDicts("sys_qw_sop_rating_type").then(response => {
+      this.ratingType = response.data;
+    });
+
+
+    this.getDicts("sys_qw_external_contact_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_qw_transfer_status").then(response => {
+      this.transferStatusOptions = response.data;
+    });
+
+  },
+  methods: {
+    updateCorpId(){
+      listTag({corpId:this.queryParams.corpId}).then(response => {
+        this.tagList = response.rows;
+      });
+      qwUserList(this.queryParams.corpId).then(response => {
+        this.qwUserList = response.rows;
+      });
+      this.getList();
+     },
+    /** 查询企业微信客户列表 */
+    getList() {
+      this.loading = true;
+      listExternalContact(this.queryParams).then(response => {
+        this.externalContactList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    changeTime(){
+      if(this.dateRange!=null){
+        this.queryParams.sTime=this.dateRange[0];
+        this.queryParams.eTime=this.dateRange[1];
+      }else{
+        this.queryParams.sTime=null;
+        this.queryParams.eTime=null;
+      }
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        gender: null,
+        remark: null,
+        description: null,
+        tagIds: null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        needClearTag: 0
+      };
+      this.resetForm("form");
+    },
+
+    selectUser(row){
+      this.form.userId=row.id
+	  console.log(row)
+      this.nickName=row.qwUserName
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.tagIds=this.selectTags.join(',')
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.selectTags=[];
+      this.dateRange=null;
+      this.changeTime();
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+     addExternalContact(this.form).then(response => {
+       this.msgSuccess("同步成功");
+       this.getList();
+     });
+
+    },
+
+    handleTransfer(row) {
+      this.reset();
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要分配的客户');
+      }
+      setTimeout(() => {
+                    this.$refs.qwUserSelectOne.getDetails(this.queryParams.corpId);
+       }, 1);
+      this.open = true;
+      this.filter = false;
+      this.title = "分配客户";
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+
+
+        let obj = JSON.parse(JSON.stringify(this.queryParams))
+        if(obj.tagIds == "" && obj.tagIds.length == 0){
+          obj.tagIds = null;
+        }
+        if(obj.tagIds !== null && obj.tagIds !== undefined){
+          obj.tagIds = obj.tagIds.split(",");
+        }
+        if (valid) {
+            var form={
+              ids:this.ids,
+              addType: 0,
+              filter: this.filter,
+              param: obj,
+              userId:this.form.userId,
+              corpId:this.queryParams.corpId,
+			        content:this.form.content,
+              needClearTag: this.form.needClearTag
+            }
+            transfer(form).then(response => {
+              this.msgSuccess(response.msg);
+              this.open = false;
+              this.getList();
+            });
+
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企业微信客户编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delExternalContact(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企业微信客户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportExternalContact(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>
+<style  scoped>
+.tag-container {
+  max-height: 300px;
+  overflow-y: auto;
+  padding: 1px;
+  border: 1px solid #ebeef5;
+  border-radius: 1px;
+  background-color: #fafafa;
+}
+.tag-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.scroll-hint {
+  text-align: center;
+  color: #909399;
+  font-size: 12px;
+  padding: 1px 0;
+}
+.container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 10px;
+}
+.title {
+  text-align: center;
+  color: #303133;
+  margin-bottom: 30px;
+}
+.demo-table {
+  width: 100%;
+  margin-bottom: 30px;
+}
+.instructions {
+  background-color: #f5f7fa;
+  padding: 15px;
+  border-radius: 1px;
+  margin-bottom: 20px;
+}
+</style>

+ 581 - 0
src/views/qw/externalContactUnassigned/index.vue

@@ -0,0 +1,581 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="110px">
+      <el-form-item label="企微公司" prop="corpId">
+                      <el-select v-model="queryParams.corpId" placeholder="企微公司"  size="small" @change="updateCorpId()">
+                        <el-option
+                          v-for="dict in myQwCompanyList"
+                          :key="dict.dictValue"
+                          :label="dict.dictLabel"
+                          :value="dict.dictValue"
+                        />
+                      </el-select>
+      </el-form-item>
+
+      <el-form-item label="原所属员工" prop="qwUserName">
+              <el-select @change="handleSelectChange" v-model="queryParams.qwUserName" remote filterable clearable reserve-keyword
+                         placeholder="请输入原所属员工名称" :remote-method="qwUserMethod">
+                <el-option
+                  v-for="item in qwUserNameList"
+                  :key="item.id"
+                  :label="item.qwUserName"
+                  :value="item.qwUserName">
+                  <span style="float: left">{{ item.qwUserName }}</span>
+                </el-option>
+              </el-select>
+            </el-form-item>
+
+      <el-form-item label="客户名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入客户名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="用户类别" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择用户类别" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="性别" prop="gender">
+        <el-input
+          v-model="queryParams.gender"
+          placeholder="请输入性别"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="转接状态" prop="addWay">
+        <el-select v-model="queryParams.transferStatus" placeholder="转接状态" clearable size="small">
+          <el-option
+            v-for="dict in transferStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </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
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:externalContact:add']"
+        >同步</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="['qw:externalContact:export']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="handleTransfer"
+          v-hasPermi="['qw:externalContact:transfer']"
+        >分配客户</el-button>
+      </el-col>
+       <el-col :span="1.5">
+        <el-button v-if="isQwUserISNull"
+          type="primary"
+          plain
+          size="mini"
+          @click="handleTransferAll"
+          v-hasPermi="['qw:externalContact:transfer']"
+        >分配此员工所有客户</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+
+      <el-table-column label="原所属员工" align="center" prop="qwUserName" width="120px"/>
+      <el-table-column label="原员工部门" align="center" prop="departmentName" width="120px"/>
+      <el-table-column label="外部联系人账号" align="center" prop="externalUserId" width="120px"/>
+      <el-table-column label="客户名称" align="center" prop="name" />
+      <el-table-column label="头像" align="center" prop="avatar" width="120px">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.avatar" width="100px">
+            <img :src="scope.row.avatar" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="用户类别" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="性别" align="center" prop="gender">
+        <template slot-scope="scope">
+          <dict-tag :options="genderOptions" :value="scope.row.gender"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="描述信息" align="center" prop="description" />
+      <el-table-column label="标签" align="center" prop="tagIds" width="150px">
+        <template slot-scope="scope">
+          <div class="tag-container">
+            <div class="tag-list">
+              <div v-for="i in JSON.parse(scope.row.tagIds)" :key="i" style="display: inline;">
+                <el-tag type="success" v-for="ii in tagList" :key="ii.id" style="margin: 3px;" v-if="ii.tagId==i">{{ii.name}}</el-tag>
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注电话号码" align="center" prop="remarkMobiles" width="150px">
+        <template slot-scope="scope">
+          <span v-for="i in JSON.parse(scope.row.remarkMobiles)" :key="i">{{i}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注企业名称" align="center" prop="remarkCorpName" />
+      <el-table-column label="来源" align="center" prop="addWay" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="addWayOptions" :value="scope.row.addWay"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="转接状态" align="center" prop="transferStatus" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="transferStatusOptions" :value="scope.row.transferStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="企业id" align="center" prop="corpId" />
+
+      <!-- <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="['qw:externalContact:edit']"
+          >修改</el-button>
+
+        </template>
+      </el-table-column> -->
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      :page-sizes="[10,100, 200, 300, 500]"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改企业微信客户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px"  append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px" style="height: 100%">
+        <div style="background-color: rgb(239, 250, 255); margin: 10px;padding: 15px;">
+          <div>原跟进成员离职时间不能超过1年且离职前一年内至少登录过一次企业微信</div>
+          <div>接替成员最近一年内至少登陆过一次企业微信。</div>
+        </div>
+        <el-form-item label="接替员工:" prop="userId">
+
+          <el-input style="width: 150px" disabled>
+            <template slot="prefix">
+              <el-button
+                plain
+                size="small"
+                type="success"
+                v-if="this.nickName">
+                {{ nickName }}
+              </el-button>
+            </template>
+          </el-input>
+
+
+        </el-form-item>
+        <el-form-item label="清除标签" prop="needClearTag">
+          <el-radio v-model="form.needClearTag" :label="0">不清除</el-radio>
+          <el-radio v-model="form.needClearTag" :label="1">清除</el-radio>
+          <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
+            <i class="el-icon-info"></i>
+            <span v-if="form.needClearTag === 0">不清除标签:客户转接后会保留原标签,不会被清除。</span>
+            <span v-else>清除标签:客户转接后原标签不会保留,仅会存在自动添加的标签。</span>
+          </div>
+        </el-form-item>
+        <el-card>
+        <qwUserSelectOne ref="qwUserSelectOne" @selectUser="selectUser"></qwUserSelectOne>
+        </el-card>
+
+      </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 { addUnassigned,resignedTransfer,listExternalContact, getExternalContact, delExternalContact, addExternalContact, updateExternalContact, exportExternalContact } from "@/api/qw/externalContact";
+import { listTag, getTag, delTag, addTag, updateTag, exportTag } from "@/api/qw/tag";
+import { qwUserList,userList } from "@/api/qw/user";
+import qwUserSelectOne from "@/views/qw/user/qwUserSelectOne.vue";
+import { getMyQwUserList,getMyQwCompanyListAll } from "@/api/qw/user";
+
+export default {
+  name: "ExternalContact",
+  components:{qwUserSelectOne},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业微信客户表格数据
+      externalContactList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 用户类别字典
+      typeOptions: [],
+      myQwCompanyList:[],
+      genderOptions: [],
+      // 来源字典
+      addWayOptions: [],
+      qwUserList:[],
+      isQwUserISNull:false,
+      qwUserName:null,
+      type:'0',
+       qwUserNameList:[],
+      qwUserNameParam:{
+        qwUserName:null
+      },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        qwUserName: null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        gender: null,
+        description: null,
+        tagIds: null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        status:1,
+        transferStatus:null
+      },
+      nickName:null,
+      // 表单参数
+      form: {
+        needClearTag: 0
+      },
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+        userId:[   { required: true, message: "接替员工不能为空", trigger: "blur" }]
+
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyListAll().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              listTag({corpId:this.queryParams.corpId}).then(response => {
+                this.tagList = response.rows;
+              });
+              this.getList();
+            }
+    });
+    this.getDicts("sys_qw_externalContact_type").then(response => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("sys_sex").then(response => {
+      this.genderOptions = response.data;
+    });
+    this.getDicts("sys_qw_externalContact_addWay").then(response => {
+      this.addWayOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_external_contact_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_qw_transfer_status").then(response => {
+      this.transferStatusOptions = response.data;
+    });
+    // qwUserList().then(response => {
+    //   this.qwUserList = response.rows;
+    // });
+
+  },
+  methods: {
+     qwUserMethod(query) {
+      if (query !== '') {
+        this.qwUserNameParam.qwUserName = query;
+        userList(this.qwUserNameParam).then(response => {
+          this.qwUserNameList = response.rows;
+        });
+      }
+    },
+     handleSelectChange(value) {
+    console.log('选中的值:', value);
+    if(value == ''){
+      this.qwUserNameList=null
+    this.isQwUserISNull = false;
+    }else{
+    this.isQwUserISNull = true;
+    }
+  },
+    updateCorpId(){
+      listTag({corpId:this.queryParams.corpId}).then(response => {
+        this.tagList = response.rows;
+      });
+      this.getList();
+    },
+    getList() {
+      this.loading = true;
+      listExternalContact(this.queryParams).then(response => {
+        this.externalContactList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        gender: null,
+        remark: null,
+        description: null,
+        tagIds: null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        needClearTag: 0
+      };
+      this.resetForm("form");
+    },
+
+    selectUser(row){
+      this.form.userId=row.id
+      // console.log("row",row)
+      this.nickName=row.nickName || row.qwUserName
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.qwUserNameList=null
+       this.isQwUserISNull = false;
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      this.queryParams.transferStatus = null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.form.corpId=this.queryParams.corpId;
+     addUnassigned(this.form).then(response => {
+       this.msgSuccess("同步成功");
+       this.getList();
+     });
+
+    },
+
+    handleTransfer(row) {
+      this.reset();
+      this.type = '0'
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要分配的客户');
+      }
+      setTimeout(() => {
+              this.$refs.qwUserSelectOne.getDetails(this.queryParams.corpId);
+      }, 1);
+      this.open = true;
+      this.title = "分配客户";
+
+    },
+
+
+     handleTransferAll(row) {
+      this.reset();
+     this.qwUserName=this.queryParams.qwUserName;
+       this.type="1";
+      setTimeout(() => {
+                    this.$refs.qwUserSelectOne.getDetails(this.queryParams.corpId);
+       }, 1);
+      this.open = true;
+      this.title = "分配该员工所有客户";
+
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.nickName=null;
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+            var form={
+              qwUserName:this.qwUserName,
+              type:this.type,
+              ids:this.ids,
+              userId:this.form.userId,
+              corpId:this.queryParams.corpId,
+              needClearTag: this.form.needClearTag
+            }
+            resignedTransfer(form).then(response => {
+              this.msgSuccess(response.msg);
+              this.open = false;
+              this.getList();
+            });
+
+        }
+      });
+      this.qwUserName=null;
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企业微信客户编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delExternalContact(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企业微信客户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportExternalContact(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>
+<style scoped>
+
+.tag-container {
+  max-height: 120px;
+  overflow-y: auto;
+  padding: 1px;
+  border: 1px solid #ebeef5;
+  border-radius: 1px;
+  background-color: #fafafa;
+}
+.tag-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.scroll-hint {
+  text-align: center;
+  color: #909399;
+  font-size: 12px;
+  padding: 1px 0;
+}
+.container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 10px;
+}
+.title {
+  text-align: center;
+  color: #303133;
+  margin-bottom: 30px;
+}
+.demo-table {
+  width: 100%;
+  margin-bottom: 30px;
+}
+.instructions {
+  background-color: #f5f7fa;
+  padding: 15px;
+  border-radius: 1px;
+  margin-bottom: 20px;
+}
+</style>

+ 312 - 0
src/views/qw/groupChat/index.vue

@@ -0,0 +1,312 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--部门数据-->
+      <el-col :span="3" :xs="24">
+        <div class="head-container">
+          <el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
+        </div>
+        <div class="head-container">
+          <el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" @node-click="handleNodeClick" />
+        </div>
+      </el-col>
+      <!--群聊数据-->
+      <el-col :span="21" :xs="24">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
+      <el-form-item label="企微公司" prop="corpId">
+          <el-select v-model="queryParams.corpId" placeholder="企微公司" size="small" @change="updateCorpId()">
+            <el-option
+              v-for="dict in myQwCompanyList"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+      </el-form-item>
+      <el-form-item label="群名" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入群名"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="群主(后台)" prop="ownerName">
+        <el-input
+          v-model="queryParams.ownerName"
+          placeholder="请输入群主名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="群主(企微)" prop="qwName">
+        <el-input
+          v-model="queryParams.qwName"
+          placeholder="请输入群主名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="群公告" prop="notice">
+        <el-input
+          v-model="queryParams.notice"
+          placeholder="请输入群公告"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="群跟进状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择客户群跟进状态" clearable size="small">
+          <el-option label="请选择状态"
+                     v-for="dict in groupChatStatusOptions"
+                      :label="dict.dictLabel"
+                      :key="dict.dictValue"
+                      :value="dict.dictValue"/>
+        </el-select>
+      </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-button type="warning" icon="el-icon-magic-stick" size="mini" @click="getCogradientGroupChat">同步客户群</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="groupChatList" border>
+      <el-table-column label="群名" align="center" prop="name" >
+        <template slot-scope="scope">
+          <i class="el-icon-s-comment"></i>
+          {{scope.row.name}}
+        </template>
+      </el-table-column>
+      <el-table-column label="群主(后台)" align="center" prop="ownerName" />
+      <el-table-column label="群主(企微)" align="center" prop="qwName" />
+      <el-table-column label="群公告" align="center" prop="notice" />
+      <el-table-column label="群跟进状态" align="center" prop="status" >
+        <template slot-scope="scope">
+          <span v-for="(item,index) in groupChatStatusOptions" v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="群人数" align="center" prop="groupSizeByChartUser"></el-table-column>
+      <el-table-column label="当日入群数" align="center" prop="todayJoinByChartUser"></el-table-column>
+      <el-table-column label="群创建时间" align="center" prop="createTime" />
+      <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-notebook-2"
+            @click="hangdleDitels(scope.row)"
+          >详情</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"
+    />
+
+    <el-drawer :title="title" :visible.sync="open" width="100%" size="85%">
+      <group_chat_user ref="GroupChatUser" :rowDetailFrom="this.form"></group_chat_user>
+    </el-drawer>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import {
+  listGroupChat,
+  getGroupChat,
+  cogradientGroupChat
+} from '@/api/qw/groupChat'
+import Group_chat_user from '@/views/qw/groupChatUser/groupChatUser'
+import { getMyQwUserList,getMyQwCompanyListAll } from "@/api/qw/user";
+import { treeselect } from "@/api/company/companyDept";
+
+export default {
+  name: "GroupChat",
+  components: { Group_chat_user },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      myQwCompanyList:[],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 客户群详情表格数据
+      groupChatList: [],
+      //客户群跟进状态
+      groupChatStatusOptions:[],
+      // 部门树选项
+      deptOptions: "",
+      // 部门名称
+      deptName: "",
+      // 部门树props
+      defaultProps: {
+        children: "children",
+        label: "label",
+      },
+
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        owner: null,
+        ownerName: null,
+        qwName: null,
+        notice: null,
+        memberVersion: null,
+        status: null,
+        companyId: null,
+        corpId: null,
+        deptId: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  watch: {
+    // 根据名称筛选部门树
+    deptName(val) {
+      this.$refs.tree.filter(val);
+    },
+  },
+  created() {
+    this.getTreeselect();
+    getMyQwCompanyListAll().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              this.getList();
+            }
+     });
+    //群跟进状态字典
+    this.getDicts("sys_qw_groupChat_status").then(response => {
+      this.groupChatStatusOptions = response.data;
+    });
+  },
+  methods: {
+
+     updateCorpId(){
+         this.getList();
+      },
+
+    /** 查询部门下拉树结构 */
+    getTreeselect() {
+      treeselect().then((response) => {
+        this.deptOptions = response.data;
+      });
+    },
+
+    // 筛选节点
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.label.indexOf(value) !== -1;
+    },
+
+    // 节点单击事件
+    handleNodeClick(data) {
+      this.queryParams.deptId = data.id;
+      this.queryParams.companyId = data.companyId;
+      this.getList();
+    },
+
+    /** 查询客户群列表 */
+    getList() {
+      this.loading = true;
+      listGroupChat(this.queryParams).then(response => {
+        this.groupChatList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    //同步客户群(暂用)
+    getCogradientGroupChat(){
+      this.loading = true;
+      cogradientGroupChat(this.queryParams.corpId).then(response=>{
+        if (response.code == 200) {
+          this.msgSuccess("同步成功");
+          this.getList();
+        } else {
+          this.msgError(response.msg);
+        }
+        this.loading = false;
+      })
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        chatId: null,
+        id: null,
+        name: null,
+        owner: null,
+        notice: null,
+        memberVersion: null,
+        status: "0",
+        companyId: null,
+        corpId: null,
+        createTime: null,
+        updateTime: null,
+        quitScene:null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    //详情
+    hangdleDitels(row){
+
+      this.reset();
+      this.open = true;
+      this.title = "客户群详情";
+      this.form=row;
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      this.handleQuery();
+    },
+
+  }
+};
+</script>

+ 504 - 0
src/views/qw/groupChatUser/groupChatUser.vue

@@ -0,0 +1,504 @@
+<template>
+  <el-card style="background-color: rgb(240 242 245)">
+  <div class="app-container">
+    <div style="display: flex; flex-wrap: nowrap; justify-content: space-between; align-items: stretch; width: 100%; padding: 0 20px;">
+      <div style="background-color: #34bfa3; width: calc(25% - 40px); height: 130px; margin: 0 20px 20px;">
+        <div class="topBlockStyle">
+          <span>今日新增成员数</span>
+        </div>
+        <div class="topBlockStyle">
+          <span>{{this.rowDetailFrom.todayJoinByChartUser}}</span>
+        </div>
+      </div>
+      <div style="background-color: lightsalmon; width: calc(25% - 40px); height: 130px; margin: 0 20px 20px;">
+        <div class="topBlockStyle">
+          <span>今日退群成员数</span>
+        </div>
+        <div class="topBlockStyle">
+          <span>{{this.rowDetailFrom.todayOutByChartUser}}</span>
+        </div>
+      </div>
+      <div style="background-color: #ed5565; width: calc(25% - 40px); height: 130px; margin: 0 20px 20px;">
+        <div class="topBlockStyle">
+          <span>当前群成员总数</span>
+        </div>
+        <div class="topBlockStyle">
+          <span>{{this.rowDetailFrom.groupSizeByChartUser}}</span>
+        </div>
+      </div>
+      <div style="background-color: #7171C6; width: calc(25% - 40px); height: 130px; margin: 0 20px 20px;">
+        <div class="topBlockStyle">
+          <span>累计退群成员数</span>
+        </div>
+        <div class="topBlockStyle">
+          <span>{{this.rowDetailFrom.allOutGroup}}</span>
+        </div>
+      </div>
+    </div>
+
+    <div style="margin: 20px">
+      <el-radio-group v-model="queryParams.countType" @input="changeLineType">
+        <el-radio-button :label="item.dictValue" v-for="item in groupChatUserDayType" style="padding-left:20px"  >{{item.dictLabel}}</el-radio-button>
+      </el-radio-group>
+      <div v-if="queryParams.countType==1" style="margin:20px 0px">
+        <el-date-picker
+          v-model="hospitalOrderScreenCharge"
+          type="daterange"
+          align="right"
+          unlink-panels
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :picker-options="pickerOptions"
+          :default-time="['00:00:00', '23:59:59']"
+          @change="changeLine">
+        </el-date-picker>
+      </div>
+      <div></div>
+      <div></div>
+    </div>
+    <div id="lineChart" style="width: 100%;height: 500px"/>
+
+  </div >
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+
+      <el-form-item label="名字" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入想查询名字"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="是否退群" prop="isOut">
+        <el-select v-model="queryParams.isOut" placeholder="请选择群员状态">
+          <el-option v-for="item in groupChatUserIsOutType"
+                     :key="item.dictValue"
+                     :label="item.dictLabel"
+                     :value="item.dictValue">
+
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item style="float: right">
+        <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-button type="warning" icon="el-icon-magic-stick" size="mini" @click="getCogradientGroupChat">同步此客户群</el-button>
+      </el-form-item>
+    </el-form>
+    <el-table v-loading="loading" :data="group_chat_userList">
+      <el-table-column label="客户群ID" align="center" prop="chatId" />
+      <el-table-column label="群成员账号" align="center" prop="userId" />
+      <el-table-column label="成员类型" align="center" prop="type" >
+        <template slot-scope="scope">
+          <span v-for="(item,index) in  groupChatUserType" v-if="scope.row.type==item.dictValue">{{item.dictLabel}}</span>
+        </template>
+      </el-table-column>
+      <!--      <el-table-column label="外部联系人在微信开放平台的唯一身份标识" align="center" prop="unionid" />-->
+      <el-table-column label="入群时间" align="center" prop="joinTime" width="180"/>
+      <el-table-column label="入群方式" align="center" prop="joinScene">
+        <template slot-scope="scope">
+          <span v-for="(item,index) in groupChatUserScene" v-if="scope.row.joinScene==item.dictValue">{{item.dictLabel}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="邀请者" align="center" prop="invitorName" />
+      <!--      <el-table-column label="客户在群里的昵称" align="center" prop="groupNickname" />-->
+      <el-table-column label="名字" align="center" prop="name" />
+      <el-table-column label="是否退群" align="center" prop="isOut" >
+        <template slot-scope="scope">
+          <dict-tag :options="groupChatUserIsOutType" :value="scope.row.isOut"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="退群时间" align="center" prop="outTime" />
+      <el-table-column label="退群方式" align="center" prop="quitScene" >
+        <template slot-scope="scope">
+          <dict-tag :options="groupChatUserQuitSceneType" :value="scope.row.quitScene"/>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+  </div>
+  </el-card>
+</template>
+
+<script>
+import {
+  listGroup_chat_user,
+  getGroup_chat_user,
+  delGroup_chat_user,
+  addGroup_chat_user,
+  updateGroup_chat_user,
+  getDataWeekMonthCount,
+  cogradientGroupChatUser
+} from '@/api/qw/group_chat_user'
+import echarts from 'echarts'
+import { cogradientGroupChat } from '@/api/qw/groupChat'
+
+export default {
+  name: "Group_chat_user",
+  components:{},
+
+  props:{
+    rowDetailFrom:{},
+  },
+
+  watch:{
+    rowDetailFrom:{
+      handler(newVal){
+        // 当formData变化时重新查询
+        this.getList(newVal);
+        this.lineChart(newVal);
+      },
+      deep: true
+    }
+  },
+  data() {
+    return {
+      //折线图
+      toDay:[],
+      dailyJoinCount:[],
+      dailyOutCount:[],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 客户群成员列表格数据
+      group_chat_userList: [],
+      //成员类型
+      groupChatUserType:[],
+      //是否退群
+      groupChatUserIsOutType:[],
+
+      //入群方式
+      groupChatUserScene:[],
+
+      //退群方式
+      groupChatUserQuitSceneType:[],
+
+      //日期查询类型
+      groupChatUserDayType:[],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        chatId: null,
+        userId: null,
+        type: null,
+        unionid: null,
+        joinTime: null,
+        joinScene: null,
+        invitor: null,
+        invitorUserid: null,
+        groupNickname: null,
+        name: null,
+        companyId: null,
+        corpId: null,
+        isAdmin: null,
+        beginTime:null,
+        endTime:null,
+        countType:null,
+        isOut:null,
+        quitScene:null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      //日期快捷选择
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: '最近三天',
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 3);
+              picker.$emit('pick', [start, end]);
+            }
+          },{
+            text: '最近一周',
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit('pick', [start, end]);
+            }
+          }, {
+            text: '最近一个月',
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              picker.$emit('pick', [start, end]);
+            }
+          }, {
+            text: '最近三个月',
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              picker.$emit('pick', [start, end]);
+            }
+          }]
+      },
+
+      //日期选择
+      hospitalOrderScreenCharge:[],
+    };
+  },
+  created() {
+    this.getList(this.rowDetailFrom)
+    this.lineChart(this.rowDetailFrom)
+    //成员类型字典
+    this.getDicts("sys_qw_groupChat_user_type").then(response => {
+      this.groupChatUserType = response.data;
+    });
+
+    //入群方式字典
+    this.getDicts("sys_qw_groupChat_user_scene").then(response => {
+      this.groupChatUserScene = response.data;
+    });
+    this.getDicts("sys_qw_groupChat_user_day_type").then(response => {
+      this.groupChatUserDayType = response.data;
+    });
+
+    //是否退群
+    this.getDicts("sys_qw_groupCharUser_isOut").then(response => {
+      this.groupChatUserIsOutType = response.data;
+    });
+
+    //是否退群
+    this.getDicts("sys_qw_groupChar_quitScene").then(response => {
+      this.groupChatUserQuitSceneType = response.data;
+    });
+
+  },
+
+
+  methods: {
+    /** 查询客户群详细信息 */
+
+    getList:function(newVal) {
+
+      if (newVal && typeof newVal === 'object') {
+        this.queryParams.chatId = newVal.chatId || this.rowDetailFrom.chatId;
+      } else {
+        this.queryParams.chatId = this.rowDetailFrom.chatId;
+      }
+
+      this.loading = true
+      listGroup_chat_user(this.queryParams).then(response => {
+        this.group_chat_userList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+
+    },
+    //折线图初始化
+    lineChart:function(newVal){
+      this.resetLineChart();
+      this.queryParams.chatId=newVal.chatId;
+      //默认按星期
+      this.queryParams.countType=2
+      getDataWeekMonthCount(this.queryParams).then(response=>{
+        for (const  key in response.data){
+          this.toDay.push(response.data[key]["toDay"])
+          this.dailyJoinCount.push(response.data[key]["dailyJoinCount"])
+          this.dailyOutCount.push(response.data[key]["dailyOutCount"])
+        }
+        setTimeout(() => {
+          this.initEchart();
+        }, 100);
+      })
+
+    },
+
+    initEchart(){
+      const option = {
+        title: {
+          text: '时间段内新增成员,退群成员表'
+        },
+        tooltip: {
+          trigger: 'axis'
+        },
+        legend: {
+          data: ['入群人员数', '退群成员数']
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        toolbox: {
+          feature: {
+            saveAsImage: {}
+          }
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: this.toDay
+        },
+        yAxis: {
+          type: 'value'
+        },
+        series: [
+          {
+            name: '入群人员数',
+            type: 'line',
+            stack: 'Total',
+            data: this.dailyJoinCount
+          },
+          {
+            name: '退群成员数',
+            type: 'line',
+            stack: 'Total',
+            data: this.dailyOutCount
+          },
+        ]
+      }
+      const lineChart = echarts.init(document.getElementById('lineChart'))
+      lineChart.setOption(option,true);
+    },
+
+    //折线图
+    changeLine(){
+      this.resetLineChart();
+
+      if (this.hospitalOrderScreenCharge!=null) {
+        this.queryParams.beginTime=this.hospitalOrderScreenCharge[0]
+        this.queryParams.endTime=this.hospitalOrderScreenCharge[1]
+        getDataWeekMonthCount(this.queryParams).then(response=>{
+          for (const  key in response.data){
+            this.toDay.push(response.data[key]["toDay"])
+            this.dailyJoinCount.push(response.data[key]["dailyJoinCount"])
+            this.dailyOutCount.push(response.data[key]["dailyOutCount"])
+          }
+          setTimeout(() => {
+            this.initEchart();
+          }, 100);
+        })
+      }
+    },
+    changeLineType(){
+      this.resetLineChart();
+      if (this.queryParams.countType==2){
+        this.queryParams.countType=2
+        getDataWeekMonthCount(this.queryParams).then(response=>{
+          for (const  key in response.data){
+            this.toDay.push(response.data[key]["toDay"])
+            this.dailyJoinCount.push(response.data[key]["dailyJoinCount"])
+            this.dailyOutCount.push(response.data[key]["dailyOutCount"])
+          }
+          setTimeout(() => {
+            this.initEchart();
+          }, 100);
+        })
+      }
+      if (this.queryParams.countType==3){
+        this.queryParams.countType=3
+        getDataWeekMonthCount(this.queryParams).then(response=>{
+          for (const  key in response.data){
+            this.toDay.push(response.data[key]["toDay"])
+            this.dailyJoinCount.push(response.data[key]["dailyJoinCount"])
+            this.dailyOutCount.push(response.data[key]["dailyOutCount"])
+          }
+          setTimeout(() => {
+            this.initEchart();
+          }, 100);
+        })
+      }
+    },
+
+    //同步某个客户群(暂用)
+    getCogradientGroupChat(){
+      this.loading = true;
+      cogradientGroupChatUser(this.rowDetailFrom).then(response=>{
+        if (response.code == 200) {
+          this.msgSuccess("同步成功");
+          this.getList();
+        } else {
+          this.msgError(response.msg);
+        }
+        this.loading = false;
+      })
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        chatId: null,
+        userId: null,
+        type: null,
+        unionid: null,
+        joinTime: null,
+        joinScene: null,
+        invitor: null,
+        invitorUserid: null,
+        groupNickname: null,
+        name: null,
+        companyId: null,
+        corpId: null,
+        isAdmin: null
+      };
+      this.resetForm("form");
+    },
+
+    //折线图重置
+    resetLineChart(){
+      this.toDay=[];
+      this.dailyJoinCount=[];
+      this.dailyOutCount=[];
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+  }
+};
+</script>
+<style>
+  .topBlockStyle{
+    margin: 30px;
+    color: white;
+    font-size: 20px
+  }
+</style>

+ 181 - 0
src/views/qw/user/qwUserSelectOne.vue

@@ -0,0 +1,181 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <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>
+        <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-table v-loading="loading" :data="userList" ref="userList">
+        <el-table-column label="企微员工账号" align="center" prop="qwUserId" />
+		    <el-table-column label="员工昵称" align="center" prop="qwUserName" />
+        <el-table-column label="员工部门" align="center" prop="departmentName" />
+        <el-table-column label="员工昵称" align="center" prop="nickName"/>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" >
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleSelectionChange(scope.row)"
+          >选择此人</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="handlePaginationChange"
+    />
+
+        <div style="margin-top: 30px;display: flex;justify-content: center;gap: 12px">
+      <el-button plain @click="handleClear">不选(清空发送人)</el-button>
+      <el-button type="warning" icon="el-icon-check" @click="confirmSelect">确定选择</el-button>
+    </div>
+
+  </div>
+</template>
+
+<script>
+import { listUser } from "@/api/qw/user";
+
+
+export default {
+  name: "qwUserSelectOne",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      selectUsers: null,
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企微用户表格数据
+      userList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        qwUserId: null,
+        companyId: null,
+        companyUserId: null,
+        corpId: null,
+        nickName: null
+      },
+      // 表单参数
+      form: {},
+
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+
+
+
+  },
+  methods: {
+    /** 查询企微用户列表 */
+    getList() {
+      this.loading = true;
+      listUser(this.queryParams).then(response => {
+        // 如果 companyUserId 为 null,移除列
+        this.userList = response.rows.filter(column => column.companyUserId !=null);
+        this.total = response.total;
+        this.loading = false;
+
+      });
+    },
+
+    getDetails(corpId){
+      this.queryParams.corpId=corpId;
+      this.getList()
+    },
+    handlePaginationChange(row) {
+      this.queryParams.pageNum = row.page;
+      this.queryParams.pageSize = row.limit;
+      this.getList();
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        qwUserId: null,
+        companyId: null,
+        companyUserId: null,
+        corpId: null
+      };
+      this.resetForm("form");
+    },
+    //确定选择
+    confirmSelect(){
+      this.$emit("selectUserList",this.selectUsers);
+      this.resetSelect();
+    },
+    //重置选择
+    resetSelect(){
+      //重置
+      this.queryParams={
+        pageNum: 1,
+        pageSize: 10,
+        qwUserId: null,
+        companyId: null,
+        companyUserId: null,
+        corpId: null,
+        nickName: null
+      },
+        this.getList();
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+    // 选中数据
+    handleSelectionChange(selection) {
+      this.$emit("selectUser",selection);
+    },
+    // 用户点击“不选”
+    handleClear() {
+      this.$emit("selectUser",{});   // 传空对象,表示清空
+    },
+  }
+};
+</script>