三七 před 17 hodinami
rodič
revize
fbd8160dc3

+ 8 - 0
src/api/course/courseWatchLog.js

@@ -9,6 +9,14 @@ export function listCourseWatchLog(query) {
   })
 }
 
+export function deptListCourseWatchLog(query) {
+  return request({
+    url: '/course/courseWatchLog/deptList',
+    method: 'get',
+    params: query
+  })
+}
+
 export function myListCourseWatchLog(query) {
   return request({
     url: '/course/courseWatchLog/myList',

+ 17 - 0
src/api/qw/externalContact.js

@@ -8,6 +8,23 @@ export function listExternalContact(query) {
     params: query
   })
 }
+
+// 查询企业微信客户列表
+export function getRepeat(query) {
+  return request({
+    url: '/qw/externalContact/getRepeat',
+    method: 'get',
+    params: query
+  })
+}
+
+export function myDeptExtList(query) {
+  return request({
+    url: '/qw/externalContact/myDeptExtList',
+    method: 'get',
+    params: query
+  })
+}
 export function myList(query) {
   return request({
     url: '/qw/externalContact/myList',

+ 9 - 0
src/api/qw/externalContactTransferLog.js

@@ -9,6 +9,15 @@ export function listExternalContactTransferLog(query) {
   })
 }
 
+export function listTransferLogDeptList(query) {
+  return request({
+    url: '/qw/externalContactTransferLog/deptList',
+    method: 'get',
+    params: query
+  })
+}
+
+
 export function syncTransferLog(id) {
   return request({
     url: '/qw/externalContactTransferLog/sync/' + id,

+ 17 - 0
src/api/qw/friendWelcome.js

@@ -8,6 +8,23 @@ export function listFriendWelcome(query) {
     params: query
   })
 }
+
+export function listMyFriendWelcome(query) {
+  return request({
+    url: '/qw/friendWelcome/myList',
+    method: 'get',
+    params: query
+  })
+}
+
+export function deptListFriendWelcome(query) {
+  return request({
+    url: '/qw/friendWelcome/deptList',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询好友欢迎语列表
 export function myList(query) {
   return request({

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

@@ -8,6 +8,20 @@ export function listGroupChat(query) {
     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) {
@@ -30,6 +44,14 @@ export function cogradientGroupChat(corpId) {
   })
 }
 
+export function cogradientMyGroupChat(corpId) {
+  return request({
+    url: '/qw/groupChat/cogradientMyGroupChat/'+corpId,
+    method: 'get',
+  })
+}
+
+
 
 export function listAll(qwUserIds, corpId, sopId) {
   return request({

+ 16 - 0
src/api/qw/sop.js

@@ -8,6 +8,22 @@ export function listSop(query) {
     params: query
   })
 }
+
+export function listMySop(query) {
+  return request({
+    url: '/qw/sop/myList',
+    method: 'get',
+    params: query
+  })
+}
+export function listDeptSop(query) {
+  return request({
+    url: '/qw/sop/deptList',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询企微sop模板列表
 export function listAiChatSop(query) {
   return request({

+ 8 - 0
src/api/qw/user.js

@@ -9,6 +9,14 @@ export function staffListUser(query) {
   })
 }
 
+export function myDepartListUser(query) {
+  return request({
+    url: '/qw/user/myDepartList',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询企微用户列表
 export function listUser(query) {
   return request({

+ 506 - 0
src/views/course/courseWatchLog/deptWatchLog.vue

@@ -0,0 +1,506 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="会员ID" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入会员ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="会员昵称" prop="nickName">
+        <el-input
+          v-model="queryParams.nickName"
+          placeholder="请输入会员昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="企微客户昵称" prop="nickName" >
+        <el-input
+          v-model="queryParams.externalUserName"
+          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.label"
+            :value="item.value">
+          </el-option>
+        </el-select>
+      </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
+            v-for="dict in courseLists"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="小节" prop="videoId">
+        <el-select filterable  v-model="queryParams.videoId" placeholder="请选择小节"  clearable size="small">
+          <el-option
+            v-for="dict in videoList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="企微ID" prop="qwUserUserId">
+        <el-input
+          v-model="queryParams.qwUserUserId"
+          placeholder="请输入所属企微ID"
+          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="deptName">-->
+<!--        <el-input-->
+<!--          v-model="queryParams.deptName"-->
+<!--          placeholder="请输入部门名称"-->
+<!--          clearable-->
+<!--          size="small"-->
+<!--          @keyup.enter.native="handleQuery"-->
+<!--        />-->
+<!--      </el-form-item>-->
+      <el-form-item label="营期时间" prop="scheduleTime">
+        <el-date-picker
+          v-model="scheduleTime"
+          type="daterange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          @change="handleScheduleTimeChange">
+        </el-date-picker>
+      </el-form-item>
+      <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="createChange"></el-date-picker>
+      </el-form-item>
+      <el-form-item label="最新更新时间" prop="updateTime">
+        <el-date-picker v-model="updateTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange"
+                        range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="updateChange"></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="warning"-->
+<!--          plain-->
+<!--          icon="el-icon-download"-->
+<!--          size="mini"-->
+<!--          :loading="exportLoading"-->
+<!--          @click="handleExport"-->
+<!--          v-hasPermi="['course:courseWatchLog:export']"-->
+<!--        >导出</el-button>-->
+<!--      </el-col>-->
+<!--      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>-->
+<!--    </el-row>-->
+
+    <el-tabs type="card" v-model="activeName" @tab-click="handleClickX">
+      <el-tab-pane label="全部" name="00"></el-tab-pane>
+      <el-tab-pane v-for="(item,index) in logTypeOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+    </el-tabs>
+    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="记录编号" align="center" prop="logId" />
+      <el-table-column label="企微客户" align="center" prop="externalUserName"/>
+      <el-table-column label="会员ID" align="center" prop="userId" />
+      <el-table-column label="会员昵称" align="center" prop="fsNickName">
+        <template slot-scope="scope">
+          <div style="display: flex;white-space: nowrap">
+            <div style="margin: auto">
+              {{scope.row.fsNickName}}
+            </div>
+            <el-popover
+              placement="right"
+              title=""
+              trigger="hover">
+              <img slot="reference" :src="scope.row.fsAvatar" style="width: 30px;height: 30px">
+              <img :src="scope.row.fsAvatar" style="max-width: 200px;max-height: 200px">
+            </el-popover>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="课程名称" align="center" prop="courseName" />
+      <el-table-column label="小节名称" align="center" prop="videoName" />
+      <el-table-column label="记录类型" align="center" prop="logType">
+        <template slot-scope="scope">
+          <dict-tag :options="logTypeOptions" :value="scope.row.logType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="播放时长" align="center" prop="duration" />
+      <el-table-column label="所属销售" align="center" prop="companyUserName" />
+<!--      <el-table-column label="所属公司" align="center" prop="companyName" />-->
+      <el-table-column label="企微员工名称" align="center" prop="qwUserName" />
+<!--      <el-table-column label="所属发送方式" align="center" prop="sendType" />-->
+      <el-table-column label="创建时间" align="center" prop="createTime" />
+      <el-table-column label="更新时间" align="center" prop="updateTime" />
+      <el-table-column label="完课时间" align="center" prop="finishTime" />
+      <el-table-column label="营期时间" align="center" prop="campPeriodTime" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+  </div>
+</template>
+
+<script>
+import { deptListCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog } from "@/api/course/courseWatchLog";
+import { courseList,videoList } from '../../../api/course/courseRedPacketLog'
+import { getCompanyUserListLikeName } from "@/api/company/companyUser";
+import {getTask} from "@/api/common";
+export default {
+  name: "CourseWatchLog",
+  data() {
+    return {
+      activeName:"00",
+      createTime:null,
+      updateTime:null,
+      courseLists:[],
+      videoList:[],
+      logTypeOptions:[],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 短链课程看课记录表格数据
+      courseWatchLogList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        nickName: null,
+        videoId: null,
+        logType: null,
+        qwExternalContactId: null,
+        externalUserName:null,
+        duration: null,
+        qwUserId: null,
+        qwUserName: null, //企微名称
+        qwUserUserId: null, //企微id
+        deptName: null, //部门名称
+        companyUserId: null,
+        companyId: null,
+        courseId: null,
+        sTime:null,
+        eTime:null,
+        upSTime:null,
+        upETime:null,
+        scheduleStartTime: null,
+        scheduleEndTime: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      scheduleTime: null,
+      // 员工选项列表
+      companyUserOptionsParams: {
+        name: undefined,
+        hasNextPage: false,
+        pageNum: 1,
+        pageSize: 10
+      },
+      companyUserOptionsLoading: false,
+      companyUserOptions: [],
+    };
+  },
+  created() {
+    courseList().then(response => {
+      this.courseLists = response.list;
+    });
+    this.getList();
+    this.getDicts("sys_course_watch_log_type").then(response => {
+      this.logTypeOptions = response.data;
+    });
+  },
+  methods: {
+    courseChange(row){
+      this.queryParams.videoId=null;
+      if(row === ''){
+        this.videoList=[];
+        return
+      }
+      videoList(row).then(response => {
+        this.videoList=response.list
+      });
+    },
+    createChange() {
+      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;
+      }
+    },
+
+    updateChange(){
+      if (this.updateTime != null) {
+        this.queryParams.upSTime = this.updateTime[0];
+        this.queryParams.upETime = this.updateTime[1];
+      } else {
+        this.queryParams.upSTime = null;
+        this.queryParams.upETime = null;
+      }
+    },
+    handleClickX(tab,event){
+      this.activeName=tab.name;
+      if(tab.name=="00"){
+        this.queryParams.logType=null;
+      }else{
+        this.queryParams.logType=tab.name;
+      }
+      this.getList()
+    },
+    /** 查询短链课程看课记录列表 */
+    getList() {
+      this.loading = true;
+      if(this.queryParams.logType == "10"){
+        this.queryParams.logType = null;
+      }
+      deptListCourseWatchLog(this.queryParams).then(response => {
+        this.courseWatchLogList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        logId: null,
+        userId: null,
+        videoId: null,
+        logType: null,
+        createTime: null,
+        updateTime: null,
+        qwExternalContactId: null,
+        externalUserName:null,
+        duration: null,
+        qwUserId: null,
+        companyUserId: null,
+        companyId: null,
+        courseId: null,
+        scheduleStartTime: null,
+        scheduleEndTime: null,
+      };
+      this.scheduleTime=null;
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.createTime = null;
+      this.scheduleTime = null;
+      this.queryParams.sTime = null;
+      this.queryParams.eTime = null;
+      this.queryParams.upSTime = null;
+      this.queryParams.upETime = null;
+      this.queryParams.scheduleStartTime = null;
+      this.queryParams.scheduleEndTime = null;
+      this.scheduleTime=null;
+      this.updateTime=null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.logId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加短链课程看课记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const logId = row.logId || this.ids
+      getCourseWatchLog(logId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改短链课程看课记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.logId != null) {
+            updateCourseWatchLog(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCourseWatchLog(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const logIds = row.logId || this.ids;
+      this.$confirm('是否确认删除短链课程看课记录编号为"' + logIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delCourseWatchLog(logIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const that = this
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportCourseWatchLog(queryParams);
+        }).then(response => {
+          if (response.code === 200){
+            that.msgSuccess(response.msg);
+            that.taskId = response.data;
+            that.time = setInterval(function(){
+              //查订单
+              getTask(that.taskId).then(res => {
+                if(res.data.status === 1){
+                  that.exportLoading = false;
+                  clearTimeout(that.time)
+                  that.time = null;
+                  that.download(res.data.fileUrl);
+                }
+              });
+            },10000);
+          } else {
+            that.msgError(response.msg)
+            that.exportLoading = false
+          }
+        }).catch(() => {});
+    },
+    handleScheduleTimeChange(val) {
+      if (val) {
+        this.queryParams.scheduleStartTime = val[0];
+        this.queryParams.scheduleEndTime = val[1];
+      } else {
+        this.queryParams.scheduleStartTime = null;
+        this.queryParams.scheduleEndTime = null;
+      }
+    },
+    /**
+     * 根据名称模糊查询用户列表
+     * @param query 参数
+     */
+    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]
+        this.companyUserOptionsParams.hasNextPage = response.data.hasNextPage
+        this.companyUserOptionsLoading = false;
+      });
+    },
+    /**
+     * 加载更多员工选项
+     */
+    loadMoreCompanyUserOptions() {
+      if (!this.companyUserOptionsParams.hasNextPage) {
+        return;
+      }
+
+      this.companyUserOptionsParams.pageNum += 1
+      this.getCompanyUserListLikeName()
+    },
+  }
+};
+</script>

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

@@ -209,7 +209,7 @@ export default {
         upETime:null,
         scheduleStartTime: null,
         scheduleEndTime: null,
-        sendType:'1',
+        sendType:null,
       },
       // 表单参数
       form: {},

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

@@ -388,7 +388,7 @@ export default {
         upETime:null,
         scheduleStartTime: null,
         scheduleEndTime: null,
-        sendType:'1',
+        sendType:null,
       },
       // 表单参数
       form: {},

+ 1929 - 0
src/views/qw/externalContact/deptIndex.vue

@@ -0,0 +1,1929 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <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="gender">
+        <el-select v-model="queryParams.gender" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in genderOptions"
+            :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="levelType">
+        <el-select v-model="queryParams.levelType" placeholder="等级升降" clearable size="small">
+          <el-option
+            v-for="dict in ratingUpFall"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+
+      <el-form-item label="电话号码" prop="remarkMobiles">
+        <el-input
+          v-model="queryParams.remarkMobiles"
+          placeholder="请输入备注电话号码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="来源" prop="addWay">
+
+        <el-select v-model="queryParams.addWay" placeholder="来源" clearable size="small">
+          <el-option
+            v-for="dict in addWayOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+
+        <el-select v-model="queryParams.status" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </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="isBindMini">
+        <el-select v-model="queryParams.isBindMini" placeholder="是否绑定小程序" clearable size="small" @change="handleQuery" >
+          <el-option
+            v-for="dict in isBindMiniOptions"
+            :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>-->
+
+        <div @click="hangleChangeTags()" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 250px">
+          <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
+            <el-tag type="success"
+                    closable
+                    :disable-transitions="false"
+                    v-for="list in this.selectTags"
+                    :key="list.tagId"
+                    @close="handleCloseTags(list)"
+                    style="margin: 3px;"
+            >{{list.name}}
+            </el-tag>
+          </div>
+        </div>
+
+
+      </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="companyUserName">
+        <el-input
+          v-model="queryParams.companyUserName"
+          placeholder="请输入员工名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <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="lossTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.lossTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择流失时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="删除时间" prop="delTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.delTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        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
+                icon="el-icon-plus"
+                size="mini"
+                @click="handleAdd"
+                v-hasPermi="['qw:externalContact:add']"
+              >同步</el-button>
+            </el-col> -->
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotes"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注</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="addUserTag"
+          v-hasPermi="['qw:externalContact:addTag']"
+        >批量添加标签</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="delUserTag"
+          v-hasPermi="['qw:externalContact:delTag']"
+        >批量移除标签</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="updateTalk"
+        >批量更改交流状态</el-button>
+      </el-col>
+      <!--       <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="primary"-->
+      <!--          plain-->
+      <!--          size="mini"-->
+      <!--          @click="setUserCourseSop"-->
+      <!--          v-hasPermi="['qw:externalContact:setCourseSop']"-->
+      <!--        >批量设置课程SOP</el-button>-->
+      <!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-tabs type="card" v-model="isBindActiveName" @tab-click="handleClickX">
+      <el-tab-pane label="全部" name="all"></el-tab-pane>
+      <!--      <el-tab-pane label="已绑定CRM" name="isBind"></el-tab-pane>-->
+      <!--      <el-tab-pane label="未绑定CRM" name="noBind"></el-tab-pane>-->
+    </el-tabs>
+
+    <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="企微客户ID" align="center" prop="id" />
+      <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="企微客户名称"  prop="name" width="110px"/>
+      <el-table-column label="客户称呼"  prop="stageStatus" width="110px"/>
+      <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="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="tagIdsName" width="250px">
+        <template slot-scope="scope">
+          <div v-for="name in scope.row.tagIdsName"  style="display: inline;">
+            <el-tag type="success">{{ name }}</el-tag>
+          </div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="状态" align="center" prop="status" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </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="levelType" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingUpFall" :value="scope.row.levelType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="绑定员工" align="center" prop="companyUserName" />
+      <el-table-column label="添加时间" align="center" prop="createTime" width="100px" />
+      <el-table-column label="流失时间" align="center" prop="lossTime" width="100px" />
+      <el-table-column label="删除时间" align="center" prop="delTime" width="100px" />
+      <el-table-column label="备注电话号码" align="center" prop="remarkMobiles" width="150px">
+        <template slot-scope="scope">
+          <div v-for="i in JSON.parse(scope.row.remarkMobiles)" :key="i">{{i}}</div>
+        </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="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="isRepeat" fixed="right">
+        <template slot-scope="scope">
+          <el-tag type="success" v-if="scope.row.isRepeat == 0">否</el-tag>
+          <el-tag type="danger" v-if="scope.row.isRepeat == 1">是</el-tag>
+          <el-button
+            v-show="scope.row.isRepeat == 1"
+            size="mini"
+            type="text"
+            @click="openRepeat(scope.row)"
+          >查看</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否绑小程序" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.fsUserId" >已绑定</el-tag>
+          <el-tag v-else type="info"> 未绑定</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="修改" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            v-show="scope.row.status==0||scope.row.status==2"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:externalContact:edit']"
+          >修改备注</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user-solid"
+            @click="handleAppellation(scope.row)"
+          >修改客户称呼</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+          <!--          <el-button-->
+          <!--            size="mini"-->
+          <!--            type="text"-->
+          <!--            icon="el-icon-edit-outline"-->
+          <!--            @click="handleUpdateCustomer(scope.row)"-->
+          <!--            >-->
+          <!--            <span v-if="scope.row.customerId">换绑CRM</span>-->
+          <!--            <span v-else>绑定CRM</span>-->
+          <!--          </el-button>-->
+
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit-outline"
+            @click="handleUpdateUser(scope.row)"
+          >
+            <span v-if="scope.row.fsUserId">换绑会员</span>
+            <span v-else>绑定会员</span>
+          </el-button>
+
+          <el-button
+            v-show="scope.row.fsUserId"
+            size="mini"
+            type="text"
+            icon="el-icon-thumb"
+            @click="handleUnBindUserId(scope.row)"
+            v-hasPermi="['qw:externalContact:unBindUserId']"
+          >
+            <span>解除会员绑定</span>
+          </el-button>
+
+
+          <el-button v-show="scope.row.customerId"
+            size="mini"
+            type="text"
+            icon="el-icon-paperclip"
+            @click="handleShow(scope.row)"
+          >CRM客户详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            @click="handledetails(scope.row)"
+          >AI获取用户信息
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-show="scope.row.fsUserId"
+            @click="handleUserdetails(scope.row)"
+          >会员详情
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-show="scope.row.fsUserId"
+            @click="healthHandledetails(scope.row)"
+          >健康档案
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination-more
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-drawer size="75%" :title="show.title" :visible.sync="show.open">
+      <customer-details  ref="customerDetails" @refreshList="refreshList"/>
+    </el-drawer>
+
+
+    <!--  搜索标签   -->
+    <el-dialog :title="changeTagDialog.title" :visible.sync="changeTagDialog.open" width="1000px"  append-to-body>
+
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(queryTagParams.name)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <div v-for="item in tagGroupList" :key="item.id"  >
+        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+          <span class="name-background">{{ item.name }}</span>
+        </div>
+        <div class="tag-container">
+          <a
+            v-for="tagItem in item.tag"
+            class="tag-box"
+            @click="tagSelection(tagItem)"
+            :class="{ 'tag-selected': tagItem.isSelected }"
+          >
+            {{ tagItem.name }}
+          </a>
+        </div>
+      </div>
+
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagSubmitForm()">确 定</el-button>
+        <el-button @click="tagCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量添加客户备注" :visible.sync="notesOpen.open" width="800px" append-to-body>
+      <el-card>
+        <el-row>
+          <el-col>
+            <el-radio-group v-model="notesOpen.nameType" style="margin-bottom: 2%">
+              <el-radio :label="1">
+                客户名称添加在【新备注】【前】
+              </el-radio>
+              <el-radio :label="2">
+                客户名称添加在【新备注】【后】
+              </el-radio>
+              <el-radio :label="3">
+                不添加客户名称
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col >
+            <el-radio-group v-model="notesOpen.type">
+              <el-radio
+                :label="1"
+              >添加【新备注】在最【前】面</el-radio>
+              <el-radio
+                :label="2"
+              >添加【新备注】在最【后】面</el-radio>
+              <el-radio
+                :label="3"
+              >替换所有备注</el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-input v-model="notesOpen.notes" placeholder="请输入客户备注(最多20个字,含已有的)" clearable size="small"
+                      maxlength="20" show-word-limit style="width: 500px;margin-top: 3%" />
+            <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
+              <i class="el-icon-info"></i>
+              由于企业微信官方限制,备注最多20个字,且自动会去除末尾超出的字
+            </div>
+          </el-col>
+        </el-row>
+      </el-card>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="notesSubmitForm()">确 定</el-button>
+        <el-button @click="notesCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量添加标签" :visible.sync="tagOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addTagSubmitForm()">确 定</el-button>
+        <el-button @click="addTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量移除标签" :visible.sync="tagDelOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagDelSubmitForm()">确 定</el-button>
+        <el-button @click="DelTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 添加或修改企业微信客户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="描述信息" prop="description">
+          <el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入描述信息" />
+        </el-form-item>
+
+        <el-form-item label="备注电话号码" prop="remarkMobiles">
+
+          <el-tag
+            :key="tag"
+            v-for="tag in remarkMobiles"
+            closable
+            :disable-transitions="false"
+            @close="handleClose(tag)">
+            {{tag}}
+          </el-tag>
+          <el-input
+            style="width:110px"
+            class="input-new-tag"
+            v-if="inputVisible"
+            v-model="inputValue"
+            ref="saveTagInput"
+            size="small"
+            @keyup.enter.native="handleInputConfirm"
+            @blur="handleInputConfirm"
+          >
+          </el-input>
+          <el-button v-else class="button-new-tag" size="small" style="width: 110px" @click="showInput">新增电话</el-button>
+
+        </el-form-item>
+
+
+        <el-form-item label="备注企业名称" prop="remarkCorpName">
+          <el-input v-model="form.remarkCorpName" placeholder="请输入备注企业名称" />
+        </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>
+
+    <el-dialog :title="callOpen.title" :visible.sync="callOpen.open" width="500px" append-to-body>
+      <el-form ref="callOpenFrom" :model="callOpenFrom" :rules="callOpenRule" label-width="110px">
+        <el-form-item label="客户称呼" prop="stageStatus">
+          <el-input v-model="callOpenFrom.stageStatus" placeholder="请输入客户称呼" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer" >
+        <el-button type="primary" @click="submitCallOpenFrom">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 绑定客户   -->
+    <el-dialog :title="bindCustomer.title" :visible.sync="bindCustomer.open"  width="1200px" append-to-body>
+      <mycustomer ref="mycustomer"  @bindCustomerId="bindCustomerId"></mycustomer>
+    </el-dialog>
+
+    <!--    设置一个课程sop-->
+    <el-dialog :title="setSop.title" :visible.sync="setSop.open"  width="1200px" append-to-body>
+      <SopDialog ref="SopDialog"  @bindCourseSop="bindCourseSop"></SopDialog>
+    </el-dialog>
+
+    <el-dialog :title="user.title" :visible.sync="user.open" width="800px" append-to-body>
+      <selectUser ref="selectUser" @bindMiniCustomerId="bindMiniCustomerId"></selectUser>
+    </el-dialog>
+
+    <el-dialog :title="info.title" :visible.sync="info.open"   width="1100px" append-to-body>
+      <info  ref="Details" />
+    </el-dialog>
+
+    <el-dialog
+      :title="resultTitle"
+      :visible.sync="resultDialogVisible"
+      width="50%"
+      custom-class="feedback-dialog"
+    >
+      <pre style="white-space: pre-wrap; font-family: inherit;">{{ resultMessage }}</pre>
+      <span slot="footer" class="dialog-footer">
+    <el-button @click="resultDialogVisible = false">关闭</el-button>
+  </span>
+    </el-dialog>
+
+    <el-dialog
+      title="企微账号"
+      :visible.sync="repeat.open"
+      width="50%"
+      custom-class="feedback-dialog"
+    >
+      <el-row style="padding: 20px 10px">
+        <el-tag v-for="item in repeat.list">{{item.qwUserName}}</el-tag>
+      </el-row>
+    </el-dialog>
+    <el-drawer
+      :with-header="false"
+      size="75%"
+      :title="showHealth.title" :visible.sync="showHealth.open">
+      <healthRecordDetails  ref="Details" />
+    </el-drawer>
+    <el-drawer
+      :with-header="false"
+      size="75%"
+      :title="showUser.title"
+      :visible.sync="showUser.open">
+      <userDetails  ref="userDetails" />
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import {
+  addExternalContact,
+  addTag,
+  batchUpdateExternalContactNotes,
+  bindUserId,
+  delExternalContact,
+  delTag,
+  editbindCustomer,
+  exportExternalContact,
+  getCustomerCourseSop,
+  getExternalContact,
+  listExternalContact,
+  setCustomerCourseSop,
+  setCustomerCourseSopList,
+  unBindUserId,
+  updateExternalContact,
+  getRepeat,
+  updateExternalContactCall, myDeptExtList
+} from '../../../api/qw/externalContact'
+import {getMyQwCompanyList} from "@/api/qw/user";
+import {getId} from "@/api/store/healthRecord";
+import {listTag, searchTags,} from "@/api/qw/tag";
+import {allListTagGroup} from "@/api/qw/tagGroup";
+import mycustomer from '@/views/qw/externalContact/mycustomer'
+import customerDetails from '@/views/qw/externalContact/customerDetails'
+import SopDialog from '@/views/course/sop/SopDialog.vue'
+import selectUser from "@/views/qw/externalContact/selectUser.vue";
+import info from "@/views/qw/externalContact/info.vue";
+import {editTalk} from "@/api/qw/externalContactInfo";
+import healthRecordDetails from '@/views/store/components/healthRecordDetails.vue'
+import userDetails from '@/views/store/components/userDetails.vue';
+import PaginationMore from "../../../components/PaginationMore/index.vue";
+
+export default {
+  name: "deptExternalContact",
+  components:{PaginationMore, mycustomer,customerDetails,SopDialog,selectUser,info,healthRecordDetails,userDetails},
+  data() {
+    return {
+
+      resultDialogVisible: false,
+      resultMessage: '',
+      resultTitle:'',
+      repeat: {
+        open: false,
+        loading: true,
+        param:{},
+        list:[]
+      },
+
+      user:{
+        open:false,
+        title:"修改客户"
+      },
+      userForm:{
+        id:null,
+        fsUserId:null,
+      },
+      info:{
+        title:"用户信息",
+        open:false,
+      },
+
+      isBindMiniOptions:[
+        {dictLabel:"已绑定",dictValue:'isBindMini'},
+        {dictLabel:"未绑定",dictValue:'noBindMini'},
+      ],
+      //标签弹窗选择
+      tagChange:{
+        open:false,
+        index:null,
+      },
+      sTime:null,
+      eTime:null,
+      createTime:null,
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      tagOpen:false,
+      notesOpen: {
+        type:1,
+        nameType:3,
+        open:false,
+        notes:null,
+      },
+      tagDelOpen:false,
+      // 选中数组
+      ids: [],
+      isBindActiveName:"all",
+      remarkMobiles: [],
+      inputVisible: false,
+      inputValue: '',
+      // 非单个禁用
+      single: true,
+      tagGroupList: [],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业微信客户表格数据
+      externalContactList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 用户类别字典
+      typeOptions: [],
+      ratingType: [],
+      ratingUpFall: [],
+      // 性别字典
+      genderOptions: [],
+
+      addTagForm:{
+        userIds:[],
+        tagIds:[]
+      },
+
+      myQwCompanyList:[],
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+      showHealth:{
+        title:"健康档案",
+        open:false,
+      },
+      showTongue:{
+        title:"舌苔报告",
+        open:false,
+      },
+      showUser:{
+        title:"会员详情",
+        open:false,
+      },
+
+      //存储选择的客户
+      chooseCustomerSOP:null,
+
+      setSop:{
+        title:"选择课节SOP",
+        open:false,
+        //区分单选1还是多选2
+        type:null,
+      },
+      //合成的客户-课节SOP参数
+      customerCourseForm:{},
+
+      //查询是否已经设置过客户-某个课节的SOP
+      customerCourseFormLogs:{},
+      //绑定客户
+      bindCustomer:{
+        title:null,
+        open:false,
+      },
+      callOpen:{
+        open:false,
+        title: '修改客户称呼',
+      },
+      callOpenFrom:{
+        id:null,
+        stageStatus:null,
+      },
+      callOpenRule:{
+        stageStatus:[{required:true,message:"员工称呼不能为空",trigger:"blur"}]
+      },
+      //绑定的参数表
+      qwFormCustomer:{
+        externalContactId:null,
+        customerId:null,
+      },
+      // 来源字典
+      addWayOptions: [],
+
+      //标签
+      changeTagDialog:{
+        title:"",
+        open:false,
+      },
+
+      queryTagParams:{
+        pageNum: 1,
+        pageSize: 10,
+        total:0,
+        name:null,
+        corpId:null,
+      },
+
+      tagTotal:0,
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        qwUserName:null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        qwUserId:null,
+        gender: null,
+        description: null,
+        tagIds: null,
+        remark:null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        status:null,
+        transferStatus:null,
+        isBind:null,
+        isBindMini:null,
+        lossTime:null,
+        sTime:null,
+        eTime:null,
+        createTime:null,
+        level:null,
+        levelType:null
+      },
+      selectTags:[],
+      // 表单参数
+      form: {},
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+      },
+      tongueReportParams: {
+        userId: null,
+      }
+    };
+  },
+  created() {
+
+    this.getDicts("sys_qw_externalContact_type").then(response => {
+      this.typeOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_type").then(response => {
+      this.ratingType = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_upFall").then(response => {
+      this.ratingUpFall = response.data;
+    });
+
+    getMyQwCompanyList().then(response => {
+      this.myQwCompanyList = response.data;
+      if(this.myQwCompanyList!=null){
+        this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+
+        var listTagFrom={corpId:this.queryParams.corpId}
+        listTag(listTagFrom).then(response => {
+          this.tagList = response.rows;
+        });
+        this.getList();
+
+      }
+    });
+
+
+    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;
+    });
+
+  },
+  methods: {
+    async healthHandledetails(row) {
+      try {
+        console.log(row.fsUserId);
+        console.log(row);
+
+        // 先尝试获取健康记录数据
+        const res = await getId(row.fsUserId);
+        console.log(res);
+
+        // 只有获取数据成功后才打开对话框
+        this.showHealth.open = true;
+
+        // 确保对话框DOM已更新
+        await this.$nextTick();
+        this.$refs.Details.getDetails(res.data);
+
+      } catch (error) {
+        console.error('获取健康档案失败:', error);
+        //this.$message.error('获取健康档案失败: ' + (error.message || '该用户还未填写健康档案'));
+      }
+    },
+    async handleUserdetails(row){
+      this.showUser.open = true;
+      try {
+        await this.$nextTick();
+        this.$refs.userDetails.getDetails(row.fsUserId);
+      } catch (error) {
+        console.error('获取会员详情失败:', error);
+      }
+    },
+    change(){
+      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;
+      }
+
+    },
+    updateCorpId(){
+      var listTagFrom={corpId:this.queryParams.corpId}
+      listTag(listTagFrom).then(response => {
+        this.tagList = response.rows;
+      });
+      this.getList();
+    },
+    /** 查询企业微信客户列表 */
+    getList() {
+      this.loading = true;
+      myDeptExtList(this.queryParams).then(response => {
+        this.externalContactList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    bindMiniCustomerId(row){
+      console.log(row)
+      this.userForm.fsUserId=row;
+      bindUserId(this.userForm).then(res=>{
+        if (res.code==200){
+          this.$message.success('绑定成功')
+        }else {
+          this.$message.error('绑定失败:',res.msg)
+        }
+        this.getList()
+        this.user.open=false;
+      })
+    },
+    /** 查看客户详情 */
+    handleShow(row){
+      this.show.open=true;
+      var that=this;
+      const tab = "visit";
+      setTimeout(() => {
+        that.$refs.customerDetails.getDetails(row.customerId);
+        that.$refs.customerDetails.handleClick(tab);
+
+      }, 200);
+    },
+
+    handledetails(row){
+      this.info.open=true;
+      setTimeout(() => {
+        this.$refs.Details.getDetails(row.id);
+      }, 1);
+    },
+
+    closeInfo(){
+      this.info.open=false
+    },
+    handleClickX(tab, event) {
+
+      this.queryParams.isBind=tab.name;
+      this.handleQuery();
+    },
+
+    handleClose(tag) {
+      this.remarkMobiles.splice(this.remarkMobiles.indexOf(tag), 1);
+    },
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick(_ => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.remarkMobiles.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = '';
+    },
+
+    handleBatchUpdateNotes(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要添加备注的客户');
+      }
+
+      this.notesOpen.open=true;
+
+    },
+
+    addUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要添加标签的客户');
+      }
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+
+      this.tagOpen = true;
+
+    },
+
+
+    getPageListTagGroup(){
+      this.queryTagParams.corpId=this.queryParams.corpId
+      allListTagGroup(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+    },
+
+    delUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要移除标签的客户');
+      }
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+      this.tagDelOpen = true;
+
+    },
+
+
+    //搜索的标签
+    hangleChangeTags(){
+
+      this.changeTagDialog.title="搜索的标签"
+      this.changeTagDialog.open=true;
+
+      // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
+      const selectedTagIds = new Set(
+        (this.selectTags || []).map(tagItem => tagItem?.tagId)
+      );
+
+      this.queryTagParams.name=null;
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
+          }
+        }
+      }, 200);
+
+
+    },
+
+    //删除一些选择的标签
+    handleCloseTags(list){
+      const ls = this.selectTags.findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.selectTags.splice(ls, 1);
+        this.selectTags = [...this.selectTags];
+      }
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+    },
+
+    //重新获取页面数据
+    refreshList(){
+      this.getList();
+    },
+
+    //批量设置课程sop
+    setUserCourseSop(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要设置课程SOP的客户');
+      }
+
+      this.$confirm('批量设置客户课节SOP可能会存在重复,确定要批量设置吗?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.setSop.open = true;
+        this.setSop.type = 2;
+      })
+        .catch(() => {
+          // 可以处理用户点击“取消”的逻辑
+        });
+
+    },
+    tagSelection(row){
+
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    addTagCancel() {
+
+      this.tagOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+
+    DelTagCancel() {
+      this.tagDelOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+    addTagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+
+      this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      addTag(this.addTagForm).then(response => {
+
+        this.tagOpen = false;
+        loadingRock.close();
+        this.addTagForm={
+          userIds:[],
+          tagIds:[]
+        };
+
+        this.resultMessage = response.msg;
+        this.resultDialogVisible = true; // 显示弹窗
+        this.resultTitle = '批量添加标签结果';
+
+      }).finally(res=>{
+
+
+        this.getList()
+        loadingRock.close();
+      });
+
+    },
+    tagDelSubmitForm(){
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+      this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      delTag(this.addTagForm).then(response => {
+
+        this.tagDelOpen = false;
+        loadingRock.close();
+        this.addTagForm={
+          userIds:[],
+          tagIds:[]
+        };
+
+        this.resultMessage = response.msg;
+        this.resultDialogVisible = true; // 显示弹窗
+        this.resultTitle = '批量删除标签结果';
+
+      }).finally(res=>{
+
+        this.getList()
+        loadingRock.close();
+      });
+    },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        externalUserId: null,
+        name: null,
+        companyUserId:null,
+        customerId: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,
+        transferStatus:null,
+        status:null,
+        sTime:null,
+        eTime:null,
+        createTime:null,
+        transferTime:null,
+        transferNum:null,
+        lossTime:null,
+        delTime:null,
+        state:null,
+        wayId:null,
+        stageStatus:null,
+        customerName:null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    handleSearchTags(name){
+
+      searchTags({name:name,corpId:this.queryParams.corpId}).then(response => {
+        this.tagGroupList = response.rows;
+      });
+
+    },
+
+    cancelSearchTags(){
+      this.resetSearchQueryTag()
+
+      this.getPageListTagGroup();
+    },
+    notesSubmitForm(){
+
+      if (this.notesOpen.notes==null || this.notesOpen.notes==""){
+        return  this.$message.error("请输入备注内容");
+      }
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      batchUpdateExternalContactNotes({userIds:this.ids,notes:this.notesOpen.notes,type:this.notesOpen.type,nameType:this.notesOpen.nameType}).then(res => {
+
+        this.resultMessage = res.msg;
+        this.resultDialogVisible = true; // 显示弹窗
+        this.resultTitle = '批量修改备注结果';
+
+      }).finally(res=>{
+        this.getList();
+        loadingRock.close();
+        this.notesCancel();
+      })
+
+    },
+
+    //确定选择标签
+    tagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if (this.tagGroupList[i].tag[x].isSelected === true) {
+
+            if (!this.selectTags) {
+              this.selectTags = [];
+            }
+
+            // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+            let tagExists = this.selectTags.some(
+              tag => tag.id === this.tagGroupList[i].tag[x].id
+            );
+
+            // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+            if (!tagExists) {
+              this.selectTags.push(this.tagGroupList[i].tag[x]);
+            }
+          }
+        }
+      }
+      if (!this.selectTags || this.selectTags.length === 0) {
+        return this.$message('请选择标签');
+      }
+
+      this.changeTagDialog.open = false;
+    },
+
+    //取消选择标签
+    tagCancel(){
+      this.changeTagDialog.open = false;
+    },
+    //取消备注
+    notesCancel(){
+      this.notesOpen={
+        open: false,
+        notes: null,
+        type: 1,
+        nameType:3,
+      }
+    },
+
+    resetSearchQueryTag(){
+
+      this.queryTagParams= {
+        pageNum: 1,
+        pageSize: 10,
+        total:0,
+        name:null,
+      };
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue;
+      this.selectTags=[];
+      this.createTime=null;
+      this.queryParams.sTime=null;
+      this.queryParams.eTime=null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.loading=true;
+      this.form.corpId=this.queryParams.corpId
+      addExternalContact(this.form).then(response => {
+        this.msgSuccess("同步成功");
+        this.getList();
+      }).finally(()=>{
+        this.loading=false;
+      });
+
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getExternalContact(id).then(response => {
+        this.form = response.data;
+        if(this.form.remarkMobiles!=null){
+          this.remarkMobiles=JSON.parse(this.form.remarkMobiles)
+        }else{
+          this.remarkMobiles=[]
+        }
+
+        this.open = true;
+        this.title = "修改企业微信客户";
+      });
+    },
+
+    handleAppellation(val){
+      this.callOpen.open=true;
+      this.callOpenFrom.stageStatus=val.stageStatus;
+      this.callOpenFrom.id=val.id;
+    },
+
+    /** 绑定客户操作 */
+    handleUpdateCustomer(row){
+      this.bindCustomer.title="绑定客户"
+      this.bindCustomer.open=true;
+      this.form.id=row.id
+      this.form.externalUserId=row.externalUserId
+      this.form.name=row.name
+    },
+
+    handleUpdateUser(row){
+      this.user.title="绑定客户"
+      this.user.open=true;
+      this.userForm.id=row.id;
+    },
+
+    handleUnBindUserId(val){
+
+      this.$confirm(
+        '确认解绑客户:<span style="color: green;">' + val.name + '' +
+        '</span> 的小程序用户?<br><span style="color: red;">【ps:可能会导致客户无法看课】</span>',
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        return unBindUserId(val.id);
+      }).then(response => {
+        this.getList();
+        this.msgSuccess("解绑成功");
+      }).finally(res=>{
+        this.getList();
+      })
+    },
+
+    bindCustomerId(row){
+
+      console.log("row",row)
+      // this.qwFormCustomer.customerId=row;
+      this.form.customerId=row;
+      this.form.corpId=this.queryParams.corpId;
+      this.msgWarning("绑定中.....同步信息中.....");
+
+      editbindCustomer(this.form).then(res=>{
+        //清空表单
+        this.reset();
+        this.bindCustomer.open = false;
+        this.msgSuccess("绑定成功");
+        this.getList();
+
+      })
+
+    },
+    //设置一个SOP
+    setCourseSOP(row) {
+
+      // 检查 row.miniUserId 是否为 null
+      if (row.miniUserId === null || row.miniUserId === undefined) {
+        return this.$confirm('当前客户【CRM客户详情】中 未绑定小程序客户,请先绑定', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).catch(error => {
+          this.msgWarning("操作取消:", error);
+        });
+      } else {
+        this.chooseCustomerSOP = row;
+        this.setSop.open = true;
+        this.setSop.type=1;
+      }
+    },
+
+    //选择课程SOP
+    // 用于设置 customerCourseForm 和 customerCourseFormLogs 的共同属性
+    setCommonProperties(form, row) {
+      form.qwUserid = this.chooseCustomerSOP.userId;
+      form.companyUserId = this.chooseCustomerSOP.companyUserId;
+      form.externalUserId = this.chooseCustomerSOP.externalUserId;
+      form.customerId = this.chooseCustomerSOP.customerId;
+      form.miniUserId = this.chooseCustomerSOP.miniUserId;
+      form.businessId = row.businessId;
+    },
+
+    bindCourseSop(row,days) {
+
+      if (this.setSop.type==2){
+        this.setSop.open = false;
+        this.loading=true;
+        this.msgWarning("设定中.....同步信息中.....");
+
+        setCustomerCourseSopList({ids:this.ids,fsCourseSopId:row.id,days:days}).then(res=>{
+
+          let msg=" 批量设置成功数【" + res.successNum + "】,<br>"
+
+          if (res.failCRM.length>0){
+            msg+="失败的客户【" + res.failCRM + "】,原因是未绑定CRM客户。<br>"
+          }
+          if (res.failMiNi.length>0){
+            msg+="失败的客户【" + res.failMiNi + "】,原因是CRM中未绑定小程序客户。<br>"
+          }
+          if (res.failCompany.length>0){
+            msg+="失败的客户【" + res.failCompany + "】,原因是客户没有所属成员。<br>"
+          }
+
+
+          return this.$confirm(msg, "提示", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+            dangerouslyUseHTMLString: true // 允许使用HTML标签
+          }).catch(error => {
+            this.msgSuccess("操作完成~");
+          });
+
+        }).finally(()=>{
+          this.loading = false;
+          this.getList();
+        })
+      }else if (this.setSop.type==1){
+
+        // 设置 customerCourseFormLogs 的属性
+        this.setCommonProperties(this.customerCourseFormLogs, row);
+
+        // 设置 customerCourseForm 的属性
+        this.setCommonProperties(this.customerCourseForm, row);
+        this.customerCourseForm.sopId = row.id;
+        this.customerCourseForm.sopType = row.sopType;
+        this.customerCourseForm.setting = row.setting;
+        this.customerCourseForm.days = days;
+
+        // 执行异步操作
+        getCustomerCourseSop(this.customerCourseFormLogs)
+          .then(res => {
+            if (res) {
+              return this.$confirm('当前客户已设置过相同课程课节SOP,确定还要再次设置吗?', "警告", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning"
+              });
+            } else {
+              return Promise.resolve(); // 如果没有设置过,直接执行后续操作
+            }
+          })
+          .then(() => {
+            this.loading = true;
+            this.setSop.open = false;
+            this.msgSuccess("设定中.....同步信息中.....");
+
+            return setCustomerCourseSop(this.customerCourseForm);
+          })
+          .then(() => {
+            this.msgSuccess("设定成功");
+          })
+          .catch(error => {
+            this.msgWarning("操作取消:", error);
+          })
+          .finally(() => {
+            this.loading = false;
+            this.getList();
+          });
+      }
+    },
+    submitCallOpenFrom(){
+
+      this.$refs["callOpenFrom"].validate(valid => {
+        if (valid) {
+
+          if (this.callOpenFrom.id != null && this.callOpenFrom.stageStatus != null) {
+            updateExternalContactCall(this.callOpenFrom).then(res=>{
+              this.$message.success('修改成功');
+              this.callOpen.open=false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            this.form.remarkMobiles=JSON.stringify(this.remarkMobiles)
+            updateExternalContact(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addExternalContact(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 delExternalContact(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+
+    updateTalk(row){
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认批量更改用户信息为非首次交流', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return editTalk(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(() => {});
+    },
+    openRepeat(row){
+      this.repeat.param = {
+        externalUserId: row.externalUserId,
+        corpId: row.corpId,
+        userId: row.userId,
+      };
+      getRepeat(this.repeat.param).then(e => {
+        this.repeat.open = true;
+        this.repeat.loading = false;
+        this.repeat.list = e.data;
+      })
+
+    },
+  }
+};
+</script>
+<style scoped>
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+.tag-box {
+  padding: 8px 12px;
+  border: 1px solid #989797;
+  border-radius: 4px;
+  cursor: pointer;
+  display: inline-block;
+}
+
+.tag-selected {
+  background-color: #00bc98;
+  color: #fff;
+  border-color: #00bc98;
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.feedback-dialog {
+  width: 100%;
+  max-width: 1000px;
+  max-height: 80vh; /* 限制最大高度为视窗高度的 80% */
+  overflow-y: auto; /* 超出时显示垂直滚动条 */
+  padding: 20px;
+  box-sizing: border-box; /* 确保 padding 不影响总宽度 */
+}
+</style>

+ 439 - 0
src/views/qw/externalContactLoss/deptLossIndex.vue

@@ -0,0 +1,439 @@
+deptLossIndex<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
+      <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>
+        <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="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:externalContact:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+    <el-tabs type="card" v-model="queryParams.status" @tab-click="handleClickX">
+      <el-tab-pane label="流失" name="3"></el-tab-pane>
+      <el-tab-pane label="删除" name="4"></el-tab-pane>
+    </el-tabs>
+    <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="userId" width="120px"/>
+      <el-table-column label="企微员工名称" align="center" prop="qwUserName" 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="lossTime" v-if="queryParams.status==3"/>
+       <el-table-column label="删除时间" align="center" prop="delTime" v-if="queryParams.status==4"/>
+      <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="是否绑定CRM" width="110px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            v-if="scope.row.customerId"
+            type="success"
+            size="mini"
+            plain>
+            已绑定
+          </el-button>
+          <el-button
+            v-else
+            type="danger"
+            size="mini"
+            plain>
+            未绑定
+          </el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+          <el-button v-if="scope.row.customerId"
+                     size="mini"
+                     type="text"
+                     icon="el-icon-paperclip"
+                     @click="handleShow(scope.row)"
+          >CRM客户详情</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="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="属于用户账号" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入属于用户账号" />
+        </el-form-item>
+        <el-form-item label="外部联系人账号" prop="externalUserId">
+          <el-input v-model="form.externalUserId" placeholder="请输入外部联系人账号" />
+        </el-form-item>
+        <el-form-item label="名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入名称" />
+        </el-form-item>
+        <el-form-item label="头像" prop="avatar">
+          <el-input v-model="form.avatar" placeholder="请输入头像" />
+        </el-form-item>
+        <el-form-item label="用户类别" prop="type">
+          <el-select v-model="form.type" placeholder="请选择用户类别">
+            <el-option
+              v-for="dict in typeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="性别" prop="gender">
+          <el-input v-model="form.gender" placeholder="请输入性别" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="描述信息" prop="description">
+          <el-input v-model="form.description" placeholder="请输入描述信息" />
+        </el-form-item>
+        <el-form-item label="标签id" prop="tagIds">
+          <el-input v-model="form.tagIds" placeholder="请输入标签id" />
+        </el-form-item>
+        <el-form-item label="备注电话号码" prop="remarkMobiles">
+          <el-input v-model="form.remarkMobiles" placeholder="请输入备注电话号码" />
+        </el-form-item>
+        <el-form-item label="备注企业名称" prop="remarkCorpName">
+          <el-input v-model="form.remarkCorpName" placeholder="请输入备注企业名称" />
+        </el-form-item>
+        <el-form-item label="来源" prop="addWay">
+          <el-input v-model="form.addWay" placeholder="请输入来源" />
+        </el-form-item>
+
+        <el-form-item label="企业id" prop="corpId">
+          <el-input v-model="form.corpId" placeholder="请输入企业id" />
+        </el-form-item>
+        <el-form-item label="公司id" prop="companyId">
+          <el-input v-model="form.companyId" placeholder="请输入公司id" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+
+
+    <el-drawer size="75%" :title="show.title" :visible.sync="show.open">
+      <customer-details  ref="customerDetails" />
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { myDeptExtList,listExternalContact, getExternalContact, delExternalContact, addExternalContact, updateExternalContact, exportExternalContact } from "@/api/qw/externalContact";
+import { listTag, getTag, delTag, addTag, updateTag, exportTag } from "@/api/qw/tag";
+import customerDetails from '@/views/qw/externalContact/customerDetails'
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+export default {
+  name: "deptLossIndex",
+  components:{customerDetails},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      myQwCompanyList:[],
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业微信客户表格数据
+      externalContactList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+      // 用户类别字典
+      typeOptions: [],
+      // 性别字典
+      genderOptions: [],
+      // 来源字典
+      addWayOptions: [],
+      // 查询参数
+      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:"3",
+        transferStatus:null
+      },
+      // 表单参数
+      form: {},
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyList().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              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;
+    });
+    listTag().then(response => {
+      this.tagList = response.rows;
+    });
+    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(){
+           this.getList();
+     },
+    /** 查询企业微信客户列表 */
+    getList() {
+      this.loading = true;
+      myDeptExtList(this.queryParams).then(response => {
+        this.externalContactList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    handleClickX(tab, event) {
+
+       this.queryParams.status=tab.name;
+
+      this.handleQuery();
+    },
+
+
+    /** 查看客户详情 */
+    handleShow(row){
+      this.show.open=true;
+      var that=this;
+      const tab = "visit";
+      setTimeout(() => {
+        that.$refs.customerDetails.getDetails(row.customerId);
+        that.$refs.customerDetails.handleClick(tab);
+
+      }, 200);
+    },
+
+    // 取消按钮
+    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
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue;
+      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();
+     });
+
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getExternalContact(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改企业微信客户";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        this.form.corpId=this.queryParams.corpId;
+        if (valid) {
+          if (this.form.id != null) {
+            updateExternalContact(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addExternalContact(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 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>

+ 524 - 0
src/views/qw/externalContactTransfer/deptTransferIndex.vue

@@ -0,0 +1,524 @@
+<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="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>
+        <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="150px">
+        <template slot-scope="scope">
+          <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>
+        </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="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 { myDeptExtList,transfer,listExternalContact, getExternalContact, delExternalContact, addExternalContact, updateExternalContact, exportExternalContact } from "@/api/qw/externalContact";
+import { listTag, getTag, delTag, addTag, updateTag, exportTag } from "@/api/qw/tag";
+import { qwUserList } from "@/api/qw/user";
+import qwUserSelectOne from '@/views/qw/user/qwUserSelectOne.vue'
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+
+export default {
+  name: "deptTransferIndex",
+  components: { qwUserSelectOne },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      myQwCompanyList:[],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业微信客户表格数据
+      externalContactList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 用户类别字典
+      typeOptions: [],
+      ratingType: [],
+      selectTags:[],
+      // 性别字典
+      genderOptions: [],
+      // 来源字典
+      addWayOptions: [],
+      nickName:null,
+      qwUserList:[],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: 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:0,
+        transferStatus:null
+      },
+      // 表单参数
+      form: {},
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+        userId: [{ required: true, message: '请选择接替员工', trigger: 'blur' }],
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyList().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;
+      myDeptExtList(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
+      };
+      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.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.title = "分配客户";
+
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+
+
+        if (valid) {
+            var form={
+              ids:this.ids,
+              userId:this.form.userId,
+              corpId:this.queryParams.corpId,
+			  content:this.form.content,
+            }
+            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>

+ 318 - 0
src/views/qw/externalContactTransferLog/deptTransferLogIndex.vue

@@ -0,0 +1,318 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <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="companyUserNickName">
+        <el-input
+        style="width:220px"
+          v-model="queryParams.companyUserNickName"
+          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
+            v-for="dict in statusOptions"
+            :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="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:externalContactTransferLog:export']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="snyc"
+          v-hasPermi="['qw:externalContactTransferLog:snyc']"
+        >同步</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="externalContactTransferLogList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+<!--      <el-table-column label="账号" align="center" prop="id" />-->
+      <el-table-column label="原员工" align="center" prop="handoverQwUserName" />
+      <el-table-column label="客户名称" align="center" prop="name" />
+      <el-table-column label="接替员工" align="center" prop="companyUserNickName" />
+      <el-table-column label="员工部门" align="center" prop="deptName" />
+      <el-table-column label="转接时间" align="center" prop="createTime" />
+      <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>
+
+    <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="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="企业id" prop="corpId">
+          <el-input v-model="form.corpId" placeholder="请输入企业id" />
+        </el-form-item>
+        <el-form-item label="公司id" prop="companyId">
+          <el-input v-model="form.companyId" placeholder="请输入公司id" />
+        </el-form-item>
+        <el-form-item label="员工id" prop="companyUserId">
+          <el-input v-model="form.companyUserId" placeholder="请输入员工id" />
+        </el-form-item>
+        <el-form-item label="企微外部联系人id" prop="externalUserId">
+          <el-input v-model="form.externalUserId" placeholder="请输入企微外部联系人id" />
+        </el-form-item>
+        <el-form-item label="客户id" prop="customerId">
+          <el-input v-model="form.customerId" placeholder="请输入客户id" />
+        </el-form-item>
+        <el-form-item label="外部联系人id" prop="externalContactId">
+          <el-input v-model="form.externalContactId" placeholder="请输入外部联系人id" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="form.status" placeholder="请选择状态">
+            <el-option
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            ></el-option>
+          </el-select>
+        </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 { listTransferLogDeptList,syncTransferLog,listExternalContactTransferLog, getExternalContactTransferLog, delExternalContactTransferLog, addExternalContactTransferLog, updateExternalContactTransferLog, exportExternalContactTransferLog } from "@/api/qw/externalContactTransferLog";
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+export default {
+  name: "deptTransferLogIndex",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 转接记录表格数据
+      externalContactTransferLogList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      myQwCompanyList:[],
+      // 状态字典
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        corpId: null,
+        companyId: null,
+        companyUserId: null,
+        externalUserId: null,
+        customerId: null,
+        externalContactId: null,
+        status: null,
+        companyUserNickName:null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyList().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              this.getList();
+            }
+    });
+    this.getDicts("sys_qw_transfer_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    updateCorpId(){
+           this.getList();
+     },
+    /** 查询转接记录列表 */
+    getList() {
+      this.loading = true;
+      listTransferLogDeptList(this.queryParams).then(response => {
+        this.externalContactTransferLogList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    snyc(){
+      syncTransferLog(this.queryParams.corpId).then(response => {
+        this.msgSuccess("同步成功");
+        this.getList();
+      });
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        corpId: null,
+        companyId: null,
+        companyUserId: null,
+        externalUserId: null,
+        customerId: null,
+        externalContactId: null,
+        status: null,
+        createTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      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
+      getExternalContactTransferLog(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改转接记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateExternalContactTransferLog(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addExternalContactTransferLog(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 delExternalContactTransferLog(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有转接记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportExternalContactTransferLog(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 474 - 0
src/views/qw/externalContactUnassigned/deptUnassignedIndex.vue

@@ -0,0 +1,474 @@
+
+<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-input
+          v-model="queryParams.qwUserName"
+          placeholder="请输入原所属员工名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </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>
+      <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 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>
+        </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"
+      @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-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,
+  myDeptExtList
+} from "../../../api/qw/externalContact";
+import { listTag, getTag, delTag, addTag, updateTag, exportTag } from "@/api/qw/tag";
+// import { qwUserList } from "@/api/qw/user";
+import qwUserSelectOne from "@/views/qw/user/qwUserSelectOne.vue";
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+
+export default {
+  name: "deptUnassignedIndex",
+  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:[],
+      // 查询参数
+      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: {
+      },
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+        userId:[   { required: true, message: "接替员工不能为空", trigger: "blur" }]
+
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyList().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: {
+    updateCorpId(){
+      listTag({corpId:this.queryParams.corpId}).then(response => {
+        this.tagList = response.rows;
+      });
+      this.getList();
+    },
+    getList() {
+      this.loading = true;
+      myDeptExtList(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
+      };
+      this.resetForm("form");
+    },
+
+    selectUser(row){
+      this.form.userId=row.id
+      // console.log("row",row)
+      this.nickName=row.nickName
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      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();
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要分配的客户');
+      }
+      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={
+              ids:this.ids,
+              userId:this.form.userId,
+              corpId:this.queryParams.corpId,
+            }
+            resignedTransfer(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>

+ 1278 - 0
src/views/qw/friendWelcome/deptFriendWelcome.vue

@@ -0,0 +1,1278 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+      <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="使用的成员" >
+        <el-select v-model="queryParams.qwUserIds" filterable  clearable placeholder="公司员工"   size="small">
+          <el-option
+             v-for="dict in companyUserList"
+             :key="dict.qwUserId"
+             :label="dict.nickName"
+             :value="dict.qwUserId">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否开启分时段" prop="isDayparting">
+        <el-select v-model="queryParams.isDayparting" placeholder="请选择" clearable size="small">
+          <el-option v-for="dict in allowSelectOptions" :key="dict.dictValue" :label="dict.dictLabel"  :value="dict.dictValue"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createdTime">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.createdTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择创建时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="更新时间" prop="updateTieme">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.updateTieme"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择更新时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="是否发送欢迎语" prop="isSendMsg">
+        <el-select v-model="queryParams.isSendMsg" placeholder="请选择" clearable size="small" >
+          <el-option v-for="dict in allowSelectOptions" :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-button
+          type="primary"
+          plain
+          size="mini"
+          icon="el-icon-plus"
+          @click="handleAdd"
+          v-hasPermi="['qw:friendWelcome:add']"
+        >新增</el-button>
+      </el-form-item>
+    </el-form>
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+
+    <el-table v-loading="loading" :data="friendWelcomeList" @selection-change="handleSelectionChange" border>
+      <el-table-column label="消息内容" align="left" prop="welcomeText"  width="400px" >
+        <template slot-scope="scope">
+          <span style="color:rgb(19, 154, 50);" v-if="scope.row.isDayparting==='1'">[共 {{JSON.parse(scope.row.daypartingItemlist).length+1}} 时段]</span>
+          <span style="color:rgb(19, 154, 50);" v-else >[默认时段]</span>
+          <el-tooltip class="item" effect="dark" :content="scope.row.welcomeText" placement="top">
+            <div style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; text-overflow: ellipsis;">
+              <span>{{ scope.row.welcomeText }}</span>
+            </div>
+          </el-tooltip>
+        </template>
+      </el-table-column>
+      <el-table-column label="使用成员" align="center" prop="qwUserIds">
+      <template slot-scope="scope">
+          <div v-for="id in JSON.parse(scope.row.qwUserIds)" :key="id" style="display: inline;" class="text-container">
+            <el-tag type="success" v-for="list in companyUserList" :key="list.qwUserId" style="margin: 3px;" v-if="list.id==id">{{list.qwUserName}}</el-tag>
+          </div>
+      </template>
+      </el-table-column>
+      <el-table-column label="是否开启分时段" align="center" prop="isDayparting">
+        <template slot-scope="scope">
+          <dict-tag :options="allowSelectOptions" :value="scope.row.isDayparting"></dict-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否发送欢迎语" align="center" prop="isSendMsg" >
+        <template slot-scope="scope">
+          <dict-tag :options="allowSelectOptions" :value="scope.row.isSendMsg"></dict-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="更新时间" align="center" prop="updateTime" width="180"/>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:friendWelcome:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:friendWelcome:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改好友欢迎语对话框 -->
+    <el-dialog :title="title" :visible.sync="open" v-loading="loading" width="1700px" append-to-body>
+      <div style="width: 1130px" class="app-container">
+        <div>
+          <span style="font-size: 15px">基础信息</span>
+          <el-divider></el-divider>
+          <el-alert
+            title="同一个销售的同一个企业微信账号,如果创建了多条记录,则以最新创建的那一条为准!!"
+            type="info"
+            :closable="false"
+            show-icon>
+          </el-alert>
+        </div>
+        <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+
+          <el-form-item label="选择使用成员:" prop="qwUserIds" style="margin-top: 2%">
+            <div>
+              <el-button
+                size="medium"
+                icon="el-icon-circle-plus-outline"
+                plain
+                @click="handlelistUser">请选择使用成员</el-button>
+            </div>
+            <div>
+              <el-tag
+                style="margin-left: 5px"
+                size="medium"
+                :key="list.id"
+                v-for="list in userSelectList"
+                closable
+                :disable-transitions="false"
+                @close="handleClosegroupUser(list)">
+                {{list.qwUserName}}({{list.nickName}})
+              </el-tag>
+            </div>
+          </el-form-item>
+          <el-form-item label="是否发送欢迎语">
+            <el-switch
+              v-model="form.isSendMsg"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              active-value="1"
+              inactive-value="2">
+            </el-switch>
+            <span v-if="form.isSendMsg == '1'" style="margin-left: 10px;color: #13ce66">允许</span>
+            <span v-if="form.isSendMsg == '2'" style="margin-left: 10px;color: #ff4949">不允许</span>
+
+          </el-form-item>
+          <div>
+            <span style="font-size: 15px">发送欢迎语</span>
+            <el-divider></el-divider>
+          </div>
+          <el-form-item label="默认欢迎语:" prop="welcomeText">
+              <el-input v-model="form.welcomeText" type="textarea"  :rows="12" maxlength="1300" show-word-limit placeholder="请输入消息内容"/>
+            <!-- 附件和链接列表 -->
+            <el-row>
+              <el-col>
+                <div v-for="(item, index) in form.attachments" :key="index" style="background-color: #f5f7fa;padding: 5px;border: 1px solid  #d9d9d9;">
+                  <div slot="header" style="display: flex;justify-content: space-between;align-items: center; ">
+                    <div style="flex: 1;">
+                    <span v-if="item.msgtype === 'image'">【图片】: {{ item.image.pic_url }}</span>
+                    <span v-if="item.msgtype === 'link'">【链接】: {{ item.link.title }}-{{item.link.desc}}</span>
+                    <span v-if="item.msgtype === 'miniprogram'">【小程序】: {{ item.miniprogram.title }}</span>
+                    </div>
+                    <div style="  display: flex;gap: 10px;">
+                      <el-button
+                        size="mini"
+                        type="text"
+                        icon="el-icon-edit"
+                        style="float: left;"
+                        @click="editFileItem(item,index,-1)"
+                      >修改</el-button>
+                      <el-button
+                        size="mini"
+                        type="text"
+                        icon="el-icon-delete"
+                        style="float: right;"
+                        @click="removeFileItem(item,index,-1)"
+                      >删除</el-button>
+                  </div>
+                  </div>
+                </div>
+              </el-col>
+            </el-row>
+
+            <el-dropdown @command="(command) => handleCommand(command, -1)" trigger="click" placement="top-start">
+              <el-dropdown-menu slot="dropdown" style="width: 120px;">
+                <el-dropdown-item command="image">
+                  <i class="el-icon-picture" style="margin-right: 10px;"></i>图片
+                </el-dropdown-item>
+                <el-dropdown-item command="link">
+                  <i class="el-icon-link" style="margin-right: 10px;"></i>链接
+                </el-dropdown-item>
+                <el-dropdown-item command="miniprogram">
+                  <i class="el-icon-link" style="margin-right: 10px;"></i>小程序
+                </el-dropdown-item>
+              </el-dropdown-menu>
+
+              <span class="el-dropdown-link">
+                <el-link icon="el-icon-paperclip" type="text" style="color: rgb(24, 144, 255)">
+                  添加附件(最多9个)
+                </el-link>
+              </span>
+            </el-dropdown>
+
+            </el-form-item>
+
+          <el-form-item label="分时段欢迎语">
+            <el-switch
+              v-model="form.isDayparting"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              active-value="1"
+              inactive-value="2">
+            </el-switch>
+            <span v-if="form.isDayparting == '1'" style="margin-left: 10px;color: #13ce66">已启用</span>
+            <span v-if="form.isDayparting == '2'" style="margin-left: 10px;color: #ff4949">已禁用</span>
+          </el-form-item>
+
+          <el-form-item v-if="form.isDayparting == '1'" >
+            <div style="background-color:#ecf8fe;width: 100%;border: 1px solid #dcdfe6">
+              <span style="margin-left:20px;font-size: 15px;display: block" >注意:1、员工上下班不同时间段可设置不同欢迎语;</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >2、分时段之外的时间将发送已允许的默认欢迎语。</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >3、不设置分时段欢迎语则使用已允许的默认欢迎语</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >4、若员工没有设置过欢迎语则不会发送</span>
+            </div>
+          </el-form-item>
+          <el-form-item v-if="form.isDayparting == '2'">
+            <div style="background-color:#ecf8fe;width: 100%;border: 1px solid #dcdfe6">
+              <span style="margin-left:20px;font-size: 15px;display: block" >注意:1、新建欢迎语最多可发送1条文字消息和9个附件;</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >2、文字消息和附件不能同时为空,当两者均填写时用户会收到多条消息;</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >3、欢迎语将在客户加为好友后20秒内下发,因网络延迟可能造成发送不成功</span>
+            </div>
+          </el-form-item>
+          <div  v-if="form.isDayparting == '1'"  v-for="(item, index) in form.daypartingItemlist"    :key="index" >
+            <el-form-item :label="`时段 ${index + 1}:`">
+                <el-row>
+                  <el-col style="width: 965px">
+                    <div style="background-color: #fbfbfb;padding: 10px;  border: 1px solid #e6e6e6; margin-bottom: 20px;">
+                          <el-form ref="friendWelcomeItemForm"  :rules="itemRules" :model="item">
+                          <div style="display: flex; gap: 10px;">
+                            <el-form-item label="发起时间:" prop="week" style="flex: 8;">
+                              <el-select v-model="item.week" remote multiple placeholder="请选择" filterable style="width: 580px">
+                                <el-option
+                                  v-for="dict in weekOptions"
+                                  :key="dict.value"
+                                  :label="dict.label"
+                                  :value="dict.value">
+                                </el-option>
+                              </el-select>
+                            </el-form-item>
+                            <el-form-item prop="startTime" style="flex: 1;">
+                              <el-time-select style="width: 120px;"
+                                              placeholder="起始时间"
+                                              v-model="item.startTime"
+                                              :picker-options="{
+                                            start: '00:00',
+                                            step: '00:15',
+                                            end: '24:00'
+                                          }">
+                              </el-time-select>
+                            </el-form-item>
+                            <el-form-item prop="endTime" style="flex: 1;">
+                              <el-time-select style="width: 120px;"
+                                              placeholder="结束时间"
+                                              v-model="item.endTime"
+                                              :picker-options="{
+                                            start: '00:00',
+                                            step: '00:15',
+                                            end: '24:00',
+                                            minTime: item.startTime
+                                          }">
+                              </el-time-select>
+                            </el-form-item>
+                          </div>
+
+                        <el-form-item style="margin-top: 20px" prop="welcomeText">
+                          <el-input v-model="item.welcomeText" type="textarea" :rows="12" maxlength="1300" show-word-limit placeholder="请输入消息内容"/>
+                          <!-- 附件和链接列表 -->
+                          <el-row>
+                            <el-col>
+                              <div v-for="(attachment, attachIndex) in item.attachments" :key="attachIndex" style="background-color: #f5f7fa;padding: 5px;border: 1px solid  #d9d9d9;">
+                                <div slot="header" style="  display: flex;justify-content: space-between;align-items: center; ">
+                                  <div style="flex: 1;">
+                                    <span v-if="attachment.msgtype === 'image'">【图片】: {{ attachment.image.pic_url }}</span>
+                                    <span v-if="attachment.msgtype === 'link'">【链接】: {{ attachment.link.title }}-{{attachment.link.desc}}</span>
+                                    <span v-if="attachment.msgtype === 'miniprogram'">【小程序】: {{ attachment.miniprogram.title }}</span>
+                                  </div>
+                                  <div style="  display: flex;gap: 10px;">
+                                    <el-button
+                                      size="mini"
+                                      type="text"
+                                      icon="el-icon-edit"
+                                      style="float: left;"
+                                      @click="editFileItem(attachment,attachIndex,index)"
+                                    >修改</el-button>
+                                    <el-button
+                                      size="mini"
+                                      type="text"
+                                      icon="el-icon-delete"
+                                      style="float: right;"
+                                      @click="removeFileItem(attachment,attachIndex,index)"
+                                    >删除</el-button>
+                                  </div>
+                                </div>
+                              </div>
+                            </el-col>
+                          </el-row>
+
+                          <el-dropdown @command="(command) => handleCommand(command, index)" trigger="click" placement="top-start">
+                            <el-dropdown-menu slot="dropdown" style="width: 120px;">
+                              <el-dropdown-item command="image">
+                                <i class="el-icon-picture" style="margin-right: 10px;"></i>图片
+                              </el-dropdown-item>
+                              <el-dropdown-item command="link">
+                                <i class="el-icon-link" style="margin-right: 10px;"></i>链接
+                              </el-dropdown-item>
+                              <el-dropdown-item command="miniprogram">
+                                <i class="el-icon-link" style="margin-right: 10px;"></i>小程序
+                              </el-dropdown-item>
+                            </el-dropdown-menu>
+
+                            <span class="el-dropdown-link">
+                            <el-link icon="el-icon-paperclip" type="text" style="color: rgb(24, 144, 255)">
+                              添加附件(最多9个)
+                            </el-link>
+                            </span>
+                          </el-dropdown>
+                        </el-form-item>
+                      </el-form>
+                    </div>
+                  </el-col>
+                  <el-col style="width: 15px;">
+                    <el-link v-if="form.daypartingItemlist.length>1" icon="el-icon-delete-solid" @click="delItemList(index)" type="text" style="color: rgb(24, 144, 255);margin-top: 350px" ></el-link>
+                  </el-col>
+                </el-row>
+            </el-form-item>
+          </div>
+          <div  v-if="form.isDayparting == '1'" style="margin-left: 10%">
+            <el-link type="primary" class="el-icon-plus" :underline="false" @click='addItemList()'>添加其他分时段欢迎语</el-link>
+          </div>
+
+        </el-form>
+      </div>
+
+      <div slot="footer" class="dialog-footer" style="text-align: center">
+        <el-button type="primary"  @click="submitForm">确定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 选择成员账号弹窗   -->
+    <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="1600px"  append-to-body>
+      <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
+    </el-dialog>
+
+    <el-dialog :title="welcomeItem.title" :visible.sync="welcomeItem.open" style="width: 1300px;height: 100%" append-to-body>
+      <el-form ref="fileFrom" :model="fileFrom" :rules="fuleRules" label-width="110px">
+        <div v-if="welcomeItem.type==='image'">
+          <el-form-item label="图片:" prop="imagePicUrl">
+            <ImageUpload v-model="fileFrom.imagePicUrl"  type="image" :num="10" :width="150" :height="150"  disabled/>
+          </el-form-item>
+        </div>
+        <div v-if="welcomeItem.type==='link'">
+
+          <el-form-item label="选择课程">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+              <el-option
+                v-for="dict in courseList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="图文标题:" prop="linkTitle">
+            <el-input v-model="fileFrom.linkTitle" :rows="2" maxlength="42"  show-word-limit placeholder="请输入图文消息标题,最长为42字" />
+          </el-form-item>
+          <el-form-item label="图文封面:" prop="linkPicUrl">
+            <ImageUpload v-model="fileFrom.linkPicUrl"  type="image" :num="10" :width="150" :height="150" />
+          </el-form-item>
+          <el-form-item label="图文的描述:" prop="linkDesc">
+            <el-input v-model="fileFrom.linkDesc" :rows="4" maxlength="170" show-word-limit type="textarea" placeholder="请输入内容,,最长为170字" />
+          </el-form-item>
+          <div v-if="fileFrom.videoId==null" style="margin-top: 1%">
+            <el-form-item label="图文链接:"  label-width="100px" >
+              <el-input v-model="fileFrom.linkUrl" placeholder="请输入链接地址" style="width: 90%;"/>
+            </el-form-item>
+          </div>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="图文链接:"  label-width="100px" >
+              <el-tag type="warning" v-model="fileFrom.linkUrl='待生成'">选择的课程小节 即为卡片链接地址</el-tag>
+            </el-form-item>
+          </div>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="课节过期时间" style="margin-top: 1%" required label-width="110px">
+              <el-row>
+                <el-input-number  v-model="fileFrom.expiresDays"  :min="1" :max="9999" ></el-input-number>
+                (天)
+              </el-row>
+              <el-row>
+                <span class="tip">默认为30天</span>
+              </el-row>
+            </el-form-item>
+          </div>
+<!--          <el-form-item label="图文链接:" prop="linkUrl">-->
+<!--            <el-input v-model="fileFrom.linkUrl" :rows="2"  placeholder="选择了课程小节会自动设置地址" />-->
+<!--          </el-form-item>-->
+        </div>
+        <div v-if="welcomeItem.type==='miniprogram'">
+
+          <el-form-item label="选择课程">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+              <el-option
+                v-for="dict in courseList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="小程序标题:" prop="miniprogramTitle">
+            <el-input v-model="fileFrom.miniprogramTitle" :rows="2" maxlength="64" placeholder="请输入小程序消息标题,最长为64字节" @input="checkByteLength(fileFrom)" />
+          </el-form-item>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="小程序链接:"  label-width="100px" >
+              <el-tag type="warning" v-model="fileFrom.miniprogramPage='待生成'">选择的课程小节 即为卡片小程序链接地址</el-tag>
+            </el-form-item>
+          </div>
+          <el-form-item label="appid" prop="miniprogramAppid" v-show="false" >
+            <el-input v-model="fileFrom.miniprogramAppid='wx73f85f8d62769119' " disabled />
+          </el-form-item>
+
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="课节过期时间" style="margin-top: 1%" required label-width="110px">
+              <el-row>
+                <el-input-number  v-model="fileFrom.expiresDays"  :min="1" :max="9999" ></el-input-number>
+                (天)
+              </el-row>
+              <el-row>
+                <span class="tip">默认为30天</span>
+              </el-row>
+            </el-form-item>
+          </div>
+          <!--          <el-form-item label="图文链接:" prop="linkUrl">-->
+          <!--            <el-input v-model="fileFrom.linkUrl" :rows="2"  placeholder="选择了课程小节会自动设置地址" />-->
+          <!--          </el-form-item>-->
+        </div>
+      </el-form>
+      <div slot="footer" class="dialog-footer" style="text-align: center">
+        <el-button type="primary" @click="confirmUpload">确定</el-button>
+        <el-button type="primary" @click="cancelUpload">取消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import { deptListFriendWelcome,listFriendWelcome, getFriendWelcome, delFriendWelcome, addFriendWelcome, updateFriendWelcome, exportFriendWelcome } from "@/api/qw/friendWelcome";
+import qwUserList from '@/views/qw/user/qwUserList.vue'
+import ImageUploadWeclome from '@/views/qw/friendWelcome/ImageUploadWeclome.vue'
+import ImageUpload from '@/views/qw/material/ImageUpload.vue'
+import { getQwAllUserList } from '@/api/company/companyUser'
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+import {courseList, videoList} from "@/api/qw/sop";
+export default {
+  name: "deptFriendWelcome",
+  components: { ImageUpload, qwUserList,ImageUploadWeclome},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      myQwCompanyList:[],
+      //选择成员列表
+      listUser:{
+        title:"",
+        open:false
+      },
+      //选择成员列表
+      userSelectList:[],
+      fileFrom:{
+        imagePicUrl:null,
+        linkTitle:null,
+        linkPicUrl:null,
+        linkDesc:null,
+        linkUrl:null,
+        videoId:null,
+        courseId:null,
+        expiresDays:30,
+        miniprogramTitle:null,
+        miniprogramPage:null,
+        miniprogramPicUrl:null,
+        miniprogramAppid:null,
+      },
+      courseList:[],
+      videoList:[],
+      fuleRules:{
+        imagePicUrl:[ { required: true, message: "图片不能为空", trigger: "submit" }],
+        linkTitle:[ { required: true, message: "图文标题不能为空", trigger: "submit" }],
+        linkUrl:[ { required: true, message: "图文链接不能为空", trigger: "submit" }],
+        miniprogramTitle:[ { required: true, message: "图文链接不能为空", trigger: "submit" }],
+      },
+
+
+      weekOptions: [{
+        value: 1,
+        label: '星期一'
+      }, {
+        value: 2,
+        label: '星期二'
+      }, {
+        value: 3,
+        label: '星期三'
+      }, {
+        value: 4,
+        label: '星期四'
+      }, {
+        value: 5,
+        label: '星期五'
+      }
+        , {
+          value: 6,
+          label: '星期六'
+        }
+        , {
+          value: 7,
+          label: '星期天'
+        }],
+
+      welcomeItem:{
+        open: false,
+        title: '',
+        type: '',
+        index: -1,
+        itemIndex: -1
+      },
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      //是否
+      allowSelectOptions:[],
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 好友欢迎语表格数据
+      friendWelcomeList: [],
+      //账号列表
+      companyUserList:[],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        qwUserIds: [],
+        companyId: null,
+        welcomeText: null,
+        isDayparting: null,
+        createTime: null,
+        updateTime: null,
+        isSendMsg: null,
+        corpId: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        qwUserIds: [
+          { required: true, message: "发送企业群发消息的成员账号不能为空", trigger: "submit" }
+        ],
+        welcomeText:[
+          { required: true, message: "消息内容不能为空噢", trigger: "submit" }
+        ],
+
+      },
+      itemRules: {
+        week: [
+          { required: true, message: '请选择发起时间的星期', trigger: 'submit' }
+        ],
+        startTime: [
+          { required: true, message: '请选择开始时间', trigger: 'submit' },
+        ],
+        endTime: [
+          { required: true, message: '请选择结束时间', trigger: 'submit' },
+
+        ],
+        welcomeText: [
+          { required: true, message: '消息内容不能为空噢', trigger: 'submit' }
+        ]
+      }
+
+    };
+  },
+  created() {
+    //账号列表
+
+
+    //是否允许发送
+    this.getDicts("sys_qw_allow_select").then(response => {
+      this.allowSelectOptions = response.data;
+    });
+    courseList().then(response => {
+      this.courseList = response.list;
+    });
+    getMyQwCompanyList().then(response => {
+
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              getQwAllUserList(this.myQwCompanyList[0].dictValue).then(response => {
+                this.companyUserList = response.data;
+              });
+              this.getList();
+            }
+    });
+  },
+  watch:{
+    userSelectList(newList) {
+      this.form.qwUserIds =newList.map(item =>item.id);
+    }
+  },
+  methods: {
+    updateCorpId(){
+        this.getList();
+        getQwAllUserList(this.queryParams.corpId).then(response => {
+        this.companyUserList = response.data;
+      });
+     },
+    /** 查询好友欢迎语列表 */
+    getList() {
+      this.loading = true;
+
+      deptListFriendWelcome(this.queryParams).then(response => {
+
+        // 将处理后的数据赋值给 friendWelcomeList
+        this.friendWelcomeList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // // 检查字节长度
+    checkByteLength(fileFrom) {
+      const text = fileFrom.miniprogramTitle;
+      const byteLength = this.getByteLength(text); // 获取当前字节数
+
+      // 如果字节数超过64,截断输入内容
+      if (byteLength > 64) {
+        this.$set(fileFrom, 'miniprogramTitle', this.truncateTextByByteLength(text,64));
+      }
+    },
+
+    // 计算字符串的字节数
+    getByteLength(text) {
+      return new Blob([text]).size; // 使用 Blob 计算字节数
+    },
+
+    // 根据字节数截断字符串
+    truncateTextByByteLength(text, maxByteLength) {
+      let byteLength = 0;
+      let result = "";
+
+      for (let i = 0; i < text.length; i++) {
+        const char = text[i];
+        const charByteLength = this.getByteLength(char); // 获取当前字符的字节数
+
+        // 如果加上当前字符的字节数后不超过限制,则添加到结果中
+        if (byteLength + charByteLength <= maxByteLength) {
+          result += char;
+          byteLength += charByteLength;
+        } else {
+          break; // 超过限制时停止
+        }
+      }
+
+      return result;
+    },
+
+    //选择群发的企业成员账号
+    handlelistUser(){
+      setTimeout(() => {
+        this.$refs.QwUserList.getDetails(this.queryParams.corpId);
+      }, 1);
+      this.listUser.title="选择企业成员"
+      this.listUser.open=true;
+    },
+    //选择的成员账号列表
+    selectUserList(list){
+
+      this.listUser.open=false;
+
+      // 3. 遍历要添加的 list,逐条判断是否存在重复
+      list.forEach(newItem => {
+        // some() 判断是否存在相同 id
+        const isExist = this.userSelectList.some(oldItem => oldItem.id === newItem.id);
+        if (!isExist) {
+          // 不存在重复的,才添加
+          this.userSelectList.push(newItem);
+        }
+      });
+      // //用于显示
+      // this.userSelectList=list;
+
+    },
+    //删除一些选择了的账号
+    handleClosegroupUser(list){
+
+      // 假设 list 对象具有一个 id 属性
+      const index = this.userSelectList.findIndex(t => t.id === list.id);
+      if (index !== -1) {
+        this.userSelectList.splice(index,1);
+      }
+    },
+    //附件选择
+    handleCommand(command,itemIndex){
+
+      if (this.form.attachments.length >=9 && itemIndex===-1) {
+        return this.$message.error('附件数量已达上限,无法添加更多附件');
+      }
+
+      if (this.isDayparting==='1' && this.form.daypartingItemlist[itemIndex].attachments.length>=9){
+        return this.$message.error('附件数量已达上限,无法添加更多附件');
+      }
+
+      this.welcomeItem = {
+        open: true,
+        title: this.getTitleByCommand(command),
+        type: command,
+        index: itemIndex === -1 ? this.form.attachments.length : this.form.daypartingItemlist[itemIndex].attachments.length,
+        itemIndex
+      };
+    },
+
+    getTitleByCommand(command) {
+      switch (command) {
+        case 'image':
+          return '添加图片';
+        case 'link':
+          return '添加链接';
+        case 'miniprogram':
+          return '添加小程序';
+      }
+    },
+
+
+    courseChange(fileFrom,index,itemIndex){
+
+      // 清空 videoId 选择
+      this.$set(fileFrom, 'videoId', null);
+      // 清空 videoList
+      this.videoList = [];
+
+      if (fileFrom.courseId != null) {
+        // 查找选中的课程对应的 label 和 dictImgUrl
+        const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === fileFrom.courseId);
+
+        if (selectedCourse) {
+          // 设置 linkTitle 和 linkImageUrl
+          this.$set(fileFrom, 'linkTitle', selectedCourse.dictLabel);
+          this.$set(fileFrom, 'linkPicUrl', selectedCourse.dictImgUrl);
+        }
+
+
+        // 获取新的 videoList
+        videoList(fileFrom.courseId).then(response => {
+          this.videoList = response.list;
+        });
+
+      }
+      //
+      // // 更新对应的数据层级
+      // if (itemIndex === -1) {
+      //   // 更新 form.attachments
+      //   this.$set(this.form.attachments, index, {
+      //     ...this.form.attachments[index],
+      //     courseId: fileFrom.courseId,
+      //     videoId: null, // 因为已清空
+      //     title: fileFrom.linkTitle,
+      //     picurl: fileFrom.linkPicUrl
+      //   });
+      // } else {
+      //
+      //   this.$set(this.form.daypartingItemlist[itemIndex].attachments, index, {
+      //     ...this.form.daypartingItemlist[itemIndex].attachments[index],
+      //     courseId: fileFrom.courseId,
+      //     videoId: null, // 因为已清空
+      //     title: fileFrom.linkTitle,
+      //     picurl: fileFrom.linkPicUrl
+      //   });
+      // }
+    },
+    videoIdChange(fileFrom,index, itemIndex,type){
+      //选择了课程小节则 默认绑上
+      if (fileFrom.videoId != null) {
+        // 根据 videoId 获取相关信息(假设有相关的 API 调用)
+        let  selectedVideo = this.videoList.find(course => parseInt(course.dictValue) === fileFrom.videoId);
+        if (selectedVideo && type==='link') {
+          this.$set(fileFrom, 'linkDesc', selectedVideo.dictLabel);
+          this.$set(fileFrom, 'expiresDays', 30);
+        }
+        if (selectedVideo && type==='miniprogram') {
+          this.$set(fileFrom, 'miniprogramTitle', this.truncateTextByByteLength(selectedVideo.dictLabel,64));
+          this.$set(fileFrom, 'expiresDays', 30);
+        }
+
+      }
+
+      // // 更新对应的数据层级
+      // if (itemIndex === -1) {
+      //   // 更新 form.attachments
+      //   this.$set(this.form.attachments, index, {
+      //     ...this.form.attachments[index],
+      //     videoId: fileFrom.videoId,
+      //     desc: fileFrom.linkDesc,
+      //   });
+      // } else {
+      //   // 更新 form.daypartingItemlist[itemIndex].attachments
+      //   this.$set(this.form.daypartingItemlist[itemIndex].attachments, index, {
+      //     ...this.form.daypartingItemlist[itemIndex].attachments[index],
+      //     videoId: fileFrom.videoId,
+      //     desc: fileFrom.linkDesc,
+      //   });
+      //
+      // }
+
+    },
+    //修改附件
+    editFileItem(item, index, itemIndex){
+
+      this.welcomeItem = {
+        open: true,
+        title: this.getEditTitleByMsgType(item.msgtype),
+        type: item.msgtype,
+        index,
+        itemIndex
+      };
+      if (item.msgtype === 'image') {
+        this.fileFrom.imagePicUrl = item.image.pic_url;
+      } else if (item.msgtype === 'link') {
+        this.fileFrom.linkTitle = item.link.title;
+        this.fileFrom.linkPicUrl = item.link.picurl;
+        this.fileFrom.linkDesc = item.link.desc;
+        this.fileFrom.linkUrl = item.link.url;
+        this.fileFrom.videoId = item.link.videoId;
+        this.fileFrom.courseId = item.link.courseId;
+        this.fileFrom.expiresDays = item.link.expiresDays;
+
+        videoList(item.link.courseId).then(response => {
+          this.videoList = response.list;
+        });
+
+
+      }else if (item.msgtype === 'miniprogram') {
+        this.fileFrom.miniprogramAppid = 'wx73f85f8d62769119';
+        this.fileFrom.miniprogramTitle = item.miniprogram.title;
+        this.fileFrom.miniprogramPicUrl = "待生成";
+        this.fileFrom.miniprogramPage = "待生成";
+        this.fileFrom.videoId = item.miniprogram.videoId;
+        this.fileFrom.courseId = item.miniprogram.courseId;
+        this.fileFrom.expiresDays = item.miniprogram.expiresDays;
+
+        videoList(item.miniprogram.courseId).then(response => {
+          this.videoList = response.list;
+        });
+
+      }
+
+
+    },
+
+
+
+    getEditTitleByMsgType(msgType) {
+      switch (msgType) {
+        case 'image':
+          return '编辑图片';
+        case 'link':
+          return '编辑链接';
+        case 'miniprogram':
+          return '编辑小程序';
+      }
+    },
+
+    //删除附件
+    removeFileItem(data,index, itemIndex) {
+
+      if (itemIndex === -1) {
+        this.form.attachments.splice(index, 1);
+      } else {
+        this.form.daypartingItemlist[itemIndex].attachments.splice(index, 1);
+      }
+    },
+
+    //添加分时段欢迎语
+    addItemList(){
+      this.form.daypartingItemlist.push({welcomeText:null,attachments:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null})
+    },
+
+
+    //删除某一个分时段欢迎语
+    delItemList(index){
+      this.form.daypartingItemlist.splice(index,1)
+    },
+
+    //提交附件
+    confirmUpload(fileFrom) {
+
+      const { type, index, itemIndex } = this.welcomeItem;
+      let attachment = {};
+      if (type === 'image') {
+        attachment = {
+          msgtype: 'image',
+          image: {
+            pic_url: this.fileFrom.imagePicUrl
+          }
+        };
+      } else if (type === 'link') {
+        attachment = {
+          msgtype: 'link',
+          link: {
+            title: this.fileFrom.linkTitle,
+            picurl: this.fileFrom.linkPicUrl,
+            desc: this.fileFrom.linkDesc,
+            url: this.fileFrom.linkUrl,
+            courseId:this.fileFrom.courseId,
+            videoId:this.fileFrom.videoId,
+            expiresDays:this.fileFrom.expiresDays,
+          }
+        };
+      }else if (type==='miniprogram'){
+        attachment = {
+          msgtype: 'miniprogram',
+          miniprogram: {
+            title: this.fileFrom.miniprogramTitle,
+            pic_media_id: "待查询",
+            appid: "wx73f85f8d62769119",
+            page: this.fileFrom.miniprogramPage,
+            courseId:this.fileFrom.courseId,
+            videoId:this.fileFrom.videoId,
+            expiresDays:this.fileFrom.expiresDays,
+          }
+        };
+      }
+
+      if (itemIndex === -1) {
+        // 默认欢迎语附件处理
+        if (index < this.form.attachments.length) {
+          // 存在附件则更新
+          this.form.attachments.splice(index, 1, attachment);
+        } else {
+          // 不存在附件则插入
+          this.form.attachments.push(attachment);
+        }
+
+      } else {
+        // 分时段欢迎语附件处理
+        if (index < this.form.daypartingItemlist[itemIndex].attachments.length) {
+          // 存在附件则更新
+          this.form.daypartingItemlist[itemIndex].attachments.splice(index, 1, attachment);
+        } else {
+          // 不存在附件则插入
+          this.form.daypartingItemlist[itemIndex].attachments.push(attachment);
+        }
+      }
+
+      this.resetFileFrom();
+    },
+
+    //取消附件
+    cancelUpload() {
+      this.resetFileFrom();
+      this.welcomeItem.open = false;
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+
+    //重置附件表单
+    resetFileFrom() {
+      this.fileFrom = {
+        imagePicUrl: null,
+        linkTitle: null,
+        linkPicUrl: null,
+        linkDesc: null,
+        linkUrl: null,
+        videoId:null,
+        courseId:null,
+        miniprogramTitle:null,
+        miniprogramPage:null,
+        miniprogramPicUrl:null,
+        miniprogramAppid:null,
+      };
+
+      this.welcomeItem={
+        open: false,
+        title: '',
+        type: '',
+        index: -1,
+        itemIndex: -1
+      } // 重置编辑索引
+
+      this.videoList=[];
+    },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        qwUserIds: [],
+        companyId: null,
+        //默认欢迎语附件
+        attachments: [],
+        createdTime: null,
+        updateTieme: null,
+        isSendMsg:'1',
+        welcomeText: '',
+        isDayparting: '2',
+        //分时段欢迎语
+        daypartingItemlist:[{welcomeText:null,attachments:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null}],
+      };
+      this.userSelectList=[]
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      getQwAllUserList(this.queryParams.corpId).then(response => {
+        this.companyUserList = response.data;
+      });
+      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
+      getFriendWelcome(id).then(response => {
+
+
+        let data = response.row;
+
+        // 转换 attachments
+        if (typeof data.attachments === 'string') {
+          data.attachments = JSON.parse(data.attachments);
+        }
+
+        // 转换 daypartingItemlist
+        if (typeof data.daypartingItemlist === 'string') {
+          data.daypartingItemlist = JSON.parse(data.daypartingItemlist);
+        }
+
+        // 转换 daypartingItemlist 中的每个项目的 attachments 和 week
+        if (Array.isArray(data.daypartingItemlist)) {
+          data.daypartingItemlist = data.daypartingItemlist.map(item => {
+            return {
+              ...item,
+              attachments: typeof item.attachments === 'string' ? JSON.parse(item.attachments) : item.attachments,
+              week: typeof item.week === 'string' ? JSON.parse(item.week) : item.week
+            };
+          });
+        }
+
+        // 赋值给表单
+        this.form = data;
+        this.userSelectList=this.form.userSelectList
+
+        this.open = true;
+        this.title = "修改好友欢迎语";
+      });
+    },
+    /** 提交按钮 验证 from表单*/
+    submitForm() {
+
+      this.loading=true;
+
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.corpId=this.queryParams.corpId;
+          //有分时段欢迎语 验证分时段表单
+          if (this.form.isDayparting==='1'){
+            const itemForms = this.$refs.friendWelcomeItemForm;
+            if (Array.isArray(itemForms)) {
+              let allValid = true;
+
+              itemForms.forEach((itemFormRef, index) => {
+                itemFormRef.validate((itemValid) => {
+                  if (!itemValid) {
+                    this.loading=false;
+                    allValid = false;
+                  } else {
+                    const { startTime, endTime } = itemFormRef.model;
+                    if (startTime && endTime && startTime > endTime) {
+                      this.$message.error(`时段 ${index + 1} 的开始时间不能大于结束时间`);
+                      allValid = false;
+                      this.loading=false;
+
+                    }
+                  }
+
+                  if (index === itemForms.length - 1 && allValid) {
+                    //全表单验证通过
+                    this.commitForm();
+                  }
+                });
+              });
+            }
+          }else {
+            //只有默认的
+            this.commitForm();
+
+          }
+
+        }
+      });
+    },
+
+    //提交form表单
+    commitForm(){
+
+      // 深拷贝表单数据
+      const requestData = { ...this.form };
+      // 将 `form.attachments` 转为 JSON 字符串
+      requestData.attachments = JSON.stringify(this.form.attachments);
+      requestData.qwUserIds = JSON.stringify(this.form.qwUserIds);
+
+      // 遍历 `daypartingItemlist`,将其中的 `attachments` 和 `week` 转为 JSON 字符串
+      requestData.daypartingItemlist = JSON.stringify(requestData.daypartingItemlist.map(item => ({
+          ...item,
+        }))
+      );
+
+
+      if (this.form.id != null) {
+        updateFriendWelcome(requestData).then(response => {
+          this.msgSuccess("修改成功");
+          this.loading=false;
+          this.open = false;
+          this.getList();
+        }).catch(error => {
+          this.open=false;
+          this.loading = false;
+        });
+      } else {
+        addFriendWelcome(requestData).then(response => {
+          this.msgSuccess("新增成功");
+          this.loading=false;
+          this.open = false;
+          this.getList();
+        }).catch(error => {
+          this.open=false;
+          this.loading = false;
+        });
+      }
+
+
+      // 重置表单 无论成功还是失败-都重置表单
+      this.reset();
+    },
+
+    //处理时间
+    // formatTime(date) {
+    //   const hours = date.getHours().toString().padStart(2, '0');
+    //   const minutes = date.getMinutes().toString().padStart(2, '0');
+    //   const seconds = date.getSeconds().toString().padStart(2, '0');
+    //   return `${hours}:${minutes}:${seconds}`;
+    // },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除好友欢迎语编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delFriendWelcome(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有好友欢迎语数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportFriendWelcome(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>
+
+<style>
+.text-container {
+  max-height: 7.5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+</style>

+ 2 - 2
src/views/qw/friendWelcome/indexNew.vue

@@ -385,11 +385,11 @@
     </el-dialog>
 
     <!-- 选择成员账号弹窗   -->
-    <el-dialog :title="listUser.title" :visible.sync="listUser.open" style="width: 1600px;height: 100%" append-to-body>
+    <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="1600px" append-to-body>
       <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
     </el-dialog>
 
-    <el-dialog :title="welcomeItem.title" :visible.sync="welcomeItem.open" style="width: 1300px;height: 100%" append-to-body>
+    <el-dialog :title="welcomeItem.title" :visible.sync="welcomeItem.open" width="1300px" append-to-body>
       <el-form ref="fileFrom" :model="fileFrom" :rules="fuleRules" label-width="110px">
         <div v-if="welcomeItem.type==='image'">
           <el-form-item label="图片:" prop="imagePicUrl">

+ 241 - 35
src/views/qw/friendWelcome/index.vue → src/views/qw/friendWelcome/myWelcome.vue

@@ -96,7 +96,7 @@
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
       <el-table-column label="更新时间" align="center" prop="updateTime" width="180"/>
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
         <template slot-scope="scope">
           <el-button
             size="mini"
@@ -131,9 +131,8 @@
           <span style="font-size: 15px">基础信息</span>
           <el-divider></el-divider>
           <el-alert
-            title="注意事项"
-            type="warning"
-            description="这是提示~根据特色还不知道写点啥"
+            title="同一个销售的同一个企业微信账号,如果创建了多条记录,则以最新创建的那一条为准!!"
+            type="info"
             :closable="false"
             show-icon>
           </el-alert>
@@ -186,7 +185,7 @@
                   <div slot="header" style="display: flex;justify-content: space-between;align-items: center; ">
                     <div style="flex: 1;">
                     <span v-if="item.msgtype === 'image'">【图片】: {{ item.image.pic_url }}</span>
-                    <span v-if="item.msgtype === 'link'">【链接】: {{ item.link.title }}</span>
+                    <span v-if="item.msgtype === 'link'">【链接】: {{ item.link.title }}-{{item.link.desc}}</span>
                     <span v-if="item.msgtype === 'miniprogram'">【小程序】: {{ item.miniprogram.title }}</span>
                     </div>
                     <div style="  display: flex;gap: 10px;">
@@ -264,7 +263,7 @@
                 <el-row>
                   <el-col style="width: 965px">
                     <div style="background-color: #fbfbfb;padding: 10px;  border: 1px solid #e6e6e6; margin-bottom: 20px;">
-                                        <el-form ref="friendWelcomeItemForm"  :rules="itemRules" :model="item">
+                          <el-form ref="friendWelcomeItemForm"  :rules="itemRules" :model="item">
                           <div style="display: flex; gap: 10px;">
                             <el-form-item label="发起时间:" prop="week" style="flex: 8;">
                               <el-select v-model="item.week" remote multiple placeholder="请选择" filterable style="width: 580px">
@@ -310,7 +309,7 @@
                                 <div slot="header" style="  display: flex;justify-content: space-between;align-items: center; ">
                                   <div style="flex: 1;">
                                     <span v-if="attachment.msgtype === 'image'">【图片】: {{ attachment.image.pic_url }}</span>
-                                    <span v-if="attachment.msgtype === 'link'">【链接】: {{ attachment.link.title }}</span>
+                                    <span v-if="attachment.msgtype === 'link'">【链接】: {{ attachment.link.title }}-{{attachment.link.desc}}</span>
                                     <span v-if="attachment.msgtype === 'miniprogram'">【小程序】: {{ attachment.miniprogram.title }}</span>
                                   </div>
                                   <div style="  display: flex;gap: 10px;">
@@ -377,7 +376,7 @@
     </el-dialog>
 
     <!-- 选择成员账号弹窗   -->
-    <el-dialog :title="listUser.title" :visible.sync="listUser.open" style="width: 1600px;height: 100%" append-to-body>
+    <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="1600px"  append-to-body>
       <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
     </el-dialog>
 
@@ -390,6 +389,25 @@
         </div>
         <div v-if="welcomeItem.type==='link'">
 
+          <el-form-item label="选择课程">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+              <el-option
+                v-for="dict in courseList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+          </el-form-item>
+
           <el-form-item label="图文标题:" prop="linkTitle">
             <el-input v-model="fileFrom.linkTitle" :rows="2" maxlength="42"  show-word-limit placeholder="请输入图文消息标题,最长为42字" />
           </el-form-item>
@@ -399,19 +417,80 @@
           <el-form-item label="图文的描述:" prop="linkDesc">
             <el-input v-model="fileFrom.linkDesc" :rows="4" maxlength="170" show-word-limit type="textarea" placeholder="请输入内容,,最长为170字" />
           </el-form-item>
-          <el-form-item label="图文链接:" prop="linkUrl">
-            <el-input v-model="fileFrom.linkUrl" :rows="2"  placeholder="请输入图文链接" />
-          </el-form-item>
+          <div v-if="fileFrom.videoId==null" style="margin-top: 1%">
+            <el-form-item label="图文链接:"  label-width="100px" >
+              <el-input v-model="fileFrom.linkUrl" placeholder="请输入链接地址" style="width: 90%;"/>
+            </el-form-item>
+          </div>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="图文链接:"  label-width="100px" >
+              <el-tag type="warning" v-model="fileFrom.linkUrl='待生成'">选择的课程小节 即为卡片链接地址</el-tag>
+            </el-form-item>
+          </div>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="课节过期时间" style="margin-top: 1%" required label-width="110px">
+              <el-row>
+                <el-input-number  v-model="fileFrom.expiresDays"  :min="1" :max="9999" ></el-input-number>
+                (天)
+              </el-row>
+              <el-row>
+                <span class="tip">默认为30天</span>
+              </el-row>
+            </el-form-item>
+          </div>
+<!--          <el-form-item label="图文链接:" prop="linkUrl">-->
+<!--            <el-input v-model="fileFrom.linkUrl" :rows="2"  placeholder="选择了课程小节会自动设置地址" />-->
+<!--          </el-form-item>-->
         </div>
         <div v-if="welcomeItem.type==='miniprogram'">
 
-          <el-form-item label="小程序标题:" prop="miniprogramTitle" >
-            <el-input v-model="fileFrom.miniprogramTitle" :rows="2" maxlength="64"  show-word-limit placeholder="请输入小程序消息标题,最长为64字" />
+          <el-form-item label="选择课程">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+              <el-option
+                v-for="dict in courseList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
           </el-form-item>
-        </div>
 
-      </el-form>
+          <el-form-item label="小程序标题:" prop="miniprogramTitle">
+            <el-input v-model="fileFrom.miniprogramTitle" :rows="2" maxlength="64" placeholder="请输入小程序消息标题,最长为64字节" @input="checkByteLength(fileFrom)" />
+          </el-form-item>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="小程序链接:"  label-width="100px" >
+              <el-tag type="warning" v-model="fileFrom.miniprogramPage='待生成'">选择的课程小节 即为卡片小程序链接地址</el-tag>
+            </el-form-item>
+          </div>
+          <el-form-item label="appid" prop="miniprogramAppid" v-show="false" >
+            <el-input v-model="fileFrom.miniprogramAppid='wx73f85f8d62769119' " disabled />
+          </el-form-item>
 
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="课节过期时间" style="margin-top: 1%" required label-width="110px">
+              <el-row>
+                <el-input-number  v-model="fileFrom.expiresDays"  :min="1" :max="9999" ></el-input-number>
+                (天)
+              </el-row>
+              <el-row>
+                <span class="tip">默认为30天</span>
+              </el-row>
+            </el-form-item>
+          </div>
+          <!--          <el-form-item label="图文链接:" prop="linkUrl">-->
+          <!--            <el-input v-model="fileFrom.linkUrl" :rows="2"  placeholder="选择了课程小节会自动设置地址" />-->
+          <!--          </el-form-item>-->
+        </div>
+      </el-form>
       <div slot="footer" class="dialog-footer" style="text-align: center">
         <el-button type="primary" @click="confirmUpload">确定</el-button>
         <el-button type="primary" @click="cancelUpload">取消</el-button>
@@ -422,7 +501,7 @@
 </template>
 
 <script>
-import { listFriendWelcome, getFriendWelcome, delFriendWelcome, addFriendWelcome, updateFriendWelcome, exportFriendWelcome } from "@/api/qw/friendWelcome";
+import { listMyFriendWelcome,listFriendWelcome, getFriendWelcome, delFriendWelcome, addFriendWelcome, updateFriendWelcome, exportFriendWelcome } from "@/api/qw/friendWelcome";
 import qwUserList from '@/views/qw/user/qwUserList.vue'
 import ImageUploadWeclome from '@/views/qw/friendWelcome/ImageUploadWeclome.vue'
 import ImageUpload from '@/views/qw/material/ImageUpload.vue'
@@ -430,7 +509,7 @@ import { getQwAllUserList } from '@/api/company/companyUser'
 import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
 import {courseList, videoList} from "@/api/qw/sop";
 export default {
-  name: "FriendWelcome",
+  name: "myWelcome",
   components: { ImageUpload, qwUserList,ImageUploadWeclome},
   data() {
     return {
@@ -460,6 +539,7 @@ export default {
         linkUrl:null,
         videoId:null,
         courseId:null,
+        expiresDays:30,
         miniprogramTitle:null,
         miniprogramPage:null,
         miniprogramPicUrl:null,
@@ -471,7 +551,7 @@ export default {
         imagePicUrl:[ { required: true, message: "图片不能为空", trigger: "submit" }],
         linkTitle:[ { required: true, message: "图文标题不能为空", trigger: "submit" }],
         linkUrl:[ { required: true, message: "图文链接不能为空", trigger: "submit" }],
-        miniprogramTitle:[ { required: true, message: "小程序标题不能为空", trigger: "submit" }],
+        miniprogramTitle:[ { required: true, message: "图文链接不能为空", trigger: "submit" }],
       },
 
 
@@ -603,7 +683,7 @@ export default {
     getList() {
       this.loading = true;
 
-      listFriendWelcome(this.queryParams).then(response => {
+      listMyFriendWelcome(this.queryParams).then(response => {
 
         // 将处理后的数据赋值给 friendWelcomeList
         this.friendWelcomeList = response.rows;
@@ -611,7 +691,42 @@ export default {
         this.loading = false;
       });
     },
+    // // 检查字节长度
+    checkByteLength(fileFrom) {
+      const text = fileFrom.miniprogramTitle;
+      const byteLength = this.getByteLength(text); // 获取当前字节数
+
+      // 如果字节数超过64,截断输入内容
+      if (byteLength > 64) {
+        this.$set(fileFrom, 'miniprogramTitle', this.truncateTextByByteLength(text,64));
+      }
+    },
+
+    // 计算字符串的字节数
+    getByteLength(text) {
+      return new Blob([text]).size; // 使用 Blob 计算字节数
+    },
 
+    // 根据字节数截断字符串
+    truncateTextByByteLength(text, maxByteLength) {
+      let byteLength = 0;
+      let result = "";
+
+      for (let i = 0; i < text.length; i++) {
+        const char = text[i];
+        const charByteLength = this.getByteLength(char); // 获取当前字符的字节数
+
+        // 如果加上当前字符的字节数后不超过限制,则添加到结果中
+        if (byteLength + charByteLength <= maxByteLength) {
+          result += char;
+          byteLength += charByteLength;
+        } else {
+          break; // 超过限制时停止
+        }
+      }
+
+      return result;
+    },
 
     //选择群发的企业成员账号
     handlelistUser(){
@@ -635,10 +750,9 @@ export default {
           this.userSelectList.push(newItem);
         }
       });
-
       // //用于显示
       // this.userSelectList=list;
-      //
+
     },
     //删除一些选择了的账号
     handleClosegroupUser(list){
@@ -670,16 +784,98 @@ export default {
     },
 
     getTitleByCommand(command) {
-        switch (command) {
-          case 'image':
-            return '添加图片';
-          case 'link':
-            return '添加链接';
-          case 'miniprogram':
-            return '添加小程序';
+      switch (command) {
+        case 'image':
+          return '添加图片';
+        case 'link':
+          return '添加链接';
+        case 'miniprogram':
+          return '添加小程序';
       }
     },
 
+
+    courseChange(fileFrom,index,itemIndex){
+
+      // 清空 videoId 选择
+      this.$set(fileFrom, 'videoId', null);
+      // 清空 videoList
+      this.videoList = [];
+
+      if (fileFrom.courseId != null) {
+        // 查找选中的课程对应的 label 和 dictImgUrl
+        const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === fileFrom.courseId);
+
+        if (selectedCourse) {
+          // 设置 linkTitle 和 linkImageUrl
+          this.$set(fileFrom, 'linkTitle', selectedCourse.dictLabel);
+          this.$set(fileFrom, 'linkPicUrl', selectedCourse.dictImgUrl);
+        }
+
+
+        // 获取新的 videoList
+        videoList(fileFrom.courseId).then(response => {
+          this.videoList = response.list;
+        });
+
+      }
+      //
+      // // 更新对应的数据层级
+      // if (itemIndex === -1) {
+      //   // 更新 form.attachments
+      //   this.$set(this.form.attachments, index, {
+      //     ...this.form.attachments[index],
+      //     courseId: fileFrom.courseId,
+      //     videoId: null, // 因为已清空
+      //     title: fileFrom.linkTitle,
+      //     picurl: fileFrom.linkPicUrl
+      //   });
+      // } else {
+      //
+      //   this.$set(this.form.daypartingItemlist[itemIndex].attachments, index, {
+      //     ...this.form.daypartingItemlist[itemIndex].attachments[index],
+      //     courseId: fileFrom.courseId,
+      //     videoId: null, // 因为已清空
+      //     title: fileFrom.linkTitle,
+      //     picurl: fileFrom.linkPicUrl
+      //   });
+      // }
+    },
+    videoIdChange(fileFrom,index, itemIndex,type){
+      //选择了课程小节则 默认绑上
+      if (fileFrom.videoId != null) {
+        // 根据 videoId 获取相关信息(假设有相关的 API 调用)
+        let  selectedVideo = this.videoList.find(course => parseInt(course.dictValue) === fileFrom.videoId);
+        if (selectedVideo && type==='link') {
+          this.$set(fileFrom, 'linkDesc', selectedVideo.dictLabel);
+          this.$set(fileFrom, 'expiresDays', 30);
+        }
+        if (selectedVideo && type==='miniprogram') {
+          this.$set(fileFrom, 'miniprogramTitle', this.truncateTextByByteLength(selectedVideo.dictLabel,64));
+          this.$set(fileFrom, 'expiresDays', 30);
+        }
+
+      }
+
+      // // 更新对应的数据层级
+      // if (itemIndex === -1) {
+      //   // 更新 form.attachments
+      //   this.$set(this.form.attachments, index, {
+      //     ...this.form.attachments[index],
+      //     videoId: fileFrom.videoId,
+      //     desc: fileFrom.linkDesc,
+      //   });
+      // } else {
+      //   // 更新 form.daypartingItemlist[itemIndex].attachments
+      //   this.$set(this.form.daypartingItemlist[itemIndex].attachments, index, {
+      //     ...this.form.daypartingItemlist[itemIndex].attachments[index],
+      //     videoId: fileFrom.videoId,
+      //     desc: fileFrom.linkDesc,
+      //   });
+      //
+      // }
+
+    },
     //修改附件
     editFileItem(item, index, itemIndex){
 
@@ -697,7 +893,6 @@ export default {
         this.fileFrom.linkPicUrl = item.link.picurl;
         this.fileFrom.linkDesc = item.link.desc;
         this.fileFrom.linkUrl = item.link.url;
-
         this.fileFrom.videoId = item.link.videoId;
         this.fileFrom.courseId = item.link.courseId;
         this.fileFrom.expiresDays = item.link.expiresDays;
@@ -706,6 +901,7 @@ export default {
           this.videoList = response.list;
         });
 
+
       }else if (item.msgtype === 'miniprogram') {
         this.fileFrom.miniprogramAppid = 'wx73f85f8d62769119';
         this.fileFrom.miniprogramTitle = item.miniprogram.title;
@@ -719,10 +915,13 @@ export default {
           this.videoList = response.list;
         });
 
-
       }
+
+
     },
 
+
+
     getEditTitleByMsgType(msgType) {
       switch (msgType) {
         case 'image':
@@ -734,7 +933,6 @@ export default {
       }
     },
 
-
     //删除附件
     removeFileItem(data,index, itemIndex) {
 
@@ -760,7 +958,6 @@ export default {
     confirmUpload(fileFrom) {
 
       const { type, index, itemIndex } = this.welcomeItem;
-
       let attachment = {};
       if (type === 'image') {
         attachment = {
@@ -776,7 +973,10 @@ export default {
             title: this.fileFrom.linkTitle,
             picurl: this.fileFrom.linkPicUrl,
             desc: this.fileFrom.linkDesc,
-            url: this.fileFrom.linkUrl
+            url: this.fileFrom.linkUrl,
+            courseId:this.fileFrom.courseId,
+            videoId:this.fileFrom.videoId,
+            expiresDays:this.fileFrom.expiresDays,
           }
         };
       }else if (type==='miniprogram'){
@@ -784,9 +984,12 @@ export default {
           msgtype: 'miniprogram',
           miniprogram: {
             title: this.fileFrom.miniprogramTitle,
-            pic_media_id: this.fileFrom.miniprogramPicUrl,
-            appid: this.fileFrom.miniprogramAppid,
+            pic_media_id: "待查询",
+            appid: "wx73f85f8d62769119",
             page: this.fileFrom.miniprogramPage,
+            courseId:this.fileFrom.courseId,
+            videoId:this.fileFrom.videoId,
+            expiresDays:this.fileFrom.expiresDays,
           }
         };
       }
@@ -800,6 +1003,7 @@ export default {
           // 不存在附件则插入
           this.form.attachments.push(attachment);
         }
+
       } else {
         // 分时段欢迎语附件处理
         if (index < this.form.daypartingItemlist[itemIndex].attachments.length) {
@@ -849,6 +1053,8 @@ export default {
         index: -1,
         itemIndex: -1
       } // 重置编辑索引
+
+      this.videoList=[];
     },
 
     // 表单重置

+ 260 - 0
src/views/qw/groupChat/deptGroupIndex.vue

@@ -0,0 +1,260 @@
+<template>
+  <div class="app-container">
+    <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>
+  </div>
+</template>
+
+<script>
+import {
+  listGroupChatDeptList,
+  listGroupChat,
+  getGroupChat,
+  cogradientGroupChat
+} from '@/api/qw/groupChat'
+import Group_chat_user from '@/views/qw/groupChatUser/groupChatUser'
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+
+export default {
+  name: "deptGroupIndex",
+  components: { Group_chat_user },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      myQwCompanyList:[],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 客户群详情表格数据
+      groupChatList: [],
+      //客户群跟进状态
+      groupChatStatusOptions:[],
+
+      // 弹出层标题
+      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,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyList().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();
+      },
+    /** 查询客户群列表 */
+    getList() {
+      this.loading = true;
+      listGroupChatDeptList(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>

+ 261 - 0
src/views/qw/groupChat/myGroupChat.vue

@@ -0,0 +1,261 @@
+<template>
+  <div class="app-container">
+    <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>
+  </div>
+</template>
+
+<script>
+import {
+  cogradientMyGroupChat,
+  listGroupChatMyList,
+  listGroupChat,
+  getGroupChat,
+  cogradientGroupChat
+} from '@/api/qw/groupChat'
+import Group_chat_user from '@/views/qw/groupChatUser/groupChatUser'
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+
+export default {
+  name: "myGroupChat",
+  components: { Group_chat_user },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      myQwCompanyList:[],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 客户群详情表格数据
+      groupChatList: [],
+      //客户群跟进状态
+      groupChatStatusOptions:[],
+
+      // 弹出层标题
+      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,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyList().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();
+      },
+    /** 查询客户群列表 */
+    getList() {
+      this.loading = true;
+      listGroupChatMyList(this.queryParams).then(response => {
+        this.groupChatList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    //同步客户群(暂用)
+    getCogradientGroupChat(){
+      this.loading = true;
+      cogradientMyGroupChat(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>

+ 1826 - 0
src/views/qw/sop/deptSop.vue

@@ -0,0 +1,1826 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <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="qwUserIds">
+        <el-select v-model="queryParams.qwUserIds" filterable clearable placeholder="选择成员" size="small">
+          <el-option
+            v-for="dict in companyUserList"
+            :key="dict.id"
+            :label="dict.qwUserName"
+            :value="dict.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="规则编号" prop="id">
+        <el-input
+          v-model="queryParams.id"
+          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"  @change="updateCorpId()" >
+          <el-option
+            :key="1"
+            :label="'个微'"
+            :value="1"
+          />
+          <el-option
+            :key="2"
+            :label="'企微'"
+            :value="2"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="规则状态 " prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择规则状态" clearable size="small"  @change="updateCorpId()" >
+          <el-option
+            v-for="dict in sysSopStatus"
+            :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="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>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:sop:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['qw:sop:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:sop:export']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          size="mini"
+          plain
+          type="warning"
+          icon="el-icon-edit"
+          :disabled="multiple"
+          @click="handleExecute"
+          v-hasPermi="['qw:sop:execute']"
+        >批量执行SOP</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+    <el-table v-loading="loading" border :data="sopList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="规则编号" align="center" prop="id"  width="160"/>
+      <el-table-column label="规则名称" align="center" prop="name" width="150" />
+      <el-table-column label="规则状态" align="center" prop="status" width="150">
+        <template slot-scope="scope">
+          <dict-tag :options="sysSopStatus" :value="scope.row.status"></dict-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="类别" align="center" prop="type">
+        <template slot-scope="scope">
+          <el-tag type="success" v-if="scope.row.type==1">个微</el-tag>
+          <el-tag type="primary" v-else-if="scope.row.type==2">企微<span v-if="scope.row.filterMode == 2">(群聊)</span></el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="发送方式" align="center" prop="sendType">
+        <template slot-scope="scope">
+          <dict-tag :options="sysQwSopType" :value="scope.row.sendType"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="成员" align="center" prop="qwUserIds" width="150">
+        <template slot-scope="scope">
+          <!-- 点击事件绑定到整个 div -->
+          <div @click="toggleRow(scope.row)" v-if="scope.row.filterMode == 1">
+            <!-- 显示当前行的成员数量 -->
+            <span v-if="!expandedRows[scope.row.id]">
+            点击展开 ({{ scope.row.qwUserIds.split(',').length }} 人)
+          </span>
+            <!-- 展开时显示所有成员 -->
+            <div v-show="expandedRows[scope.row.id]">
+              <div v-if="scope.row.type==2" v-for="id in scope.row.qwUserIds.split(',')" :key="id"
+                   style="display: inline;" class="text-container">
+                <el-tag type="success" v-for="list in companyUserList" :key="list.qwUserId" style="margin: 3px;"
+                        v-if="list.id==id">
+                  {{ list.qwUserName }}
+                </el-tag>
+              </div>
+              <div v-if="scope.row.type==1" v-for="id in scope.row.qwUserIds.split(',')" :key="id"
+                   style="display: inline;" class="text-container">
+                <el-tag type="success" v-for="list in companyUserLists" :key="list.userId" style="margin: 3px;"
+                        v-if="list.userId==id">
+                  {{ list.nickName }}
+                </el-tag>
+              </div>
+            </div>
+          </div>
+          <div @click="toggleRow(scope.row)" v-if="scope.row.filterMode == 2">
+            <!-- 显示当前行的成员数量 -->
+            <span v-if="!expandedRows[scope.row.id]">
+            点击展开 ({{ scope.row.chatId.split(',').length }} 个)
+          </span>
+            <!-- 展开时显示所有成员 -->
+            <div v-show="expandedRows[scope.row.id]">
+              <div v-for="id in scope.row.chatId.split(',')" :key="id"
+                   style="display: inline;" class="text-container">
+                <el-tag type="success" v-for="list in chatList" :key="list.chatId" style="margin: 3px;"
+                        v-if="list.chatId == id">
+                  {{ list.name }}
+                </el-tag>
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="模板" align="center" prop="tempId" >
+        <template slot-scope="scope">
+            <div v-for="id in tempList" v-if="id.id==scope.row.tempId">{{id.name}}</div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="新客户自动创建sop" align="center" prop="isAutoSop" width="140">
+        <template slot-scope="scope">
+          <el-switch
+            v-if="scope.row.sendType==2 || scope.row.sendType==4"
+            v-model="scope.row.isAutoSop"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            :active-value="1"
+            :inactive-value="2"
+            @change="switchAutoSopChange(scope.row,scope.row.isAutoSop)">
+          </el-switch>
+          <span v-if="scope.row.sendType!=1 && scope.row.isAutoSop == '1'" style="margin-left: 10px;color: #13ce66">已开启</span>
+          <span v-if="scope.row.sendType!=1 && scope.row.isAutoSop == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
+          <span v-if="scope.row.sendType==1" style="margin-left: 10px;color: rgb(250,114,3)">企微接口无法设置</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="过期时间" align="center" prop="expiryTime" >
+        <template slot-scope="scope">
+          {{scope.row.expiryTime}} 小时
+        </template>
+      </el-table-column>
+      <el-table-column label="创建人" align="center" prop="createBy" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="修改规则状态时间" align="center" prop="stopTime" width="180"/>
+      <el-table-column label="查看操作" align="center" class-name="small-padding fixed-width"  width="200" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            v-if="scope.row.status==2||scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4 "
+            size="mini"
+            type="text"
+            @click="selectSchedule(scope.row)"
+            v-hasPermi="['qw:sop:list']"
+          >营期</el-button>
+          <el-button
+            v-if="scope.row.status==2 || scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4  "
+            size="mini"
+            type="text"
+            style="color: green;"
+            @click="handleScheduleDetail(scope.row)"
+            v-hasPermi="['qw:sop:list']"
+          >执行详情</el-button>
+          <el-button
+            v-if="scope.row.status==2 || scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4  "
+            size="mini"
+            type="text"
+            @click="handleUpdate(scope.row,2)"
+            v-hasPermi="['qw:sop:edit']"
+          >查看规则</el-button>
+          <el-button
+            v-if="scope.row.status==2 || scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4  "
+            size="mini"
+            type="text"
+            style="color: green;"
+            @click="handleQueryDetails(scope.row)"
+            v-hasPermi="['qw:sop:list']"
+          >查看模板</el-button>
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            @click="voice(scope.row.id)"-->
+<!--          >语音</el-button>-->
+
+        </template>
+      </el-table-column>
+      <el-table-column label="修改操作" align="center" class-name="small-padding fixed-width"  width="100px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleUpdateOutTime(scope.row)"
+          >修改规则</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-if="scope.row.filterMode == 2 && (scope.row.status==2||scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4)"
+            @click="handleSendMsg(scope.row)"
+          >一键发群
+          </el-button>
+          <el-button
+            v-if="scope.row.status == 1  "
+            size="mini"
+            type="text"
+            @click="handleUpdate(scope.row,1)"
+            v-hasPermi="['qw:sop:edit']"
+          >修改规则</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            style="color: red;"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:sop:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改企微sop对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="规则名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入规则名称" />
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="parseInt(dict.dictValue)"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+         <el-form-item label="类别" prop="type">
+         <el-radio-group v-model="form.type">
+             <el-radio
+               :label="1"
+             >个微</el-radio>
+             <el-radio
+               :label="2"
+             >企微</el-radio>
+         </el-radio-group>
+         </el-form-item>
+
+<!--        <div v-if="form.type==2">-->
+
+<!--        <el-form-item label="推送方式 ">-->
+<!--          <el-radio-group v-model="form.sendType" @input="handleSendTypeChange">-->
+<!--            <el-radio-->
+<!--              v-for="dict in sysQwSopType"-->
+<!--              :key="dict.dictValue"-->
+<!--              :label="parseInt(dict.dictValue)"-->
+<!--            >{{dict.dictLabel}}</el-radio>-->
+<!--          </el-radio-group>-->
+<!--        </el-form-item>-->
+<!--          <el-form-item label="选择员工" prop="qwUserIds" style="margin-top: 2%">-->
+<!--            <div>-->
+<!--              <el-button-->
+<!--                size="medium"-->
+<!--                icon="el-icon-circle-plus-outline"-->
+<!--                plain-->
+<!--                @click="handlelistUser(form.type,form.sendType)">请选择使用员工</el-button>-->
+<!--            </div>-->
+<!--            <div>-->
+<!--              <el-tag-->
+<!--                style="margin-left: 5px"-->
+<!--                size="medium"-->
+<!--                :key="id"-->
+<!--                v-for="id in userSelectList"-->
+<!--                closable-->
+<!--                :disable-transitions="false"-->
+<!--                @close="handleClosegroupUser(id)">-->
+<!--                <span v-for="list in companyUserList" :key="list.qwUserId" v-if="list.id==id">{{list.qwUserName}}</span>-->
+<!--              </el-tag>-->
+<!--            </div>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="标签规则" prop="filterType">-->
+<!--            <el-radio-group v-model="form.filterType">-->
+<!--              <el-radio-->
+<!--                :label="1"-->
+<!--              >含全部标签</el-radio>-->
+<!--              <el-radio-->
+<!--                :label="2"-->
+<!--              >含任意标签</el-radio>-->
+<!--            </el-radio-group>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="选择的标签" prop="tags">-->
+<!--            <el-select v-model="tags" 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="excludeTags">-->
+<!--            <el-select v-model="excludeTags" 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>-->
+<!--        </div>-->
+<!--        <div v-if="form.type==1">-->
+<!--          <el-form-item label="推送方式 ">-->
+<!--            <el-tag type="success" v-model="form.sendType=2">AI插件</el-tag>-->
+<!--          </el-form-item>-->
+<!--        </div>-->
+
+        <el-form-item label="开始时间" prop="startTime">
+          <el-date-picker clearable size="small"
+            v-model="form.startTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择开始时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="模板" prop="tempId">
+          <el-select v-model="form.tempId"  @focus="selectListSopTemp(form.sendType)" placeholder="请选择模板" v-loading="tempListLoading"   >
+            <el-option
+              v-for="dict in tempList"
+              :label="dict.name"
+              :value="dict.id">
+            </el-option>
+            <div v-if="tempListLoading" slot="prefix" class="select-prefix">正在查询相应模板...</div>
+          </el-select>
+        </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>
+    <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="1300px"  append-to-body>
+      <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
+    </el-dialog>
+
+    <!-- 单独的修改时间   -->
+    <el-dialog :title="outTimeOpen.title" :visible.sync="outTimeOpen.open" width="500px">
+
+       <el-col>
+
+         <el-row style="margin-top: 3%">
+           <span>过期时间:</span>
+           <el-input-number  v-model="outTimeOpen.expiryTime"  :min="1" :max="100" ></el-input-number>
+           (小时)
+         </el-row>
+
+         <el-row  style="margin-top: 3%">
+           <span>是否开启客户评级:</span>
+             <el-switch
+               v-model="outTimeOpen.isRating"
+               active-color="#13ce66"
+               inactive-color="#ff4949"
+               :active-value="1"
+               :inactive-value="2">
+             </el-switch>
+             <span v-if="outTimeOpen.isRating == '1'" style="margin-left: 10px;color: #13ce66">已开启</span>
+             <span v-if="outTimeOpen.isRating == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
+         </el-row>
+         <el-row style="margin-top: 3%">
+           <span>小转天数:</span>
+           <el-input-number  v-model="outTimeOpen.minConversionDay"></el-input-number>
+           (天)
+         </el-row>
+         <el-row style="margin-top: 3%">
+           <span>大转天数:</span>
+           <el-input-number  v-model="outTimeOpen.maxConversionDay"></el-input-number>
+           (天)
+         </el-row>
+         <el-row style="margin-top: 3%">
+           <span>发课开始天数:</span>
+           <el-input-number  v-model="outTimeOpen.courseDay"  :min="1" :max="100" ></el-input-number>
+           (天)
+           <div style="color: #999;font-size: 14px;display: flex;align-items: center;margin-top: 2%">
+             <i class="el-icon-info"></i>
+             作用于【催课看板】和【看课记录】的统计,由多少天开始计算。比如 模板里 第一天是先导课,第二天是正课,此处设置天数为2,则统计从第二天开始。如果无视模板天数,此处设置几天,则统计面板就从第几天开始统计
+           </div>
+         </el-row>
+         <el-row style="margin-top: 3%" >
+
+           <el-button type="primary" icon="el-icon-search" size="mini" @click="handleUpdateExpiryTime">确定修改</el-button>
+           <el-button icon="el-icon-refresh" size="mini" @click="resetUpdateExpiryTime">取消</el-button>
+         </el-row>
+
+
+       </el-col>
+    </el-dialog>
+    <!-- 单独的修改时间   -->
+    <el-dialog title="语音记录" :visible.sync="voiceForm.open" width="70%" append-to-body>
+      <el-row style="height: 600px">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:sop:add']"
+        >新增</el-button>
+        <el-table border :data="voiceForm.list">
+          <el-table-column label="员工" align="center" prop="companyUserName" />
+          <el-table-column label="名称" align="center" prop="name" />
+          <el-table-column label="天数" align="center" prop="dayNum">
+            <template slot-scope="scope">
+              第{{scope.row.dayNum}}天
+            </template>
+          </el-table-column>
+          <el-table-column label="发送时间" align="center" prop="time" />
+          <el-table-column label="语音文本" align="center" prop="voiceTxt" />
+          <el-table-column label="语音时长" align="center" prop="duration">
+            <template slot-scope="scope">
+              {{scope.row.duration}}秒
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+          v-show="voiceForm.total>0"
+          :total="voiceForm.total"
+          :page.sync="voiceForm.queryParams.pageNum"
+          :limit.sync="voiceForm.queryParams.pageSize"
+          @pagination="voice(voiceForm.queryParams.id)"
+        />
+      </el-row>
+    </el-dialog>
+
+    <el-dialog :title="autoSopOpen.title" :visible.sync="autoSopOpen.open" width="1300px"  append-to-body>
+        <el-form ref="autoSopTimeFrom" :model="form.autoSopTime" :rules="autoSopTimeRules">
+          <el-form-item label="自动类型" prop="type"     style="margin: 2%; display: flex; align-items: center;">
+            <el-radio-group v-model="form.autoSopTime.autoSopType">
+              <el-radio
+                :label="1"
+              >当天开始</el-radio>
+              <el-radio
+                :label="2"
+              >次日开始</el-radio>
+              <el-radio
+                :label="3"
+              >分营期开始(正课)</el-radio>
+              <el-radio
+                :label="4"
+              >分营期开始(先导)</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <div style="display: flex; align-items: center; flex-wrap: nowrap;">
+            <div v-if="form.autoSopTime.autoSopType==1" style="display: flex; align-items: center">
+              <el-form-item
+                label="起始时间"
+                prop="autoStartTime"
+                label-width="100px"
+                style="margin: 2% 0;align-items: center;">
+                <el-time-select
+                  style="width: 120px;"
+                  placeholder="起始时间"
+                  v-model="form.autoSopTime.autoStartTime"
+                  :picker-options="{
+                  start: '00:00',
+                  step: '00:15',
+                  end: '24:00'
+                }">
+                </el-time-select>
+              </el-form-item>
+              <el-form-item
+                label="结束时间"
+                prop="autoEndTime"
+                label-width="100px"
+                style="margin: 2% 0; align-items: center; ">
+                <el-time-select
+                  style="width: 120px;"
+                  placeholder="结束时间"
+                  v-model="form.autoSopTime.autoEndTime"
+                  :picker-options="{
+                  start: '00:00',
+                  step: '00:15',
+                  end: '24:00',
+                  minTime: form.autoSopTime.autoEndTime
+                }">
+                </el-time-select>
+              </el-form-item>
+            </div>
+          </div>
+          <el-form-item  v-if="form.autoSopTime.autoSopType==1" label="过期消息是否发送" prop="autoSopSend"     style="margin: 2%; display: flex; align-items: center;">
+            <el-radio-group v-model="form.autoSopTime.autoSopSend">
+              <el-radio
+                :label="1"
+              >是</el-radio>
+              <el-radio
+                :label="2"
+              >否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+
+          <div style="display: flex; align-items: center; flex-wrap: nowrap;" v-if="form.autoSopTime.autoSopType==3 || form.autoSopTime.autoSopType==4">
+            <el-form-item
+              label="选择一个或多个日期"
+              prop="autoDateTime"
+              label-width="150px">
+              <el-date-picker
+                size="large"
+                type="dates"
+                style="width: 600px"
+                v-model="form.autoSopTime.autoDateTime"
+                value-format="yyyy-MM-dd"
+                placeholder="选择一个或多个日期【ps:请先选择开始时间,不得小于任务开始时间】"
+                @change="sortSelectedDates(form.autoSopTime.autoDateTime)"
+                :disabled="!form.startTime">
+              </el-date-picker>
+            </el-form-item>
+          </div>
+
+
+          <el-alert
+            v-if="form.autoSopTime.autoSopType==1"
+            title="起始时间-结束时间之内的,当天立即创建SOP,时间之外的 次日创建SOP"
+            type="warning"
+            style="font-size: 30px; margin-top: 3%;"
+            :closable="false"
+            show-icon>
+          </el-alert>
+          <el-alert
+            v-if="form.autoSopTime.autoSopType==3"
+            type="warning"
+            style="margin-top: 3%;"
+            :closable="false"
+            show-icon>
+            <template #title>
+              <span style="font-size: 23px; line-height: 1.5;">
+                  此功能用于正课区分营期,可以选择你想要开始营期的具体时间,选择后在此期间添加的用户将会自动进入对应营期。
+                  例如今天1月1日,选择时间是1月1日,1月5日,1月10日。
+                  用户1月1日-1月4日添加(添加上对应标签)则会进入1月5日的营期,1月5日-1月9日添加则会进入1月10日营期,1月5日自动给用户发送第一节课程
+              </span>
+            </template>
+          </el-alert>
+          <el-alert
+            v-if="form.autoSopTime.autoSopType==4"
+            title=""
+            type="warning"
+            style="font-size: 30px; margin-top: 3%;"
+            :closable="false"
+            show-icon>
+            <template #title>
+              <span style="font-size: 23px; line-height: 1.5;">
+                    此功能用于先导课区分营期,可以选择先导课开始营期的具体时间,选择后在此期间添加的用户将会自动进入对应营期。
+                    例如今天1月1日,选择时间是1月1日,1月5日,1月10日。
+                    用户1月1日-1月4日添加(添加上对应标签)则会进入1月1日的营期,1月5日-1月9日添加则会进入1月5日营期,自动给用户匹配上对应应该听到天数的时间节点
+              </span>
+            </template>
+          </el-alert>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click="submitAutoSopTimeFrom">确 定</el-button>
+          <el-button @click="cancelAutoSopTime">取 消</el-button>
+        </div>
+    </el-dialog>
+    <!--  执行详情  -->
+    <el-drawer :title="sopLogsDialog.title" :visible.sync="sopLogsDialog.open" size="85%" style="font-weight: bolder">
+      <sopLogsDetails ref="sopLogsDetails" :rowDetailFrom="sopLogsDialog.sopLogsForm"></sopLogsDetails>
+    </el-drawer>
+    <el-dialog :title="sendMsgOpen.title" :visible.sync="sendMsgOpen.open"  width="1000px" append-to-body>
+      <el-form ref="msgForm" :model="msgForm" :rules="msgRules" label-width="100px">
+        <el-form-item label="群">
+          <el-select  v-model="msgForm.chatIds" placeholder="请选择群" size="mini" multiple>
+            <el-option
+              v-for="chatId in sendMsgOpen.chatIds"
+              :key="chatId"
+              :label="chatList.filter(e => e.chatId == chatId) && chatList.filter(e => e.chatId == chatId).length > 0 ? chatList.filter(e => e.chatId == chatId)[0].name : ''"
+              :value="chatId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="发送类型">
+          <el-radio-group v-model="msgForm.sendType">
+            <el-radio :label="1">群</el-radio>
+            <el-radio :label="2">群成员</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="选择课程">
+          <el-select  v-model="msgForm.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange()">
+            <el-option
+              v-for="dict in courseList"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            />
+          </el-select>
+          <el-select  v-model="msgForm.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange()"  >
+            <el-option
+              v-for="dict in videoList"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            />
+          </el-select>
+          <el-select  v-model="msgForm.courseType" placeholder="请选择消息类型" size="mini" style=" margin-right: 10px;">
+            <el-option
+              v-for="dict in sysFsSopWatchStatus"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="规则" prop="setting"  >
+          <div v-for="(item, index) in setting" :key="index" style="background-color: #fdfdfd; border: 1px solid #e6e6e6; margin-bottom: 20px;">
+            <el-row>
+              <el-col :span="22">
+                <el-form :model="item" label-width="70px">
+                  <el-form-item label="内容类别" style="margin: 2%">
+                    <el-radio-group  v-model="item.contentType">
+                      <el-radio   :label="item.dictValue" v-for="item in sysQwSopAiContentType"  @change="handleContentTypeChange()">{{item.dictLabel}}</el-radio>
+                    </el-radio-group>
+                  </el-form-item>
+                  <el-form-item label="内容" style="margin-bottom: 2%" >
+                    <el-input v-if="item.contentType == 1 " v-model="item.value" type="textarea" :rows="3" placeholder="内容" style="width: 90%;margin-top: 10px;"/>
+
+                    <ImageUpload v-if="item.contentType == 2 " v-model="item.imgUrl" type="image" :num="1"  :width="150" :height="150" />
+
+                    <div v-if="item.contentType == 3 ">
+                      <el-card class="box-card">
+                        <el-form-item label="链接标题:"  label-width="100px">
+                          <el-input v-model="item.linkTitle" placeholder="请输入链接标题" style="width: 90%;"/>
+                        </el-form-item>
+                        <el-form-item label="链接描述:"   label-width="100px" >
+                          <el-input type="textarea" :rows="3" v-model="item.linkDescribe" placeholder="请输入链接描述" style="width: 90%;margin-top: 1%;"/>
+                        </el-form-item>
+                        <el-form-item label="链接封面:"   label-width="100px">
+                          <ImageUpload v-model="item.linkImageUrl" type="image" :num="1" :file-size="2" :width="150" :height="150" style="margin-top: 1%;" />
+                        </el-form-item>
+                        <el-form-item label="链接地址:"  label-width="100px" >
+                          <el-tag type="warning" v-model="item.isBindUrl=1">选择的课程小节 即为卡片链接地址</el-tag>
+                        </el-form-item>
+                      </el-card>
+                    </div>
+                    <div v-if="item.contentType == 4">
+
+                    </div>
+                    <div v-if="item.contentType == 5 ">
+
+                      <el-form-item label="上传文件:" prop="fileUrl" label-width="100px">
+                        <el-upload
+                          v-model="item.fileUrl"
+                          class="avatar-uploader"
+                          :action="uploadUrl"
+                          :show-file-list="false"
+                          :on-success="(res, file) => handleAvatarSuccessFile(res, file, item)"
+                          :before-upload="beforeAvatarUploadFile">
+                          <i class="el-icon-plus avatar-uploader-icon"></i>
+                        </el-upload>
+                        <el-link v-if="item.fileUrl" type="primary" :href="downloadUrl(item.fileUrl)" download>
+                          {{item.fileUrl}}
+                        </el-link>
+                      </el-form-item>
+
+                    </div>
+
+                    <div v-if="item.contentType == 6 ">
+                      <el-form-item label="上传视频:" prop="videoUrl" label-width="100px">
+                        <el-upload
+                          v-model="item.videoUrl"
+                          class="avatar-uploader"
+                          :action="uploadUrl"
+                          :show-file-list="false"
+                          :on-success="(res, file) => handleAvatarSuccessVideo(res, file, item)"
+                          :before-upload="beforeAvatarUploadVideo">
+                          <i class="el-icon-plus avatar-uploader-icon"></i>
+                        </el-upload>
+                        <video v-if="item.videoUrl"
+                               :src="item.videoUrl"
+                               controls style="width: 200px;height: 100px">
+                        </video>
+                      </el-form-item>
+                    </div>
+                    <div v-if="item.contentType == 7 ">
+                      <el-input
+                        v-model="item.value"
+                        type="textarea" :rows="3" maxlength="66" show-word-limit
+                        placeholder="输入要转为语音的内容" style="width: 90%;margin-top: 10px;"
+                        @input="handleInputVideoText(item.value,item)"/>
+                    </div>
+
+                    <div v-if="item.contentType == 10 ">
+                      <el-card class="box-card">
+                        <el-form-item label="链接标题:"  label-width="100px">
+                          <el-input v-model="item.linkTitle" placeholder="请输入链接标题" style="width: 90%;"/>
+                        </el-form-item>
+                        <el-form-item label="链接描述:"   label-width="100px" >
+                          <el-input type="textarea" :rows="3" v-model="item.linkDescribe" placeholder="请输入链接描述" style="width: 90%;margin-top: 1%;"/>
+                        </el-form-item>
+                        <el-form-item label="链接封面:"   label-width="100px">
+                          <ImageUpload v-model="item.linkImageUrl" type="image" :num="1" :file-size="2" :width="150" :height="150" style="margin-top: 1%;" />
+                        </el-form-item>
+                        <el-form-item label="链接地址:"  label-width="100px" >
+                          <el-tag type="warning" >链接地址自动生成</el-tag>
+                        </el-form-item>
+                      </el-card>
+                    </div>
+                  </el-form-item>
+
+                  <el-form-item label="添加短链" v-if="item.contentType == 1 "  >
+                    <el-tooltip content="请先根据课程选定课程小节之后再添加" effect="dark" :disabled="!!msgForm.videoId">
+                      <el-switch
+                        v-model="item.isBindUrl"
+                        :disabled="!msgForm.videoId"
+                        active-color="#13ce66"
+                        inactive-color="#DCDFE6"
+                        active-value="1"
+                        inactive-value="2">
+                      </el-switch>
+                    </el-tooltip>
+
+                    <span v-if="item.isBindUrl == '1'" style="margin-left: 10px; color: #13ce66">添加URL</span>
+                    <span v-if="item.isBindUrl == '2'" style="margin-left: 10px; color: #b1b4ba">不加URL</span>
+                  </el-form-item>
+                  <el-form-item label="课节过期时间" v-if="item.isBindUrl == '1'
+                                                          && item.contentType != 2
+                                                          && item.contentType != 5
+                                                          && item.contentType != 6
+                                                          && item.contentType != 8
+                                                          && item.contentType != 9
+                                                          && item.contentType != 10"
+                                style="margin-top: 1%" label-width="100px">
+                    <el-row>
+                      <el-input-number  v-model="item.expiresDays"  :min="1" :max="100" ></el-input-number>
+                      (天)
+                    </el-row>
+                    <el-row>
+                      <span class="tip">填写0或不填时,默认为系统配置的默认时间</span>
+                    </el-row>
+                  </el-form-item>
+                </el-form>
+              </el-col>
+              <el-col :span="1" :offset="1">
+                <i class="el-icon-delete" @click="delSetList(index)" style="margin-top: 20px;" v-if="setting.length>1"></i>
+              </el-col>
+            </el-row>
+          </div>
+          <el-link type="primary" class="el-icon-plus" :underline="false" @click='addSetList()'  >添加内容</el-link>
+
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitMsgForm">确 定</el-button>
+        <el-button @click="cancelMsgForm">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listDeptSop,
+  addSop,
+  courseList,
+  videoList,
+  delSop,
+  exportSop,
+  getSopVoiceList,
+  listSop,
+  updateAutoSopTime,
+  updateSop,
+  updateSopStatus,
+  updateStatus
+} from "@/api/qw/sop";
+import {listSopTemp} from "@/api/qw/sopTemp";
+import {getQwAllUserList, listUser} from '@/api/company/companyUser'
+import qwUserList from '@/views/qw/user/qwUserList.vue'
+import ImageUpload from "@/views/qw/sop/ImageUpload";
+import CustomerGroupDetails from '@/views/qw/groupMsg/customerGroupDetails.vue'
+import sopLogsDetails from '@/views/qw/sopLogs/sopLogsList.vue'
+import {listTag,} from "@/api/qw/tag";
+import {sendMsgSop} from "@/api/qw/sopUserLogsInfo";
+import {getMyQwCompanyList} from "@/api/qw/user";
+import {allList} from "@/api/qw/groupChat";
+
+export default {
+  name: "deptSop",
+    components: { CustomerGroupDetails, qwUserList,ImageUpload,sopLogsDetails},
+  data() {
+    return {
+      // 存储每一行的展开状态
+      expandedRows: {},
+      //模板查询
+      tempListLoading:false,
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      //选中的map
+      selectionMap:{},
+      myQwCompanyList:[],
+      //销售员工列表
+      companyUserLists:[],
+      videoList:[],
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      uploadUrlByVoice:process.env.VUE_APP_BASE_API+"/common/uploadOSSByHOOKVoice",
+      msgForm:{
+        videoId:null,
+        courseId:null,
+        courseType:null,
+        userIdParam:null,
+        sendType:1,
+        setting:null,
+        ids:null,
+        sopId: null,
+        startTime: null,
+        chatIds: [],
+        isRegister:2
+      },
+      sendMsgOpen:{
+        title:'一键批量群发',
+        open:false,
+        row: {},
+        ids:null,
+      },
+      msgRules:{},
+      courseList:[],
+      // videoList:[],
+      tags:null,
+      excludeTags:null,
+      // 非单个禁用
+      single: true,
+      setting:[],
+      tagList:[],
+      tempList:[],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企微sop表格数据
+      sopList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      companyUserList:[],
+      // 状态字典
+      statusOptions: [],
+      //sop状态
+      sysSopStatus: [],
+
+      autoSopOpen:{
+        title:'',
+        open:false,
+        id:null,
+        isAutoSop:null,
+      },
+      outTimeOpen:{
+        title:'',
+        open:false,
+        id:null,
+        tempId:null,
+        expiryTime:null,
+        isRating:null,
+        isSampSend:null,
+      },
+      voiceForm:{
+        list:[],
+        open:false,
+        total:0,
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          id: null,
+        },
+      },
+
+      //企微SOP发送类型
+      sysQwSopType: [],
+      chatList: [],
+
+      //SOP课程观看状态
+      sysFsSopWatchStatus:[],
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        id: null,
+        name: null,
+        status: null,
+        sendType:null,
+        type: null,
+        qwUserIds: null,
+        setting: null,
+        createBy: null,
+        corpId: null,
+        createTime: null
+      },
+      sopLogsDialog:{
+        title:'',
+        open:false,
+        sopLogsForm:[],
+      },
+      // 表单参数
+      form: {
+        autoSopTime:{ autoSopType:2,autoStartTime:'00:00',autoEndTime:'24:00',autoSopSend:2,autoDateTime:[]},
+      },
+      userSelectList:[],
+      listUser:{
+        title:"",
+        open:false
+      },
+      // 表单校验
+      rules: {
+        name:[ { required: true, message: "名称不能为空", trigger: "submit" }],
+        type:[ { required: true, message: "不能为空", trigger: "submit" }],
+        sendType:[ { required: true, message: "不能为空", trigger: "submit" }],
+        startTime:[ { required: true, message: "开始时间不能为空", trigger: "submit" }],
+        tempId:[ { required: true, message: "模板不能为空", trigger: "submit" }],
+      },
+      autoSopTimeRules:{
+        autoSopType:[ { required: true, message: "选项不能为空", trigger: "submit" }],
+        autoStartTime:[ { required: true, message: "起始时间不能为空", trigger: "submit" }],
+        autoEndTime:[ { required: true, message: "结束时间不能为空", trigger: "submit" }],
+        autoDateTime:[ { required: true, message: "日期不能为空", trigger: "submit" }],
+      }
+    };
+  },
+  created() {
+
+    this.getDicts("sys_sop_status").then(response => {
+      this.sysSopStatus = response.data;
+    });
+
+
+    this.getDicts("sys_qwSopAi_contentType").then(response => {
+      this.sysQwSopAiContentType = response.data;
+    });
+    this.getDicts("sys_fs_sop_watch_status").then(response => {
+      this.sysFsSopWatchStatus = response.data;
+    });
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_type").then(response => {
+      this.sysQwSopType = response.data;
+    });
+
+
+    listUser().then(res => {
+        this.companyUserLists = res.rows;
+      }
+    );
+
+    courseList().then(response => {
+      this.courseList = response.list;
+    });
+
+
+    getMyQwCompanyList().then(response => {
+      this.myQwCompanyList = response.data;
+      if(this.myQwCompanyList!=null){
+        this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+        this.refreshData(this.queryParams.corpId);
+        this.getList();
+      }
+    });
+
+
+
+  },
+  watch:{
+    userSelectList(newList) {
+      this.form.qwUserIds = newList.map(item => item.id);
+    }
+  },
+  methods: {
+    voice(id){
+      this.voiceForm.queryParams.id = id;
+      getSopVoiceList(this.voiceForm.queryParams).then(res => {
+        this.voiceForm.list = res.rows;
+        this.voiceForm.total = res.total;
+        this.voiceForm.open = true;
+      })
+    },
+    // 单元格点击事件
+    handleCellClick(row, column, cell, event) {
+      // 判断是否为规则编号列
+      if (column.property === 'id') {
+        this.handleRowClick(row); // 触发规则编号点击事件
+      }
+    },
+    // handleUpdateTags(){
+    //
+    // },
+    // handleUpdateQwUser(){
+    //
+    // },
+    // handleUpdateSopTemp(){
+    //
+    // },
+    handleRowClick(row, column, event) {
+      // 判断状态是否符合条件
+      if (row.status == 2 || row.status == 0 || row.status == 3 || row.status == 4) {
+        this.handleUpdate(row, 2);
+      }
+    },
+    // 切换某一行的展开状态
+    toggleRow(row) {
+      this.$set(this.expandedRows, row.id, !this.expandedRows[row.id]);
+    },
+    getSwitchVal(status) {
+      return [2, 3, 4].includes(status) ? 2 : 0;
+    },
+
+    onSwitchChange(row, val) {
+      this.loading=true;
+      // ① 调用接口更新后端
+      updateSopStatus({ id: row.id, status: val })
+        .then(() => {
+          row.status = val;
+          this.loading=false;
+          this.$message.success("切换成功!");
+        })
+        .catch(() => {
+          this.loading=false;
+          this.$message.error("操作失败,请重试");
+        });
+    },
+
+    switchSopStatusChange(row,checked){
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '暂停中-请勿刷新页面-重复点击',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      updateSopStatus({id:row,status:checked}).then(response => {
+        this.$message.success("修改成功");
+        this.getList();
+      }).finally(res=>{
+        loadingRock.close();
+      })
+
+
+    },
+
+    //新客户自动创建sop
+    switchAutoSopChange(row,checked){
+
+      this.form.startTime=row.startTime;
+      this.form.autoSopTime=JSON.parse(row.autoSopTime);
+
+      if (checked==1) {
+        this.autoSopOpen.title='请设置相应时间段'
+        this.autoSopOpen.open=true;
+        this.autoSopOpen.id=row.id;
+        this.autoSopOpen.isAutoSop=1;
+      }else {
+        this.form.autoSopTime.createTime=this.formatDateTo24HourString(new Date());
+        updateAutoSopTime({id:row.id,isAutoSop:checked,autoSopTime: JSON.stringify(this.form.autoSopTime)}).then(response => {
+          this.getList();
+        })
+      }
+
+
+    },
+     updateCorpId(){
+       this.reset();
+       this.refreshData(this.queryParams.corpId);
+       this.queryParams.qwUserId = null;
+       this.getList();
+     },
+
+    //刷新部分数据
+    refreshData(row){
+      getQwAllUserList(row).then(response => {
+        this.companyUserList = response.data;
+      });
+
+      listTag({corpId:row}).then(response => {
+        this.tagList = response.rows;
+      });
+
+      if (row != null) {
+        allList(row).then(e => {
+          this.chatList = e.data;
+        })
+      }
+    },
+
+    //查询模板
+    selectListSopTemp(type){
+      this.tempListLoading = true; // 开始查询,显示加载提示
+      listSopTemp({sendType:type}).then(response => {
+        this.tempList = response.rows;
+        this.tempListLoading = false;
+      });
+    },
+    handlelistUser(type,sendType){
+
+       setTimeout(() => {
+         this.$refs.QwUserList.getDetails(this.queryParams.corpId,type,sendType);
+       }, 1);
+       this.listUser.title="选择企业成员"
+       this.listUser.open=true;
+
+    },
+    selectUserList(list){
+      this.listUser.open=false;
+      list.forEach(obj => {
+        if (!this.userSelectList.some(item => item == obj.id)) {
+          this.userSelectList.push(obj.id);
+        }
+      });
+
+    },
+
+    //修改过期时间
+    handleUpdateOutTime(val){
+        this.outTimeOpen.title="修改过期时间/评级";
+        this.outTimeOpen.id=val.id;
+        this.outTimeOpen.tempId=val.tempId;
+        this.outTimeOpen.expiryTime=val.expiryTime;
+        this.outTimeOpen.isRating=val.isRating;
+        this.outTimeOpen.minConversionDay=val.minConversionDay;
+        this.outTimeOpen.maxConversionDay=val.maxConversionDay;
+        this.outTimeOpen.courseDay=val.courseDay;
+        this.outTimeOpen.isSampSend=val.isSampSend;
+        this.outTimeOpen.open=true;
+    },
+
+    handleUpdateExpiryTime(){
+      updateSop({id:this.outTimeOpen.id,tempId:this.outTimeOpen.tempId,expiryTime:this.outTimeOpen.expiryTime,
+        isRating: this.outTimeOpen.isRating,minConversionDay: this.outTimeOpen.minConversionDay,maxConversionDay: this.outTimeOpen.maxConversionDay,
+        courseDay: this.outTimeOpen.courseDay,isSampSend:this.outTimeOpen.isSampSend}).then(response => {
+        this.msgSuccess("修改成功");
+        this.resetUpdateExpiryTime()
+        this.getList();
+      });
+    },
+    resetUpdateExpiryTime(){
+      this.outTimeOpen={
+          title:'',
+          open:false,
+          id:null,
+          expiryTime:null,
+          courseDay:null,
+          minConversionDay:null,
+          maxConversionDay:null,
+          isRating:null,
+          isSampSend:null,
+      }
+    },
+    addContent(index){
+      // this.setting[index].content.push({type:1})
+      if (this.form.sendType==2){
+        this.setting[index].content.push({ type: 1 });
+      }else {
+        if (this.setting[index].content.length < 9) {
+          this.setting[index].content.push({ type: 1 });
+        } else {
+          this.$message({
+            message: '最多只能添加 9 个内容',
+            type: 'warning'
+          });
+        }
+      }
+
+    },
+
+    //选择变动时的变动
+    handleSendTypeChange(val){
+      this.tempList=[];
+      this.form.tempId=null;
+      if (val==1) {
+        // 遍历 this.setting 数组并清空每个对象的 content 属性
+        this.setting.forEach(item => {
+          if (item.content.length > 9) {
+            item.content = item.content.slice(0, 9); // 保留前 9 个元素
+          }
+        });
+      }
+    },
+    delContent(index,contentIndex){
+      this.setting[index].content.splice(contentIndex,1)
+    },
+
+    //添加SOP规则类型
+    handleCommand(command){
+      this.setting.push({sopType:command,ruleType:null,name:null,type:1,content:[],isBindUrl:1,url:null,day:"0",hour:"0",minute:"0",time:""})
+    },
+
+    //添加课程SOP
+    handleCrouseCommand(command,val){
+      console.log("command",command)
+      console.log("val",val)
+    },
+
+    delSetting(index){
+      this.setting.splice(index,1)
+    },
+    handleClosegroupUser(list){
+      const index = this.userSelectList.findIndex(t => t === list);
+      if (index !== -1) {
+        this.userSelectList.splice(index, 1);
+      }
+    },
+    /** 查询企微sop列表 */
+    getList() {
+      this.loading = true;
+      listDeptSop(this.queryParams).then(response => {
+
+        this.sopList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+
+
+        listSopTemp().then(res => {
+          this.tempList = res.rows;
+        });
+
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+
+    // courseChange(){
+    //   videoList(this.form.courseId).then(response => {
+    //     this.videoList = response.list;
+    //   });
+    // },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        status: 1,
+        sendType:2,
+        type: 2,
+        filterType:2,
+        qwUserIds: null,
+        corpId: null,
+        setting: null,
+        createBy: null,
+        createTime: null,
+        isAutoSop:null,
+        autoSopTime:{ autoSopType:2,autoStartTime:'00:00',autoEndTime:'24:00',autoSopSend:2,autoDateTime:[]},
+      };
+      this.resetForm("form");
+      this.tags = null;
+      this.excludeTags = null;
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+      this.refreshData(this.queryParams.corpId);
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.selectionMap=selection;
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.$router.push('/qw/sop/addSop/'+this.queryParams.corpId)
+      // this.open = true;
+      // this.setting=[]
+      // this.userSelectList=[]
+      // this.title = "添加企微sop";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row,type) {
+      this.$router.push('/qw/sop/updateSop/'+row.id+'/'+type)
+    },
+
+
+    /**
+    * 查看SOP任务内营期
+    */
+    selectSchedule(row){
+      // type 2:我的sop 1:部门sop/销售公司sop
+      const query = {
+        id: row.id,
+        name: row.name,
+        tempId: row.tempId,
+        filterMode: row.filterMode,
+        corpId: row.corpId,
+        type:1,
+      }
+      // 使用 params 传递参数
+      this.$router.push({
+        path: `/qw/sopUserLogs/sopUserLogsSchedule/${query.id}`,
+        query // 如果需要传递更多参数,可以使用 query
+      });
+    },
+
+
+    /**
+    * 查看营期内详情
+    */
+    handleScheduleDetail(row){
+        this.sopLogsDialog.title='规则执行详情';
+        this.sopLogsDialog.open=true;
+        this.sopLogsDialog.sopLogsForm=row;
+    },
+
+    /**
+    * 查看模板
+    */
+    handleQueryDetails(row){
+      this.$router.push(`/qw/sopTemp/updateSopTemp/${row.tempId}/3`)
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if(this.userSelectList.length<=0){
+            return this.$message("请选择员工")
+          }
+          this.form.qwUserIds = this.userSelectList.join(",");
+          this.form.corpId=this.queryParams.corpId;
+          if (this.tags!=null && this.tags.length>0 ){
+            this.form.tags=(this.tags).toString()
+          }else {
+            return  this.$message.error("选择的标签不能为空!!请选择筛选的标签")
+          }
+          if (this.excludeTags!=null){
+            this.form.excludeTags=(this.excludeTags).toString()
+          }
+
+          this.form.setting=JSON.stringify(this.setting)
+          if (this.form.id != null) {
+            updateSop(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addSop(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    sortSelectedDates(dates){
+
+      if (!this.form.startTime) {
+        this.$message.error("请先选择开始时间!不得小于任务开始时间");
+        this.form.autoSopTime.autoDateTime = [];
+        return;
+      }
+
+      // 1. 过滤掉 < startTime 的日期
+      const validDates = dates.filter(date => new Date(date) >= new Date(this.form.startTime));
+
+      // 2. 如果有被过滤掉的日期,提示用户
+      if (validDates.length < dates.length) {
+        this.$message.warning(`已自动移除小于 ${this.form.startTime} 的日期!`);
+      }
+
+      // 3. 升序排序
+      validDates.sort((a, b) => new Date(a) - new Date(b));
+
+      // 4. 更新数据
+      this.form.autoSopTime.autoDateTime = validDates;
+    },
+
+    submitAutoSopTimeFrom(){
+
+      if (this.form.autoSopTime.autoSopType==3 || this.form.autoSopTime.autoSopType==4){
+        if(this.form.autoSopTime.autoDateTime==null || this.form.autoSopTime.autoDateTime=="") {
+          return  this.$message.error("选择的日期不能为空!!请选择日期")
+        }
+      }
+
+      this.$refs["autoSopTimeFrom"].validate(valid => {
+        if (valid) {
+          this.autoSopOpen.open=false
+          this.form.autoSopTime.createTime=this.formatDateTo24HourString(new Date());
+          updateAutoSopTime({id:this.autoSopOpen.id,isAutoSop:this.autoSopOpen.isAutoSop,autoSopTime: JSON.stringify(this.form.autoSopTime)}).then(response => {
+            this.msgSuccess("修改成功");
+          });
+        }
+        this.getList();
+        this.reset();
+      });
+    },
+
+    formatDateTo24HourString(date) {
+      let year = date.getFullYear();
+      let month = ('0' + (date.getMonth() + 1)).slice(-2); // 月份需要加 1 并补零
+      let day = ('0' + date.getDate()).slice(-2); // 日需要补零
+      let hours = ('0' + date.getHours()).slice(-2); // 小时需要补零
+      let minutes = ('0' + date.getMinutes()).slice(-2); // 分钟需要补零
+      let seconds = ('0' + date.getSeconds()).slice(-2); // 秒需要补零
+
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    },
+    cancelAutoSopTime(){
+      this.autoSopOpen.open=false
+      this.getList();
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企微sop编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delSop(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /**
+    * 批量执行SOP任务
+    */
+    handleExecute(){
+
+        const ids = this.selectionMap
+          .filter(item => item.status === 1)
+          .map(item => item.id);
+
+        if (ids.length === 0) {
+          this.msgError("选择的任务已经执行或正在执行,请选择待执行的任务");
+          return;
+        }
+
+        this.$confirm('是否确认立即执行sop编号为"' + ids + '"的数据项?', "警告【只能立即执行(待执行的)】", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+            this.loading = true;
+            // 执行更新操作
+            return updateStatus(ids); // 返回一个Promise,直接在此链式调用
+        }).then(res => {
+          let msg = "";
+
+          // 判断成功和失败的任务,并显示消息
+          if (res.suc.length > 0) {
+            msg += "执行成功的SOP任务【" + res.suc.join(", ") + "】。<br>"; // 优化:将数组转换为字符串
+          }
+          if (res.err.length > 0) {
+            msg += "失败的SOP任务【" + res.err.join(", ") + "】,原因是已经执行或正在执行。<br>";
+          }
+
+          // 显示确认框,显示成功与失败信息
+          return this.$confirm(msg, "提示", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+            dangerouslyUseHTMLString: true // 允许HTML标签
+          });
+
+        }).then(() => {
+          // 操作完成后刷新列表,并显示成功信息
+          this.getList();
+          this.msgSuccess("执行完成");
+        }).catch(() => {
+          // 处理任何异常,操作取消或者失败时显示提示信息
+          this.msgError("操作失败,请重试");
+        }).finally(() => {
+          this.loading = false; // 操作完成后关闭加载状态
+        });
+
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企微sop数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportSop(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    courseChange() {
+      if (this.msgForm.courseId != null ) {
+        const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === this.msgForm.courseId);
+        for (let i = 0; i < this.setting.length; i++) {
+          //响应式直接给链接的标题/封面上值
+          if (selectedCourse && this.setting[i].contentType == 3 && this.msgForm.courseId != null) {
+            this.$set(this.setting[i], 'linkTitle', selectedCourse.dictLabel);
+            this.$set(this.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
+          }
+
+        }
+
+      }
+      videoList(this.msgForm.courseId).then(response => {
+        this.videoList=response.list;
+      });
+    },
+    handleSendMsg(row){
+      let chatList = row.chatId ? row.chatId.split(",") : [];
+      this.sendMsgOpen.id = row.id;
+      this.sendMsgOpen.row = row;
+      this.sendMsgOpen.chatIds = chatList;
+      this.msgForm.chatIds = chatList;
+      this.sendMsgOpen.open = true;
+    },
+    handleContentTypeChange() {
+
+      //如果是链接的才上
+      if (this.msgForm.courseId != null ) {
+        const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === this.msgForm.courseId);
+        for (let i = 0; i < this.setting.length; i++) {
+          //响应式直接给链接的标题/封面上值
+          if (selectedCourse && this.setting[i].contentType == 3 && this.msgForm.courseId != null) {
+            this.$set(this.setting[i], 'linkTitle', selectedCourse.dictLabel);
+            this.$set(this.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
+          }
+
+        }
+
+      }
+      if (this.msgForm.videoId != null ) {
+        // 查找选中的课节对应的 label
+        const selectedVideo = this.videoList.find(course => parseInt(course.dictValue) === this.msgForm.videoId);
+
+        for (let i = 0; i < this.setting.length; i++) {
+          //响应式直接给链接的描述上值
+          if (selectedVideo && this.setting[i].contentType == 3  && this.msgForm.videoId != null) {
+            this.$set(this.setting[i], 'linkDescribe', selectedVideo.dictLabel);
+          }
+        }
+      }
+    },
+    handleAvatarSuccessFile(res, file, item) {
+      if (res.code === 200) {
+        // 使用 $set 确保响应式更新
+        this.$set(item, 'fileUrl', res.url);
+      } else {
+        this.msgError(res.msg);
+      }
+    },
+    beforeAvatarUploadFile(file){
+      const isLt1M = file.size / 1024 / 1024 < 10;
+      if (!isLt1M) {
+        this.$message.error('上传大小不能超过 10MB!');
+      }
+      return isLt1M;
+    },
+    //下载文件
+    downloadUrl(materialUrl) {
+      // 直接返回文件 URL
+      return materialUrl;
+    },
+
+    handleAvatarSuccessVideo(res, file, item) {
+      if(res.code==200){
+        // 使用 $set 确保响应式更新
+        this.$set(item, 'videoUrl', res.url);
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
+
+    beforeAvatarUploadVideo(file){
+      const isLt30M = file.size / 1024 / 1024 < 10;
+      const isMP4 = file.type === 'video/mp4';
+
+      if (!isMP4) {
+        this.$message.error('仅支持上传 MP4 格式的视频文件!');
+        return false;
+      }
+
+      if (!isLt30M) {
+        this.$message.error('上传大小不能超过 10MB!');
+        return false;
+      }
+
+      return true;
+    },
+
+    handleInputVideoText(value,content){
+      // 允许的字符:中文、英文(大小写)、数字和指定标点符号(,。!?)
+      const regex = /^[\u4e00-\u9fa5,。!?,!?]+$/;
+
+      // 删除不符合条件的字符
+      const filteredValue = value.split('').filter(char => regex.test(char)).join('');
+
+      this.$set(content, 'value', filteredValue);
+
+    },
+    delSetList(index){
+      this.setting.splice(index,1)
+    },
+    addSetList(){
+      const newSetting = {
+        contentType:'1',
+        value: '',
+      };
+      // 将新设置项添加到 content.setting 数组中
+      this.setting.push(newSetting);
+
+    },
+    submitMsgForm(){
+      this.$refs["msgForm"].validate(valid => {
+        if (valid) {
+          this.msgForm.setting=JSON.stringify(this.setting)
+          this.msgForm.sopId=this.sendMsgOpen.row.id;
+          this.msgForm.filterMode=this.sendMsgOpen.row.filterMode;
+
+          if (this.setting.length <= 0) {
+            return this.$message.error("请添加规则")
+          }
+          if (this.msgForm.courseId===null || this.msgForm.courseId===''){
+            return this.$message.error("课程不能为空")
+          }
+
+          if (this.msgForm.videoId===null || this.msgForm.videoId===''){
+            return this.$message.error("课节不能为空")
+          }
+
+          if (this.msgForm.courseType===null || this.msgForm.courseType===''){
+            return this.$message.error("消息类型不能为空")
+          }
+
+          for (let i = 0; i < this.setting.length; i++) {
+            if (this.setting[i].contentType == 1 && (this.setting[i].value == null || this.setting[i].value == "")) {
+              return this.$message.error("内容不能为空")
+            }
+            if (this.setting[i].contentType == 2 && (this.setting[i].imgUrl == null || this.setting[i].imgUrl == "")) {
+              return this.$message.error("图片不能为空")
+            }
+            if (this.setting[i].contentType == 3 && (this.setting[i].linkTitle == null || this.setting[i].linkTitle == "")) {
+              return this.$message.error("链接标题不能为空")
+            }
+            if (this.setting[i].contentType == 3 && (this.setting[i].linkDescribe == null || this.setting[i].linkDescribe == "")) {
+              return this.$message.error("链接描述不能为空")
+            }
+            if (this.setting[i].contentType == 3 && (this.setting[i].linkImageUrl == null || this.setting[i].linkImageUrl == "")) {
+              return this.$message.error("链接图片不能为空")
+            }
+            if (this.setting[i].contentType == 3 && this.setting[i].type == 1 && (this.setting[i].linkUrl == null || this.setting[i].linkUrl == "")) {
+              return this.$message.error("链接地址不能为空")
+            }
+            if (this.setting[i].contentType == 5 && (this.setting[i].fileUrl == null || this.setting[i].fileUrl == "")) {
+              return this.$message.error("文件不能为空")
+            }
+            if (this.setting[i].contentType == 6 && (this.setting[i].videoUrl == null || this.setting[i].videoUrl == "")) {
+              return this.$message.error("视频不能为空")
+            }
+            if (this.setting[i].contentType == 7 && (this.setting[i].value == null || this.setting[i].value == "")) {
+              return this.$message.error("语音不能为空")
+            }
+          }
+
+          this.sendMsgOpen.open = false;
+
+          const loading = this.$loading({
+            lock: true,
+            text: '正在执行中请稍后~~请不要刷新页面!!',
+            spinner: 'el-icon-loading',
+            background: 'rgba(0, 0, 0, 0.7)'
+          });
+
+          sendMsgSop(this.msgForm).then(response => {
+            this.msgSuccess("一键群发成功");
+            loading.close();
+            this.setting=[];
+            this.msgForm = {
+              videoId:null,
+              courseId:null,
+              courseType:null,
+              setting:null,
+              isRegister:2,
+              sendType:1,
+              filterMode:2,
+
+            }
+            this.getList();
+          }).finally(()=>{
+            loading.close();
+          });
+
+        }
+      });
+    },
+    cancelMsgForm(){
+      this.sendMsgOpen.open = false;
+      this.resetSendMsgSop();
+    },
+    videoIdChange() {
+      if (this.msgForm.videoId != null ) {
+        // 查找选中的课节对应的 label
+        const selectedVideo = this.videoList.find(course => parseInt(course.dictValue) === this.msgForm.videoId);
+
+        for (let i = 0; i < this.setting.length; i++) {
+          //响应式直接给链接的描述上值
+          if (selectedVideo && this.setting[i].contentType == 3  && this.msgForm.videoId != null) {
+            this.$set(this.setting[i], 'linkDescribe', selectedVideo.dictLabel);
+          }
+        }
+      }
+    },
+  }
+};
+</script>
+<style scoped>
+.custom-input /deep/ .el-input__inner {
+  height: 20px;
+  padding: 0 4px;
+  text-align:center;
+  display: block;
+}
+.custom-input /deep/ .el-input__icon {
+  line-height: 20px;
+}
+.el-button--text{
+  cursor: pointer;
+}
+</style>

+ 1857 - 0
src/views/qw/sop/mySop.vue

@@ -0,0 +1,1857 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <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="qwUserIds">
+        <el-select v-model="queryParams.qwUserIds" filterable clearable placeholder="选择成员" size="small">
+          <el-option
+            v-for="dict in companyUserList"
+            :key="dict.id"
+            :label="dict.qwUserName"
+            :value="dict.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="规则编号" prop="id">
+        <el-input
+          v-model="queryParams.id"
+          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"  @change="updateCorpId()" >
+          <el-option
+            :key="1"
+            :label="'个微'"
+            :value="1"
+          />
+          <el-option
+            :key="2"
+            :label="'企微'"
+            :value="2"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="规则状态 " prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择规则状态" clearable size="small"  @change="updateCorpId()" >
+          <el-option
+            v-for="dict in sysSopStatus"
+            :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="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>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:sop:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['qw:sop:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:sop:export']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          size="mini"
+          plain
+          type="warning"
+          icon="el-icon-edit"
+          :disabled="multiple"
+          @click="handleExecute"
+          v-hasPermi="['qw:sop:execute']"
+        >批量执行SOP</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+    <el-table v-loading="loading" border :data="sopList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="规则编号" align="center" prop="id"  width="160"/>
+      <el-table-column label="规则名称" align="center" prop="name" width="150" />
+      <el-table-column label="规则状态" align="center" prop="status" width="150">
+        <template slot-scope="scope">
+          <dict-tag :options="sysSopStatus" :value="scope.row.status"></dict-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="类别" align="center" prop="type">
+        <template slot-scope="scope">
+          <el-tag type="success" v-if="scope.row.type==1">个微</el-tag>
+          <el-tag type="primary" v-else-if="scope.row.type==2">企微<span v-if="scope.row.filterMode == 2">(群聊)</span></el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="发送方式" align="center" prop="sendType">
+        <template slot-scope="scope">
+          <dict-tag :options="sysQwSopType" :value="scope.row.sendType"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="成员" align="center" prop="qwUserIds" width="150">
+        <template slot-scope="scope">
+          <!-- 点击事件绑定到整个 div -->
+          <div @click="toggleRow(scope.row)" v-if="scope.row.filterMode == 1">
+            <!-- 显示当前行的成员数量 -->
+            <span v-if="!expandedRows[scope.row.id]">
+            点击展开 ({{ scope.row.qwUserIds.split(',').length }} 人)
+          </span>
+            <!-- 展开时显示所有成员 -->
+            <div v-show="expandedRows[scope.row.id]">
+              <div v-if="scope.row.type==2" v-for="id in scope.row.qwUserIds.split(',')" :key="id"
+                   style="display: inline;" class="text-container">
+                <el-tag type="success" v-for="list in companyUserList" :key="list.qwUserId" style="margin: 3px;"
+                        v-if="list.id==id">
+                  {{ list.qwUserName }}
+                </el-tag>
+              </div>
+              <div v-if="scope.row.type==1" v-for="id in scope.row.qwUserIds.split(',')" :key="id"
+                   style="display: inline;" class="text-container">
+                <el-tag type="success" v-for="list in companyUserLists" :key="list.userId" style="margin: 3px;"
+                        v-if="list.userId==id">
+                  {{ list.nickName }}
+                </el-tag>
+              </div>
+            </div>
+          </div>
+          <div @click="toggleRow(scope.row)" v-if="scope.row.filterMode == 2">
+            <!-- 显示当前行的成员数量 -->
+            <span v-if="!expandedRows[scope.row.id]">
+            点击展开 ({{ scope.row.chatId.split(',').length }} 个)
+          </span>
+            <!-- 展开时显示所有成员 -->
+            <div v-show="expandedRows[scope.row.id]">
+              <div v-for="id in scope.row.chatId.split(',')" :key="id"
+                   style="display: inline;" class="text-container">
+                <el-tag type="success" v-for="list in chatList" :key="list.chatId" style="margin: 3px;"
+                        v-if="list.chatId == id">
+                  {{ list.name }}
+                </el-tag>
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="模板" align="center" prop="tempId" >
+        <template slot-scope="scope">
+            <div v-for="id in tempList" v-if="id.id==scope.row.tempId">{{id.name}}</div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="新客户自动创建sop" align="center" prop="isAutoSop" width="140">
+        <template slot-scope="scope">
+          <el-switch
+            v-if="scope.row.sendType==2 || scope.row.sendType==4"
+            v-model="scope.row.isAutoSop"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            :active-value="1"
+            :inactive-value="2"
+            @change="switchAutoSopChange(scope.row,scope.row.isAutoSop)">
+          </el-switch>
+          <span v-if="scope.row.sendType!=1 && scope.row.isAutoSop == '1'" style="margin-left: 10px;color: #13ce66">已开启</span>
+          <span v-if="scope.row.sendType!=1 && scope.row.isAutoSop == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
+          <span v-if="scope.row.sendType==1" style="margin-left: 10px;color: rgb(250,114,3)">企微接口无法设置</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="过期时间" align="center" prop="expiryTime" >
+        <template slot-scope="scope">
+          {{scope.row.expiryTime}} 小时
+        </template>
+      </el-table-column>
+      <el-table-column label="创建人" align="center" prop="createBy" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="修改规则状态时间" align="center" prop="stopTime" width="180"/>
+      <el-table-column label="查看操作" align="center" class-name="small-padding fixed-width"  width="200" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            v-if="scope.row.status==2||scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4 "
+            size="mini"
+            type="text"
+            @click="selectSchedule(scope.row)"
+            v-hasPermi="['qw:sop:list']"
+          >营期</el-button>
+          <el-button
+            v-if="scope.row.status==2 || scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4  "
+            size="mini"
+            type="text"
+            style="color: green;"
+            @click="handleScheduleDetail(scope.row)"
+            v-hasPermi="['qw:sop:list']"
+          >执行详情</el-button>
+          <el-button
+            v-if="scope.row.status==2 || scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4  "
+            size="mini"
+            type="text"
+            @click="handleUpdate(scope.row,2)"
+            v-hasPermi="['qw:sop:edit']"
+          >查看规则</el-button>
+          <el-button
+            v-if="scope.row.status==2 || scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4  "
+            size="mini"
+            type="text"
+            style="color: green;"
+            @click="handleQueryDetails(scope.row)"
+            v-hasPermi="['qw:sop:list']"
+          >查看模板</el-button>
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            @click="voice(scope.row.id)"-->
+<!--          >语音</el-button>-->
+
+        </template>
+      </el-table-column>
+      <el-table-column label="修改操作" align="center" class-name="small-padding fixed-width"  width="100px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleUpdateOutTime(scope.row)"
+          >修改规则</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-if="scope.row.filterMode == 2 && (scope.row.status==2||scope.row.status==0 || scope.row.status == 3 || scope.row.status == 4)"
+            @click="handleSendMsg(scope.row)"
+          >一键发群
+          </el-button>
+          <el-button
+            v-if="scope.row.status == 1  "
+            size="mini"
+            type="text"
+            @click="handleUpdate(scope.row,1)"
+            v-hasPermi="['qw:sop:edit']"
+          >修改规则</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            style="color: red;"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:sop:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改企微sop对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="规则名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入规则名称" />
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="parseInt(dict.dictValue)"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+         <el-form-item label="类别" prop="type">
+         <el-radio-group v-model="form.type">
+             <el-radio
+               :label="1"
+             >个微</el-radio>
+             <el-radio
+               :label="2"
+             >企微</el-radio>
+         </el-radio-group>
+         </el-form-item>
+
+<!--        <div v-if="form.type==2">-->
+
+<!--        <el-form-item label="推送方式 ">-->
+<!--          <el-radio-group v-model="form.sendType" @input="handleSendTypeChange">-->
+<!--            <el-radio-->
+<!--              v-for="dict in sysQwSopType"-->
+<!--              :key="dict.dictValue"-->
+<!--              :label="parseInt(dict.dictValue)"-->
+<!--            >{{dict.dictLabel}}</el-radio>-->
+<!--          </el-radio-group>-->
+<!--        </el-form-item>-->
+<!--          <el-form-item label="选择员工" prop="qwUserIds" style="margin-top: 2%">-->
+<!--            <div>-->
+<!--              <el-button-->
+<!--                size="medium"-->
+<!--                icon="el-icon-circle-plus-outline"-->
+<!--                plain-->
+<!--                @click="handlelistUser(form.type,form.sendType)">请选择使用员工</el-button>-->
+<!--            </div>-->
+<!--            <div>-->
+<!--              <el-tag-->
+<!--                style="margin-left: 5px"-->
+<!--                size="medium"-->
+<!--                :key="id"-->
+<!--                v-for="id in userSelectList"-->
+<!--                closable-->
+<!--                :disable-transitions="false"-->
+<!--                @close="handleClosegroupUser(id)">-->
+<!--                <span v-for="list in companyUserList" :key="list.qwUserId" v-if="list.id==id">{{list.qwUserName}}</span>-->
+<!--              </el-tag>-->
+<!--            </div>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="标签规则" prop="filterType">-->
+<!--            <el-radio-group v-model="form.filterType">-->
+<!--              <el-radio-->
+<!--                :label="1"-->
+<!--              >含全部标签</el-radio>-->
+<!--              <el-radio-->
+<!--                :label="2"-->
+<!--              >含任意标签</el-radio>-->
+<!--            </el-radio-group>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="选择的标签" prop="tags">-->
+<!--            <el-select v-model="tags" 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="excludeTags">-->
+<!--            <el-select v-model="excludeTags" 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>-->
+<!--        </div>-->
+<!--        <div v-if="form.type==1">-->
+<!--          <el-form-item label="推送方式 ">-->
+<!--            <el-tag type="success" v-model="form.sendType=2">AI插件</el-tag>-->
+<!--          </el-form-item>-->
+<!--        </div>-->
+
+        <el-form-item label="开始时间" prop="startTime">
+          <el-date-picker clearable size="small"
+            v-model="form.startTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择开始时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="模板" prop="tempId">
+          <el-select v-model="form.tempId"  @focus="selectListSopTemp(form.sendType)" placeholder="请选择模板" v-loading="tempListLoading"   >
+            <el-option
+              v-for="dict in tempList"
+              :label="dict.name"
+              :value="dict.id">
+            </el-option>
+            <div v-if="tempListLoading" slot="prefix" class="select-prefix">正在查询相应模板...</div>
+          </el-select>
+        </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>
+    <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="1300px"  append-to-body>
+      <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
+    </el-dialog>
+
+    <!-- 单独的修改时间   -->
+    <el-dialog :title="outTimeOpen.title" :visible.sync="outTimeOpen.open" width="500px">
+
+       <el-row>
+
+         <el-col style="margin-top: 3%">
+           <span>过期时间:</span>
+           <el-input-number  v-model="outTimeOpen.expiryTime"  :min="1" :max="100" ></el-input-number>
+           (小时)
+         </el-col>
+
+         <el-col  style="margin-top: 3%">
+           <span>是否开启客户评级:</span>
+             <el-switch
+               v-model="outTimeOpen.isRating"
+               active-color="#13ce66"
+               inactive-color="#ff4949"
+               :active-value="1"
+               :inactive-value="2">
+             </el-switch>
+             <span v-if="outTimeOpen.isRating == '1'" style="margin-left: 10px;color: #13ce66">已开启</span>
+             <span v-if="outTimeOpen.isRating == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
+         </el-col>
+         <el-col style="margin-top: 3%">
+           <span>小转天数:</span>
+           <el-input-number  v-model="outTimeOpen.minConversionDay"></el-input-number>
+           (天)
+         </el-col>
+         <el-col style="margin-top: 3%">
+           <span>大转天数:</span>
+           <el-input-number  v-model="outTimeOpen.maxConversionDay"></el-input-number>
+           (天)
+         </el-col>
+         <el-col style="margin-top: 3%">
+           <span>发课开始天数:</span>
+           <el-input-number  v-model="outTimeOpen.courseDay"  :min="1" :max="100" ></el-input-number>
+           (天)
+           <div style="color: #999;font-size: 14px;display: flex;align-items: center;margin-top: 2%">
+             <i class="el-icon-info"></i>
+             作用于【催课看板】和【看课记录】的统计,由多少天开始计算。比如 模板里 第一天是先导课,第二天是正课,此处设置天数为2,则统计从第二天开始。如果无视模板天数,此处设置几天,则统计面板就从第几天开始统计
+           </div>
+         </el-col>
+         <el-col style="margin-top: 3%">
+           <el-card>
+             <el-radio-group v-model="outTimeOpen.isSampSend">
+               <el-row :gutter="20">
+                 <el-col>
+                   <el-radio
+                     border size="medium"
+                     :label="1"
+                     style="font-size: 16px; margin: 10px 0;font-weight: bold"
+                   >【官方群发】 按照【营期+插件补发】的形式发</el-radio>
+                   <div style="color: #999;font-size: 14px;display: flex;align-items: center;margin-top: 2%;margin-left: 3%">
+                     <i class="el-icon-question"></i>
+                     按照一个营期一个通用链接的形式,仅【营期详情】中(官方群发许可)为【是】的能用于官方群发,为【否】的按照 【sop插件】补发(ps:未注册用户全部不走官方群发,早上5点统一任务补发(官方群发的较少,补发及时))
+                   </div>
+                 </el-col>
+                 <el-col>
+                   <el-radio
+                     border size="medium"
+                     :label="2"
+                     style="font-size: 16px; margin: 10px 0;font-weight: bold"
+                   >【官方群发】 按照【营期+官方单链】的形式发</el-radio>
+                   <div style="color: #999;font-size: 14px;display: flex;align-items: center;margin-top: 2%;margin-left: 3%">
+                     <i class="el-icon-question"></i>
+                     按照一个营期一个通用链接的形式,仅【营期详情】中(官方群发许可)为【是】的能用于官方群发,为【否】的按照 【官方一对一链接】(ps:未注册用户也走官方群发,7点开始查询补发(官方群发较多,补发相对不及时))
+                   </div>
+                 </el-col>
+
+               </el-row>
+             </el-radio-group>
+           </el-card>
+         </el-col>
+         <el-row style="margin-top: 3%" >
+
+           <el-button type="primary" icon="el-icon-search" size="mini" @click="handleUpdateExpiryTime">确定修改</el-button>
+           <el-button icon="el-icon-refresh" size="mini" @click="resetUpdateExpiryTime">取消</el-button>
+         </el-row>
+
+
+       </el-row>
+    </el-dialog>
+    <!-- 单独的修改时间   -->
+    <el-dialog title="语音记录" :visible.sync="voiceForm.open" width="70%" append-to-body>
+      <el-row style="height: 600px">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:sop:add']"
+        >新增</el-button>
+        <el-table border :data="voiceForm.list">
+          <el-table-column label="员工" align="center" prop="companyUserName" />
+          <el-table-column label="名称" align="center" prop="name" />
+          <el-table-column label="天数" align="center" prop="dayNum">
+            <template slot-scope="scope">
+              第{{scope.row.dayNum}}天
+            </template>
+          </el-table-column>
+          <el-table-column label="发送时间" align="center" prop="time" />
+          <el-table-column label="语音文本" align="center" prop="voiceTxt" />
+          <el-table-column label="语音时长" align="center" prop="duration">
+            <template slot-scope="scope">
+              {{scope.row.duration}}秒
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+          v-show="voiceForm.total>0"
+          :total="voiceForm.total"
+          :page.sync="voiceForm.queryParams.pageNum"
+          :limit.sync="voiceForm.queryParams.pageSize"
+          @pagination="voice(voiceForm.queryParams.id)"
+        />
+      </el-row>
+    </el-dialog>
+
+    <el-dialog :title="autoSopOpen.title" :visible.sync="autoSopOpen.open" width="1300px"  append-to-body>
+        <el-form ref="autoSopTimeFrom" :model="form.autoSopTime" :rules="autoSopTimeRules">
+          <el-form-item label="自动类型" prop="type"     style="margin: 2%; display: flex; align-items: center;">
+            <el-radio-group v-model="form.autoSopTime.autoSopType">
+              <el-radio
+                :label="1"
+              >当天开始</el-radio>
+              <el-radio
+                :label="2"
+              >次日开始</el-radio>
+              <el-radio
+                :label="3"
+              >分营期开始(正课)</el-radio>
+              <el-radio
+                :label="4"
+              >分营期开始(先导)</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <div style="display: flex; align-items: center; flex-wrap: nowrap;">
+            <div v-if="form.autoSopTime.autoSopType==1" style="display: flex; align-items: center">
+              <el-form-item
+                label="起始时间"
+                prop="autoStartTime"
+                label-width="100px"
+                style="margin: 2% 0;align-items: center;">
+                <el-time-select
+                  style="width: 120px;"
+                  placeholder="起始时间"
+                  v-model="form.autoSopTime.autoStartTime"
+                  :picker-options="{
+                  start: '00:00',
+                  step: '00:15',
+                  end: '24:00'
+                }">
+                </el-time-select>
+              </el-form-item>
+              <el-form-item
+                label="结束时间"
+                prop="autoEndTime"
+                label-width="100px"
+                style="margin: 2% 0; align-items: center; ">
+                <el-time-select
+                  style="width: 120px;"
+                  placeholder="结束时间"
+                  v-model="form.autoSopTime.autoEndTime"
+                  :picker-options="{
+                  start: '00:00',
+                  step: '00:15',
+                  end: '24:00',
+                  minTime: form.autoSopTime.autoEndTime
+                }">
+                </el-time-select>
+              </el-form-item>
+            </div>
+          </div>
+          <el-form-item  v-if="form.autoSopTime.autoSopType==1" label="过期消息是否发送" prop="autoSopSend"     style="margin: 2%; display: flex; align-items: center;">
+            <el-radio-group v-model="form.autoSopTime.autoSopSend">
+              <el-radio
+                :label="1"
+              >是</el-radio>
+              <el-radio
+                :label="2"
+              >否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+
+          <div style="display: flex; align-items: center; flex-wrap: nowrap;" v-if="form.autoSopTime.autoSopType==3 || form.autoSopTime.autoSopType==4">
+            <el-form-item
+              label="选择一个或多个日期"
+              prop="autoDateTime"
+              label-width="150px">
+              <el-date-picker
+                size="large"
+                type="dates"
+                style="width: 600px"
+                v-model="form.autoSopTime.autoDateTime"
+                value-format="yyyy-MM-dd"
+                placeholder="选择一个或多个日期【ps:请先选择开始时间,不得小于任务开始时间】"
+                @change="sortSelectedDates(form.autoSopTime.autoDateTime)"
+                :disabled="!form.startTime">
+              </el-date-picker>
+            </el-form-item>
+          </div>
+
+
+          <el-alert
+            v-if="form.autoSopTime.autoSopType==1"
+            title="起始时间-结束时间之内的,当天立即创建SOP,时间之外的 次日创建SOP"
+            type="warning"
+            style="font-size: 30px; margin-top: 3%;"
+            :closable="false"
+            show-icon>
+          </el-alert>
+          <el-alert
+            v-if="form.autoSopTime.autoSopType==3"
+            type="warning"
+            style="margin-top: 3%;"
+            :closable="false"
+            show-icon>
+            <template #title>
+              <span style="font-size: 23px; line-height: 1.5;">
+                  此功能用于正课区分营期,可以选择你想要开始营期的具体时间,选择后在此期间添加的用户将会自动进入对应营期。
+                  例如今天1月1日,选择时间是1月1日,1月5日,1月10日。
+                  用户1月1日-1月4日添加(添加上对应标签)则会进入1月5日的营期,1月5日-1月9日添加则会进入1月10日营期,1月5日自动给用户发送第一节课程
+              </span>
+            </template>
+          </el-alert>
+          <el-alert
+            v-if="form.autoSopTime.autoSopType==4"
+            title=""
+            type="warning"
+            style="font-size: 30px; margin-top: 3%;"
+            :closable="false"
+            show-icon>
+            <template #title>
+              <span style="font-size: 23px; line-height: 1.5;">
+                    此功能用于先导课区分营期,可以选择先导课开始营期的具体时间,选择后在此期间添加的用户将会自动进入对应营期。
+                    例如今天1月1日,选择时间是1月1日,1月5日,1月10日。
+                    用户1月1日-1月4日添加(添加上对应标签)则会进入1月1日的营期,1月5日-1月9日添加则会进入1月5日营期,自动给用户匹配上对应应该听到天数的时间节点
+              </span>
+            </template>
+          </el-alert>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click="submitAutoSopTimeFrom">确 定</el-button>
+          <el-button @click="cancelAutoSopTime">取 消</el-button>
+        </div>
+    </el-dialog>
+    <!--  执行详情  -->
+    <el-drawer :title="sopLogsDialog.title" :visible.sync="sopLogsDialog.open" size="85%" style="font-weight: bolder">
+      <sopLogsDetails ref="sopLogsDetails" :rowDetailFrom="sopLogsDialog.sopLogsForm"></sopLogsDetails>
+    </el-drawer>
+    <el-dialog :title="sendMsgOpen.title" :visible.sync="sendMsgOpen.open"  width="1000px" append-to-body>
+      <el-form ref="msgForm" :model="msgForm" :rules="msgRules" label-width="100px">
+        <el-form-item label="群">
+          <el-select  v-model="msgForm.chatIds" placeholder="请选择群" size="mini" multiple>
+            <el-option
+              v-for="chatId in sendMsgOpen.chatIds"
+              :key="chatId"
+              :label="chatList.filter(e => e.chatId == chatId) && chatList.filter(e => e.chatId == chatId).length > 0 ? chatList.filter(e => e.chatId == chatId)[0].name : ''"
+              :value="chatId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="发送类型">
+          <el-radio-group v-model="msgForm.sendType">
+            <el-radio :label="1">群</el-radio>
+            <el-radio :label="2">群成员</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="选择课程">
+          <el-select  v-model="msgForm.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange()">
+            <el-option
+              v-for="dict in courseList"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            />
+          </el-select>
+          <el-select  v-model="msgForm.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange()"  >
+            <el-option
+              v-for="dict in videoList"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            />
+          </el-select>
+          <el-select  v-model="msgForm.courseType" placeholder="请选择消息类型" size="mini" style=" margin-right: 10px;">
+            <el-option
+              v-for="dict in sysFsSopWatchStatus"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="规则" prop="setting"  >
+          <div v-for="(item, index) in setting" :key="index" style="background-color: #fdfdfd; border: 1px solid #e6e6e6; margin-bottom: 20px;">
+            <el-row>
+              <el-col :span="22">
+                <el-form :model="item" label-width="70px">
+                  <el-form-item label="内容类别" style="margin: 2%">
+                    <el-radio-group  v-model="item.contentType">
+                      <el-radio   :label="item.dictValue" v-for="item in sysQwSopAiContentType"  @change="handleContentTypeChange()">{{item.dictLabel}}</el-radio>
+                    </el-radio-group>
+                  </el-form-item>
+                  <el-form-item label="内容" style="margin-bottom: 2%" >
+                    <el-input v-if="item.contentType == 1 " v-model="item.value" type="textarea" :rows="3" placeholder="内容" style="width: 90%;margin-top: 10px;"/>
+
+                    <ImageUpload v-if="item.contentType == 2 " v-model="item.imgUrl" type="image" :num="1"  :width="150" :height="150" />
+
+                    <div v-if="item.contentType == 3 ">
+                      <el-card class="box-card">
+                        <el-form-item label="链接标题:"  label-width="100px">
+                          <el-input v-model="item.linkTitle" placeholder="请输入链接标题" style="width: 90%;"/>
+                        </el-form-item>
+                        <el-form-item label="链接描述:"   label-width="100px" >
+                          <el-input type="textarea" :rows="3" v-model="item.linkDescribe" placeholder="请输入链接描述" style="width: 90%;margin-top: 1%;"/>
+                        </el-form-item>
+                        <el-form-item label="链接封面:"   label-width="100px">
+                          <ImageUpload v-model="item.linkImageUrl" type="image" :num="1" :file-size="2" :width="150" :height="150" style="margin-top: 1%;" />
+                        </el-form-item>
+                        <el-form-item label="链接地址:"  label-width="100px" >
+                          <el-tag type="warning" v-model="item.isBindUrl=1">选择的课程小节 即为卡片链接地址</el-tag>
+                        </el-form-item>
+                      </el-card>
+                    </div>
+                    <div v-if="item.contentType == 4">
+
+                    </div>
+                    <div v-if="item.contentType == 5 ">
+
+                      <el-form-item label="上传文件:" prop="fileUrl" label-width="100px">
+                        <el-upload
+                          v-model="item.fileUrl"
+                          class="avatar-uploader"
+                          :action="uploadUrl"
+                          :show-file-list="false"
+                          :on-success="(res, file) => handleAvatarSuccessFile(res, file, item)"
+                          :before-upload="beforeAvatarUploadFile">
+                          <i class="el-icon-plus avatar-uploader-icon"></i>
+                        </el-upload>
+                        <el-link v-if="item.fileUrl" type="primary" :href="downloadUrl(item.fileUrl)" download>
+                          {{item.fileUrl}}
+                        </el-link>
+                      </el-form-item>
+
+                    </div>
+
+                    <div v-if="item.contentType == 6 ">
+                      <el-form-item label="上传视频:" prop="videoUrl" label-width="100px">
+                        <el-upload
+                          v-model="item.videoUrl"
+                          class="avatar-uploader"
+                          :action="uploadUrl"
+                          :show-file-list="false"
+                          :on-success="(res, file) => handleAvatarSuccessVideo(res, file, item)"
+                          :before-upload="beforeAvatarUploadVideo">
+                          <i class="el-icon-plus avatar-uploader-icon"></i>
+                        </el-upload>
+                        <video v-if="item.videoUrl"
+                               :src="item.videoUrl"
+                               controls style="width: 200px;height: 100px">
+                        </video>
+                      </el-form-item>
+                    </div>
+                    <div v-if="item.contentType == 7 ">
+                      <el-input
+                        v-model="item.value"
+                        type="textarea" :rows="3" maxlength="66" show-word-limit
+                        placeholder="输入要转为语音的内容" style="width: 90%;margin-top: 10px;"
+                        @input="handleInputVideoText(item.value,item)"/>
+                    </div>
+
+                    <div v-if="item.contentType == 10 ">
+                      <el-card class="box-card">
+                        <el-form-item label="链接标题:"  label-width="100px">
+                          <el-input v-model="item.linkTitle" placeholder="请输入链接标题" style="width: 90%;"/>
+                        </el-form-item>
+                        <el-form-item label="链接描述:"   label-width="100px" >
+                          <el-input type="textarea" :rows="3" v-model="item.linkDescribe" placeholder="请输入链接描述" style="width: 90%;margin-top: 1%;"/>
+                        </el-form-item>
+                        <el-form-item label="链接封面:"   label-width="100px">
+                          <ImageUpload v-model="item.linkImageUrl" type="image" :num="1" :file-size="2" :width="150" :height="150" style="margin-top: 1%;" />
+                        </el-form-item>
+                        <el-form-item label="链接地址:"  label-width="100px" >
+                          <el-tag type="warning" >链接地址自动生成</el-tag>
+                        </el-form-item>
+                      </el-card>
+                    </div>
+                  </el-form-item>
+
+                  <el-form-item label="添加短链" v-if="item.contentType == 1 "  >
+                    <el-tooltip content="请先根据课程选定课程小节之后再添加" effect="dark" :disabled="!!msgForm.videoId">
+                      <el-switch
+                        v-model="item.isBindUrl"
+                        :disabled="!msgForm.videoId"
+                        active-color="#13ce66"
+                        inactive-color="#DCDFE6"
+                        active-value="1"
+                        inactive-value="2">
+                      </el-switch>
+                    </el-tooltip>
+
+                    <span v-if="item.isBindUrl == '1'" style="margin-left: 10px; color: #13ce66">添加URL</span>
+                    <span v-if="item.isBindUrl == '2'" style="margin-left: 10px; color: #b1b4ba">不加URL</span>
+                  </el-form-item>
+                  <el-form-item label="课节过期时间" v-if="item.isBindUrl == '1'
+                                                          && item.contentType != 2
+                                                          && item.contentType != 5
+                                                          && item.contentType != 6
+                                                          && item.contentType != 8
+                                                          && item.contentType != 9
+                                                          && item.contentType != 10"
+                                style="margin-top: 1%" label-width="100px">
+                    <el-row>
+                      <el-input-number  v-model="item.expiresDays"  :min="1" :max="100" ></el-input-number>
+                      (天)
+                    </el-row>
+                    <el-row>
+                      <span class="tip">填写0或不填时,默认为系统配置的默认时间</span>
+                    </el-row>
+                  </el-form-item>
+                </el-form>
+              </el-col>
+              <el-col :span="1" :offset="1">
+                <i class="el-icon-delete" @click="delSetList(index)" style="margin-top: 20px;" v-if="setting.length>1"></i>
+              </el-col>
+            </el-row>
+          </div>
+          <el-link type="primary" class="el-icon-plus" :underline="false" @click='addSetList()'  >添加内容</el-link>
+
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitMsgForm">确 定</el-button>
+        <el-button @click="cancelMsgForm">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listMySop,
+  addSop,
+  courseList,
+  videoList,
+  delSop,
+  exportSop,
+  getSopVoiceList,
+  listSop,
+  updateAutoSopTime,
+  updateSop,
+  updateSopStatus,
+  updateStatus
+} from "@/api/qw/sop";
+import {listSopTemp} from "@/api/qw/sopTemp";
+import {getQwAllUserList, listUser} from '@/api/company/companyUser'
+import qwUserList from '@/views/qw/user/qwUserList.vue'
+import ImageUpload from "@/views/qw/sop/ImageUpload";
+import CustomerGroupDetails from '@/views/qw/groupMsg/customerGroupDetails.vue'
+import sopLogsDetails from '@/views/qw/sopLogs/sopLogsList.vue'
+import {listTag,} from "@/api/qw/tag";
+import {sendMsgSop} from "@/api/qw/sopUserLogsInfo";
+import {getMyQwCompanyList} from "@/api/qw/user";
+import {allList} from "@/api/qw/groupChat";
+
+export default {
+  name: "Sop",
+    components: { CustomerGroupDetails, qwUserList,ImageUpload,sopLogsDetails},
+  data() {
+    return {
+      // 存储每一行的展开状态
+      expandedRows: {},
+      //模板查询
+      tempListLoading:false,
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      //选中的map
+      selectionMap:{},
+      myQwCompanyList:[],
+      //销售员工列表
+      companyUserLists:[],
+      videoList:[],
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      uploadUrlByVoice:process.env.VUE_APP_BASE_API+"/common/uploadOSSByHOOKVoice",
+      msgForm:{
+        videoId:null,
+        courseId:null,
+        courseType:null,
+        userIdParam:null,
+        sendType:1,
+        setting:null,
+        ids:null,
+        sopId: null,
+        startTime: null,
+        chatIds: [],
+        isRegister:2
+      },
+      sendMsgOpen:{
+        title:'一键批量群发',
+        open:false,
+        row: {},
+        ids:null,
+      },
+      msgRules:{},
+      courseList:[],
+      // videoList:[],
+      tags:null,
+      excludeTags:null,
+      // 非单个禁用
+      single: true,
+      setting:[],
+      tagList:[],
+      tempList:[],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企微sop表格数据
+      sopList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      companyUserList:[],
+      // 状态字典
+      statusOptions: [],
+      //sop状态
+      sysSopStatus: [],
+
+      autoSopOpen:{
+        title:'',
+        open:false,
+        id:null,
+        isAutoSop:null,
+      },
+      outTimeOpen:{
+        title:'',
+        open:false,
+        id:null,
+        tempId:null,
+        expiryTime:null,
+        isRating:null,
+        isSampSend:null,
+      },
+      voiceForm:{
+        list:[],
+        open:false,
+        total:0,
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          id: null,
+        },
+      },
+
+      //企微SOP发送类型
+      sysQwSopType: [],
+      chatList: [],
+
+      //SOP课程观看状态
+      sysFsSopWatchStatus:[],
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        id: null,
+        name: null,
+        status: null,
+        sendType:null,
+        type: null,
+        qwUserIds: null,
+        setting: null,
+        createBy: null,
+        corpId: null,
+        createTime: null
+      },
+      sopLogsDialog:{
+        title:'',
+        open:false,
+        sopLogsForm:[],
+      },
+      // 表单参数
+      form: {
+        autoSopTime:{ autoSopType:2,autoStartTime:'00:00',autoEndTime:'24:00',autoSopSend:2,autoDateTime:[]},
+      },
+      userSelectList:[],
+      listUser:{
+        title:"",
+        open:false
+      },
+      // 表单校验
+      rules: {
+        name:[ { required: true, message: "名称不能为空", trigger: "submit" }],
+        type:[ { required: true, message: "不能为空", trigger: "submit" }],
+        sendType:[ { required: true, message: "不能为空", trigger: "submit" }],
+        startTime:[ { required: true, message: "开始时间不能为空", trigger: "submit" }],
+        tempId:[ { required: true, message: "模板不能为空", trigger: "submit" }],
+      },
+      autoSopTimeRules:{
+        autoSopType:[ { required: true, message: "选项不能为空", trigger: "submit" }],
+        autoStartTime:[ { required: true, message: "起始时间不能为空", trigger: "submit" }],
+        autoEndTime:[ { required: true, message: "结束时间不能为空", trigger: "submit" }],
+        autoDateTime:[ { required: true, message: "日期不能为空", trigger: "submit" }],
+      }
+    };
+  },
+  created() {
+
+    this.getDicts("sys_sop_status").then(response => {
+      this.sysSopStatus = response.data;
+    });
+
+
+    this.getDicts("sys_qwSopAi_contentType").then(response => {
+      this.sysQwSopAiContentType = response.data;
+    });
+    this.getDicts("sys_fs_sop_watch_status").then(response => {
+      this.sysFsSopWatchStatus = response.data;
+    });
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_type").then(response => {
+      this.sysQwSopType = response.data;
+    });
+
+
+    listUser().then(res => {
+        this.companyUserLists = res.rows;
+      }
+    );
+
+    courseList().then(response => {
+      this.courseList = response.list;
+    });
+
+
+    getMyQwCompanyList().then(response => {
+      this.myQwCompanyList = response.data;
+      if(this.myQwCompanyList!=null){
+        this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+        this.refreshData(this.queryParams.corpId);
+        this.getList();
+      }
+    });
+
+
+
+  },
+  watch:{
+    userSelectList(newList) {
+      this.form.qwUserIds = newList.map(item => item.id);
+    }
+  },
+  methods: {
+    voice(id){
+      this.voiceForm.queryParams.id = id;
+      getSopVoiceList(this.voiceForm.queryParams).then(res => {
+        this.voiceForm.list = res.rows;
+        this.voiceForm.total = res.total;
+        this.voiceForm.open = true;
+      })
+    },
+    // 单元格点击事件
+    handleCellClick(row, column, cell, event) {
+      // 判断是否为规则编号列
+      if (column.property === 'id') {
+        this.handleRowClick(row); // 触发规则编号点击事件
+      }
+    },
+    // handleUpdateTags(){
+    //
+    // },
+    // handleUpdateQwUser(){
+    //
+    // },
+    // handleUpdateSopTemp(){
+    //
+    // },
+    handleRowClick(row, column, event) {
+      // 判断状态是否符合条件
+      if (row.status == 2 || row.status == 0 || row.status == 3 || row.status == 4) {
+        this.handleUpdate(row, 2);
+      }
+    },
+    // 切换某一行的展开状态
+    toggleRow(row) {
+      this.$set(this.expandedRows, row.id, !this.expandedRows[row.id]);
+    },
+    getSwitchVal(status) {
+      return [2, 3, 4].includes(status) ? 2 : 0;
+    },
+
+    onSwitchChange(row, val) {
+      this.loading=true;
+      // ① 调用接口更新后端
+      updateSopStatus({ id: row.id, status: val })
+        .then(() => {
+          row.status = val;
+          this.loading=false;
+          this.$message.success("切换成功!");
+        })
+        .catch(() => {
+          this.loading=false;
+          this.$message.error("操作失败,请重试");
+        });
+    },
+
+    switchSopStatusChange(row,checked){
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '暂停中-请勿刷新页面-重复点击',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      updateSopStatus({id:row,status:checked}).then(response => {
+        this.$message.success("修改成功");
+        this.getList();
+      }).finally(res=>{
+        loadingRock.close();
+      })
+
+
+    },
+
+    //新客户自动创建sop
+    switchAutoSopChange(row,checked){
+
+      this.form.startTime=row.startTime;
+      this.form.autoSopTime=JSON.parse(row.autoSopTime);
+
+      if (checked==1) {
+        this.autoSopOpen.title='请设置相应时间段'
+        this.autoSopOpen.open=true;
+        this.autoSopOpen.id=row.id;
+        this.autoSopOpen.isAutoSop=1;
+      }else {
+        this.form.autoSopTime.createTime=this.formatDateTo24HourString(new Date());
+        updateAutoSopTime({id:row.id,isAutoSop:checked,autoSopTime: JSON.stringify(this.form.autoSopTime)}).then(response => {
+          this.getList();
+        })
+      }
+
+
+    },
+     updateCorpId(){
+       this.reset();
+       this.refreshData(this.queryParams.corpId);
+       this.queryParams.qwUserId = null;
+       this.getList();
+     },
+
+    //刷新部分数据
+    refreshData(row){
+      getQwAllUserList(row).then(response => {
+        this.companyUserList = response.data;
+      });
+
+      listTag({corpId:row}).then(response => {
+        this.tagList = response.rows;
+      });
+
+      if (row != null) {
+        allList(row).then(e => {
+          this.chatList = e.data;
+        })
+      }
+    },
+
+    //查询模板
+    selectListSopTemp(type){
+      this.tempListLoading = true; // 开始查询,显示加载提示
+      listSopTemp({sendType:type}).then(response => {
+        this.tempList = response.rows;
+        this.tempListLoading = false;
+      });
+    },
+    handlelistUser(type,sendType){
+
+       setTimeout(() => {
+         this.$refs.QwUserList.getDetails(this.queryParams.corpId,type,sendType);
+       }, 1);
+       this.listUser.title="选择企业成员"
+       this.listUser.open=true;
+
+    },
+    selectUserList(list){
+      this.listUser.open=false;
+      list.forEach(obj => {
+        if (!this.userSelectList.some(item => item == obj.id)) {
+          this.userSelectList.push(obj.id);
+        }
+      });
+
+    },
+
+    //修改过期时间
+    handleUpdateOutTime(val){
+        this.outTimeOpen.title="修改过期时间/评级";
+        this.outTimeOpen.id=val.id;
+        this.outTimeOpen.tempId=val.tempId;
+        this.outTimeOpen.expiryTime=val.expiryTime;
+        this.outTimeOpen.isRating=val.isRating;
+        this.outTimeOpen.minConversionDay=val.minConversionDay;
+        this.outTimeOpen.maxConversionDay=val.maxConversionDay;
+        this.outTimeOpen.courseDay=val.courseDay;
+        this.outTimeOpen.isSampSend=val.isSampSend;
+        this.outTimeOpen.open=true;
+    },
+
+    handleUpdateExpiryTime(){
+      updateSop({id:this.outTimeOpen.id,tempId:this.outTimeOpen.tempId,expiryTime:this.outTimeOpen.expiryTime,
+        isRating: this.outTimeOpen.isRating,minConversionDay: this.outTimeOpen.minConversionDay,maxConversionDay: this.outTimeOpen.maxConversionDay,
+        courseDay: this.outTimeOpen.courseDay,isSampSend:this.outTimeOpen.isSampSend}).then(response => {
+        this.msgSuccess("修改成功");
+        this.resetUpdateExpiryTime()
+        this.getList();
+      });
+    },
+    resetUpdateExpiryTime(){
+      this.outTimeOpen={
+          title:'',
+          open:false,
+          id:null,
+          expiryTime:null,
+          courseDay:null,
+          minConversionDay:null,
+          maxConversionDay:null,
+          isRating:null,
+          isSampSend:null,
+      }
+    },
+    addContent(index){
+      // this.setting[index].content.push({type:1})
+      if (this.form.sendType==2){
+        this.setting[index].content.push({ type: 1 });
+      }else {
+        if (this.setting[index].content.length < 9) {
+          this.setting[index].content.push({ type: 1 });
+        } else {
+          this.$message({
+            message: '最多只能添加 9 个内容',
+            type: 'warning'
+          });
+        }
+      }
+
+    },
+
+    //选择变动时的变动
+    handleSendTypeChange(val){
+      this.tempList=[];
+      this.form.tempId=null;
+      if (val==1) {
+        // 遍历 this.setting 数组并清空每个对象的 content 属性
+        this.setting.forEach(item => {
+          if (item.content.length > 9) {
+            item.content = item.content.slice(0, 9); // 保留前 9 个元素
+          }
+        });
+      }
+    },
+    delContent(index,contentIndex){
+      this.setting[index].content.splice(contentIndex,1)
+    },
+
+    //添加SOP规则类型
+    handleCommand(command){
+      this.setting.push({sopType:command,ruleType:null,name:null,type:1,content:[],isBindUrl:1,url:null,day:"0",hour:"0",minute:"0",time:""})
+    },
+
+    //添加课程SOP
+    handleCrouseCommand(command,val){
+      console.log("command",command)
+      console.log("val",val)
+    },
+
+    delSetting(index){
+      this.setting.splice(index,1)
+    },
+    handleClosegroupUser(list){
+      const index = this.userSelectList.findIndex(t => t === list);
+      if (index !== -1) {
+        this.userSelectList.splice(index, 1);
+      }
+    },
+    /** 查询企微sop列表 */
+    getList() {
+      this.loading = true;
+      listMySop(this.queryParams).then(response => {
+
+        this.sopList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+
+
+        listSopTemp().then(res => {
+          this.tempList = res.rows;
+        });
+
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+
+    // courseChange(){
+    //   videoList(this.form.courseId).then(response => {
+    //     this.videoList = response.list;
+    //   });
+    // },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        status: 1,
+        sendType:2,
+        type: 2,
+        filterType:2,
+        qwUserIds: null,
+        corpId: null,
+        setting: null,
+        createBy: null,
+        createTime: null,
+        isAutoSop:null,
+        autoSopTime:{ autoSopType:2,autoStartTime:'00:00',autoEndTime:'24:00',autoSopSend:2,autoDateTime:[]},
+      };
+      this.resetForm("form");
+      this.tags = null;
+      this.excludeTags = null;
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+      this.refreshData(this.queryParams.corpId);
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.selectionMap=selection;
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.$router.push('/qw/sop/addSop/'+this.queryParams.corpId)
+      // this.open = true;
+      // this.setting=[]
+      // this.userSelectList=[]
+      // this.title = "添加企微sop";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row,type) {
+      this.$router.push('/qw/sop/updateSop/'+row.id+'/'+type)
+    },
+
+
+    /**
+    * 查看SOP任务内营期
+    */
+    selectSchedule(row){
+      // type 2:我的sop 1:部门sop/销售公司sop
+      const query = {
+        id: row.id,
+        name: row.name,
+        tempId: row.tempId,
+        filterMode: row.filterMode,
+        corpId: row.corpId,
+        type:2,
+      }
+      // 使用 params 传递参数
+      this.$router.push({
+        path: `/qw/sopUserLogs/sopUserLogsSchedule/${query.id}`,
+        query // 如果需要传递更多参数,可以使用 query
+      });
+    },
+
+
+    /**
+    * 查看营期内详情
+    */
+    handleScheduleDetail(row){
+        this.sopLogsDialog.title='规则执行详情';
+        this.sopLogsDialog.open=true;
+        this.sopLogsDialog.sopLogsForm=row;
+    },
+
+    /**
+    * 查看模板
+    */
+    handleQueryDetails(row){
+      this.$router.push(`/qw/sopTemp/updateSopTemp/${row.tempId}/3`)
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if(this.userSelectList.length<=0){
+            return this.$message("请选择员工")
+          }
+          this.form.qwUserIds = this.userSelectList.join(",");
+          this.form.corpId=this.queryParams.corpId;
+          if (this.tags!=null && this.tags.length>0 ){
+            this.form.tags=(this.tags).toString()
+          }else {
+            return  this.$message.error("选择的标签不能为空!!请选择筛选的标签")
+          }
+          if (this.excludeTags!=null){
+            this.form.excludeTags=(this.excludeTags).toString()
+          }
+
+          this.form.setting=JSON.stringify(this.setting)
+          if (this.form.id != null) {
+            updateSop(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addSop(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    sortSelectedDates(dates){
+
+      if (!this.form.startTime) {
+        this.$message.error("请先选择开始时间!不得小于任务开始时间");
+        this.form.autoSopTime.autoDateTime = [];
+        return;
+      }
+
+      // 1. 过滤掉 < startTime 的日期
+      const validDates = dates.filter(date => new Date(date) >= new Date(this.form.startTime));
+
+      // 2. 如果有被过滤掉的日期,提示用户
+      if (validDates.length < dates.length) {
+        this.$message.warning(`已自动移除小于 ${this.form.startTime} 的日期!`);
+      }
+
+      // 3. 升序排序
+      validDates.sort((a, b) => new Date(a) - new Date(b));
+
+      // 4. 更新数据
+      this.form.autoSopTime.autoDateTime = validDates;
+    },
+
+    submitAutoSopTimeFrom(){
+
+      if (this.form.autoSopTime.autoSopType==3 || this.form.autoSopTime.autoSopType==4){
+        if(this.form.autoSopTime.autoDateTime==null || this.form.autoSopTime.autoDateTime=="") {
+          return  this.$message.error("选择的日期不能为空!!请选择日期")
+        }
+      }
+
+      this.$refs["autoSopTimeFrom"].validate(valid => {
+        if (valid) {
+          this.autoSopOpen.open=false
+          this.form.autoSopTime.createTime=this.formatDateTo24HourString(new Date());
+          updateAutoSopTime({id:this.autoSopOpen.id,isAutoSop:this.autoSopOpen.isAutoSop,autoSopTime: JSON.stringify(this.form.autoSopTime)}).then(response => {
+            this.msgSuccess("修改成功");
+          });
+        }
+        this.getList();
+        this.reset();
+      });
+    },
+
+    formatDateTo24HourString(date) {
+      let year = date.getFullYear();
+      let month = ('0' + (date.getMonth() + 1)).slice(-2); // 月份需要加 1 并补零
+      let day = ('0' + date.getDate()).slice(-2); // 日需要补零
+      let hours = ('0' + date.getHours()).slice(-2); // 小时需要补零
+      let minutes = ('0' + date.getMinutes()).slice(-2); // 分钟需要补零
+      let seconds = ('0' + date.getSeconds()).slice(-2); // 秒需要补零
+
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    },
+    cancelAutoSopTime(){
+      this.autoSopOpen.open=false
+      this.getList();
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企微sop编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delSop(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /**
+    * 批量执行SOP任务
+    */
+    handleExecute(){
+
+        const ids = this.selectionMap
+          .filter(item => item.status === 1)
+          .map(item => item.id);
+
+        if (ids.length === 0) {
+          this.msgError("选择的任务已经执行或正在执行,请选择待执行的任务");
+          return;
+        }
+
+        this.$confirm('是否确认立即执行sop编号为"' + ids + '"的数据项?', "警告【只能立即执行(待执行的)】", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+            this.loading = true;
+            // 执行更新操作
+            return updateStatus(ids); // 返回一个Promise,直接在此链式调用
+        }).then(res => {
+          let msg = "";
+
+          // 判断成功和失败的任务,并显示消息
+          if (res.suc.length > 0) {
+            msg += "执行成功的SOP任务【" + res.suc.join(", ") + "】。<br>"; // 优化:将数组转换为字符串
+          }
+          if (res.err.length > 0) {
+            msg += "失败的SOP任务【" + res.err.join(", ") + "】,原因是已经执行或正在执行。<br>";
+          }
+
+          // 显示确认框,显示成功与失败信息
+          return this.$confirm(msg, "提示", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+            dangerouslyUseHTMLString: true // 允许HTML标签
+          });
+
+        }).then(() => {
+          // 操作完成后刷新列表,并显示成功信息
+          this.getList();
+          this.msgSuccess("执行完成");
+        }).catch(() => {
+          // 处理任何异常,操作取消或者失败时显示提示信息
+          this.msgError("操作失败,请重试");
+        }).finally(() => {
+          this.loading = false; // 操作完成后关闭加载状态
+        });
+
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企微sop数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportSop(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    courseChange() {
+      if (this.msgForm.courseId != null ) {
+        const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === this.msgForm.courseId);
+        for (let i = 0; i < this.setting.length; i++) {
+          //响应式直接给链接的标题/封面上值
+          if (selectedCourse && this.setting[i].contentType == 3 && this.msgForm.courseId != null) {
+            this.$set(this.setting[i], 'linkTitle', selectedCourse.dictLabel);
+            this.$set(this.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
+          }
+
+        }
+
+      }
+      videoList(this.msgForm.courseId).then(response => {
+        this.videoList=response.list;
+      });
+    },
+    handleSendMsg(row){
+      let chatList = row.chatId ? row.chatId.split(",") : [];
+      this.sendMsgOpen.id = row.id;
+      this.sendMsgOpen.row = row;
+      this.sendMsgOpen.chatIds = chatList;
+      this.msgForm.chatIds = chatList;
+      this.sendMsgOpen.open = true;
+    },
+    handleContentTypeChange() {
+
+      //如果是链接的才上
+      if (this.msgForm.courseId != null ) {
+        const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === this.msgForm.courseId);
+        for (let i = 0; i < this.setting.length; i++) {
+          //响应式直接给链接的标题/封面上值
+          if (selectedCourse && this.setting[i].contentType == 3 && this.msgForm.courseId != null) {
+            this.$set(this.setting[i], 'linkTitle', selectedCourse.dictLabel);
+            this.$set(this.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
+          }
+
+        }
+
+      }
+      if (this.msgForm.videoId != null ) {
+        // 查找选中的课节对应的 label
+        const selectedVideo = this.videoList.find(course => parseInt(course.dictValue) === this.msgForm.videoId);
+
+        for (let i = 0; i < this.setting.length; i++) {
+          //响应式直接给链接的描述上值
+          if (selectedVideo && this.setting[i].contentType == 3  && this.msgForm.videoId != null) {
+            this.$set(this.setting[i], 'linkDescribe', selectedVideo.dictLabel);
+          }
+        }
+      }
+    },
+    handleAvatarSuccessFile(res, file, item) {
+      if (res.code === 200) {
+        // 使用 $set 确保响应式更新
+        this.$set(item, 'fileUrl', res.url);
+      } else {
+        this.msgError(res.msg);
+      }
+    },
+    beforeAvatarUploadFile(file){
+      const isLt1M = file.size / 1024 / 1024 < 10;
+      if (!isLt1M) {
+        this.$message.error('上传大小不能超过 10MB!');
+      }
+      return isLt1M;
+    },
+    //下载文件
+    downloadUrl(materialUrl) {
+      // 直接返回文件 URL
+      return materialUrl;
+    },
+
+    handleAvatarSuccessVideo(res, file, item) {
+      if(res.code==200){
+        // 使用 $set 确保响应式更新
+        this.$set(item, 'videoUrl', res.url);
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
+
+    beforeAvatarUploadVideo(file){
+      const isLt30M = file.size / 1024 / 1024 < 10;
+      const isMP4 = file.type === 'video/mp4';
+
+      if (!isMP4) {
+        this.$message.error('仅支持上传 MP4 格式的视频文件!');
+        return false;
+      }
+
+      if (!isLt30M) {
+        this.$message.error('上传大小不能超过 10MB!');
+        return false;
+      }
+
+      return true;
+    },
+
+    handleInputVideoText(value,content){
+      // 允许的字符:中文、英文(大小写)、数字和指定标点符号(,。!?)
+      const regex = /^[\u4e00-\u9fa5,。!?,!?]+$/;
+
+      // 删除不符合条件的字符
+      const filteredValue = value.split('').filter(char => regex.test(char)).join('');
+
+      this.$set(content, 'value', filteredValue);
+
+    },
+    delSetList(index){
+      this.setting.splice(index,1)
+    },
+    addSetList(){
+      const newSetting = {
+        contentType:'1',
+        value: '',
+      };
+      // 将新设置项添加到 content.setting 数组中
+      this.setting.push(newSetting);
+
+    },
+    submitMsgForm(){
+      this.$refs["msgForm"].validate(valid => {
+        if (valid) {
+          this.msgForm.setting=JSON.stringify(this.setting)
+          this.msgForm.sopId=this.sendMsgOpen.row.id;
+          this.msgForm.filterMode=this.sendMsgOpen.row.filterMode;
+
+          if (this.setting.length <= 0) {
+            return this.$message.error("请添加规则")
+          }
+          if (this.msgForm.courseId===null || this.msgForm.courseId===''){
+            return this.$message.error("课程不能为空")
+          }
+
+          if (this.msgForm.videoId===null || this.msgForm.videoId===''){
+            return this.$message.error("课节不能为空")
+          }
+
+          if (this.msgForm.courseType===null || this.msgForm.courseType===''){
+            return this.$message.error("消息类型不能为空")
+          }
+
+          for (let i = 0; i < this.setting.length; i++) {
+            if (this.setting[i].contentType == 1 && (this.setting[i].value == null || this.setting[i].value == "")) {
+              return this.$message.error("内容不能为空")
+            }
+            if (this.setting[i].contentType == 2 && (this.setting[i].imgUrl == null || this.setting[i].imgUrl == "")) {
+              return this.$message.error("图片不能为空")
+            }
+            if (this.setting[i].contentType == 3 && (this.setting[i].linkTitle == null || this.setting[i].linkTitle == "")) {
+              return this.$message.error("链接标题不能为空")
+            }
+            if (this.setting[i].contentType == 3 && (this.setting[i].linkDescribe == null || this.setting[i].linkDescribe == "")) {
+              return this.$message.error("链接描述不能为空")
+            }
+            if (this.setting[i].contentType == 3 && (this.setting[i].linkImageUrl == null || this.setting[i].linkImageUrl == "")) {
+              return this.$message.error("链接图片不能为空")
+            }
+            if (this.setting[i].contentType == 3 && this.setting[i].type == 1 && (this.setting[i].linkUrl == null || this.setting[i].linkUrl == "")) {
+              return this.$message.error("链接地址不能为空")
+            }
+            if (this.setting[i].contentType == 5 && (this.setting[i].fileUrl == null || this.setting[i].fileUrl == "")) {
+              return this.$message.error("文件不能为空")
+            }
+            if (this.setting[i].contentType == 6 && (this.setting[i].videoUrl == null || this.setting[i].videoUrl == "")) {
+              return this.$message.error("视频不能为空")
+            }
+            if (this.setting[i].contentType == 7 && (this.setting[i].value == null || this.setting[i].value == "")) {
+              return this.$message.error("语音不能为空")
+            }
+          }
+
+          this.sendMsgOpen.open = false;
+
+          const loading = this.$loading({
+            lock: true,
+            text: '正在执行中请稍后~~请不要刷新页面!!',
+            spinner: 'el-icon-loading',
+            background: 'rgba(0, 0, 0, 0.7)'
+          });
+
+          sendMsgSop(this.msgForm).then(response => {
+            this.msgSuccess("一键群发成功");
+            loading.close();
+            this.setting=[];
+            this.msgForm = {
+              videoId:null,
+              courseId:null,
+              courseType:null,
+              setting:null,
+              isRegister:2,
+              sendType:1,
+              filterMode:2,
+
+            }
+            this.getList();
+          }).finally(()=>{
+            loading.close();
+          });
+
+        }
+      });
+    },
+    cancelMsgForm(){
+      this.sendMsgOpen.open = false;
+      this.resetSendMsgSop();
+    },
+    videoIdChange() {
+      if (this.msgForm.videoId != null ) {
+        // 查找选中的课节对应的 label
+        const selectedVideo = this.videoList.find(course => parseInt(course.dictValue) === this.msgForm.videoId);
+
+        for (let i = 0; i < this.setting.length; i++) {
+          //响应式直接给链接的描述上值
+          if (selectedVideo && this.setting[i].contentType == 3  && this.msgForm.videoId != null) {
+            this.$set(this.setting[i], 'linkDescribe', selectedVideo.dictLabel);
+          }
+        }
+      }
+    },
+  }
+};
+</script>
+<style scoped>
+.custom-input /deep/ .el-input__inner {
+  height: 20px;
+  padding: 0 4px;
+  text-align:center;
+  display: block;
+}
+.custom-input /deep/ .el-input__icon {
+  line-height: 20px;
+}
+.el-button--text{
+  cursor: pointer;
+}
+</style>

+ 1129 - 0
src/views/qw/user/cuDeptIdIndex.vue

@@ -0,0 +1,1129 @@
+<template>
+
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <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="qwUserId">
+        <el-input
+          v-model="queryParams.qwUserId"
+          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="appKey">
+        <el-input
+          v-model="queryParams.appKey"
+          placeholder="请输入授权码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="员工状态" prop="isDel">
+        <el-select v-model="queryParams.isDel" placeholder="请选择员工状态" clearable>
+          <el-option
+            v-for="item in optionsStatus"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value">
+          </el-option>
+        </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="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:user:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
+      <el-table-column label="企微成员ID" align="center" prop="id" />
+      <el-table-column label="企微账号" align="center" prop="qwUserId" />
+      <el-table-column label="企微昵称" align="center" prop="qwUserName" />
+      <el-table-column label="员工称呼" align="center" prop="welcomeText" />
+      <el-table-column label="所属部门" align="center" prop="isDel">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.isDel == 0" type="success">正常</el-tag>
+          <el-tag v-else type="error">离职</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="联系我二维码" align="center" prop="contactWay" >
+        <template slot-scope="scope">
+          <el-image
+            v-if="scope.row.contactWay!=null"
+            style="width: 100px; height: 100px"
+            :src="scope.row.contactWay"
+            fit="contain"
+            @click="openImageViewer(scope.row.contactWay)"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="绑定的AI客服" align="center" prop="fastGptRoleName" />
+      <el-table-column label="授权码" align="center" prop="appKey" />
+     <el-table-column label="ai状态" align="center" prop="loginStatus">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.ipadStatus == 1" type="success">在线</el-tag>
+          <el-tag v-else type="danger">离线</el-tag>
+        </template>
+      </el-table-column>
+<!--      <el-table-column label="插件状态" align="center" prop="toolStatus">-->
+<!--        <template slot-scope="scope">-->
+<!--          <el-tag v-if="scope.row.toolStatus == 1" type="success">在线</el-tag>-->
+<!--          <el-tag v-else type="danger">离线</el-tag>-->
+<!--        </template>-->
+<!--      </el-table-column>-->
+<!--      <el-table-column label="插件版本" align="center" prop="version"/>-->
+      <el-table-column label="服务器地址" align="center" prop="loginCodeUrl">
+        <template slot-scope="scope">
+          <el-tooltip class="item" effect="dark" :content="scope.row.loginCodeUrl" placement="top">
+            <div style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; text-overflow: ellipsis;">
+              <span>{{ scope.row.loginCodeUrl }}</span>
+            </div>
+          </el-tooltip>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user-solid"
+            plain
+            @click="handleAppellation(scope.row)"
+          >
+            修改员工称呼
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user-solid"
+            plain
+            @click="handleAutoRemark(scope.row)"
+          >
+            完课备注修改
+          </el-button>
+
+          <el-button
+            v-if="scope.row.serverStatus==1&&scope.row.ipadStatus!=1"
+            size="mini"
+            type="text"
+            icon="el-icon-sunny"
+            plain
+            @click="handleLoginQwCode(scope.row)"
+            v-hasPermi="['qw:user:login']"
+          >
+            登录企微
+          </el-button>
+         <el-button
+			v-if="scope.row.serverStatus==1&&scope.row.ipadStatus==1"
+            size="mini"
+            type="text"
+            icon="el-icon-moon"
+            plain
+            @click="handleLoginOutQwStatus(scope.row)"
+            v-hasPermi="['qw:user:login']"
+          >
+            退出企微
+          </el-button>
+		<el-button
+			v-if="scope.row.ipadStatus==1"
+		   size="mini"
+		   type="text"
+		   icon="el-icon-moon"
+		   plain
+		   @click="handleTwoCode(scope.row)"
+		   v-hasPermi="['qw:user:login']">
+		   二次验证
+		 </el-button>
+		 <el-button
+		 	v-if="scope.row.serverStatus!=1"
+		    size="mini"
+		    type="text"
+		    icon="el-icon-moon"
+		    plain
+		    @click="handleGetQwIpad(scope.row)"
+		    v-hasPermi="['qw:user:login']"
+		  >
+		    获取Ai主机
+		  </el-button>
+		  <el-button
+		  	v-if="scope.row.serverStatus==1 && scope.row.ipadStatus!=1"
+		     size="mini"
+		     type="text"
+		     icon="el-icon-moon"
+		     plain
+		     @click="handleDelQwIpad(scope.row)"
+		     v-hasPermi="['qw:user:login']"
+		   >
+		     解绑Ai主机
+		   </el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="主机" align="center" class-name="small-padding fixed-width" width="110px" fixed="right">
+        <template slot-scope="scope">
+
+          <el-button
+            v-if="scope.row.appKey==null"
+            size="mini"
+            type="text"
+            icon="el-icon-s-check"
+            plain
+            v-hasPermi="['qw:user:authAppKey']"
+            @click="uploadAuthorizeKey2(scope.row)"
+          >授权key
+          </el-button>
+          <el-button
+            v-if="scope.row.loginCodeUrl==null && scope.row.appKey !=null"
+            size="mini"
+            type="text"
+            icon="el-icon-sunny"
+            plain
+            @click="handleBindCloudHost(scope.row)"
+            v-hasPermi="['qw:user:loginIp']"
+          >
+            绑定主机
+          </el-button>
+<!--          <el-button-->
+<!--            v-if="scope.row.loginCodeUrl!=null"-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-video-camera-solid"-->
+<!--            plain-->
+<!--            @click="handleCloudAP(scope.row.loginCodeUrl)"-->
+<!--            v-hasPermi="['qw:user:cloudAP']"-->
+<!--          >-->
+<!--            获取主机帐密-->
+<!--          </el-button>-->
+          <el-button
+            v-if="scope.row.loginCodeUrl!=null"
+            size="mini"
+            type="text"
+            icon="el-icon-moon"
+            plain
+            @click="handleUnbindCloudHost(scope.row)"
+            v-hasPermi="['qw:user:loginIpOut']"
+          >
+            解除主机
+          </el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="AI客服" align="center" class-name="small-padding fixed-width" width="100px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-connection"
+            plain
+            v-if="scope.row.fastGptRoleName!=null"
+            @click="bindFastGptRole(scope.row)"
+          >换绑AI客服</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            plain
+            icon="el-icon-link"
+            v-else
+            @click="bindFastGptRole(scope.row)"
+          >绑定AI客服</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-unlock"
+            plain
+            v-if="scope.row.fastGptRoleName!=null"
+            @click="relieveFastGptRole(scope.row)"
+          >解绑AI客服</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"
+    />
+
+    <!-- 绑定AI客服-->
+    <el-dialog :title="bindAiTitle" :visible.sync="bindAiOpen" width="1200px" append-to-body>
+      <fast-gpt-role ref="fastGptRole" @refreshFastGptList="refreshFastGptList" ></fast-gpt-role>
+    </el-dialog>
+
+<!--    <el-dialog :visible.sync="updateIp.open" width="600px" append-to-body>-->
+<!--      <el-form ref="updateIpForm" :model="updateIpForm" :rules="updateIpRule" label-width="100px">-->
+<!--        <el-form-item label="新云主机IP" prop="Ip">-->
+<!--          <el-input v-model="updateIpForm.newIp" placeholder="请输入新IP" />-->
+<!--        </el-form-item>-->
+<!--      </el-form>-->
+<!--      <div slot="footer" class="dialog-footer" >-->
+<!--        <el-button type="primary" @click="submitUpdateIpForm">确 定</el-button>-->
+<!--      </div>-->
+<!--    </el-dialog>-->
+
+    <el-dialog title="云主机信息" :visible.sync="cloudAPOpen.open" append-to-body>
+      <el-card class="box-card">
+        <div slot="header" class="clearfix">
+          <span>账号:{{cloudAPOpen.admin}}</span>
+        </div>
+        <div slot="header" class="clearfix">
+          <span>密码:{{cloudAPOpen.passWord}}</span>
+        </div>
+      </el-card>
+    </el-dialog>
+
+    <el-dialog :title="callOpen.title" :visible.sync="callOpen.open" width="500px" append-to-body>
+      <el-form ref="callOpenFrom" :model="callOpenFrom" :rules="callOpenRule" label-width="110px">
+        <el-form-item label="员工称呼" prop="welcomeText">
+          <el-input v-model="callOpenFrom.welcomeText" placeholder="请输入员工称呼" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer" >
+        <el-button type="primary" @click="submitCallOpenFrom">确 定</el-button>
+      </div>
+    </el-dialog>
+
+
+    <el-dialog :title="editRemarkOpen.title" :visible.sync="editRemarkOpen.open" width="500px" append-to-body>
+      <el-form ref="callOpenFrom" :model="editRemarkOpen" label-width="110px">
+        <el-radio-group v-model="editRemarkOpen.isSendMsg">
+          <el-card>
+            <el-row :gutter="20">
+              <el-col>
+                <el-radio
+                  :label="1"
+                  style="font-size: 16px; margin: 10px 0;"
+                >添加【完课备注】在最【旧备注-(前面)】</el-radio>
+              </el-col>
+              <el-col>
+                <el-radio
+                  :label="2"
+                  style="font-size: 16px; margin: 10px 0;"
+                >添加【完课备注】在最【旧备注-(后面)】</el-radio>
+              </el-col>
+              <el-col>
+                <el-radio
+                  :label="3"
+                  style="font-size: 16px; margin: 10px 0;"
+                >使用简洁版备注【*日期完】,在【旧备注-前面】</el-radio>
+              </el-col>
+              <el-col>
+                <el-radio
+                  :label="4"
+                  style="font-size: 16px; margin: 10px 0;"
+                >使用简洁版备注【*日期完】,在【旧备注-后面】</el-radio>
+              </el-col>
+              <el-col>
+                <el-radio
+                  :label="5"
+                  style="font-size: 16px; margin: 10px 0;"
+                >不用完课备注</el-radio>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-radio-group>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitEditRemarkOpenFrom">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="授权key" :visible.sync="authorizeKeyOpen" width="500px" append-to-body>
+        <el-form ref="authorizeKeyFrom" :model="authorizeKeyFrom" :rules="authorizeKeyRule" label-width="110px">
+            <el-form-item label="授权的key值" prop="appKey">
+              <el-input v-model="authorizeKeyFrom.appKey" placeholder="请输入授权key" type="Number"/>
+            </el-form-item>
+        </el-form>
+            <div slot="footer" class="dialog-footer" >
+              <el-button type="primary" @click="submitAuthorizeKeyForm">确 定</el-button>
+            </div>
+    </el-dialog>
+    <!--二维码   -->
+    <el-dialog
+      title="企微二次认证"
+      :visible.sync="qwLoginTwo.open"
+      width="600px"
+      append-to-body
+      custom-class="qr-login-dialog"
+    >
+      <div class="qr-login-container">
+        <div class="image-wrapper" v-loading="imageLoading" >
+          <el-image
+            :src="'data:image/png;base64,' +qwLoginTwo.codeUrl"
+            style="display: block; margin: 0 auto; width: 300px; height: 300px;"
+          />
+        </div>
+        <p class="qr-login-instructions">二次验证二维码</p>
+		</div>
+		<div slot="footer" class="dialog-footer" >
+		  <el-button type="primary" @click="qwLoginTwo.open=false">确 定</el-button>
+		</div>
+    </el-dialog>
+
+	<el-dialog
+	  :title="qwLogin.title"
+	  :visible.sync="qwLogin.open"
+	  width="600px"
+	  append-to-body
+	  custom-class="qr-login-dialog"
+	>
+	  <div class="qr-login-container">
+	    <div class="image-wrapper" v-loading="imageLoading" >
+	      <el-image
+	        :src="'data:image/png;base64,' +qwLogin.codeUrl"
+	        style="display: block; margin: 0 auto; width: 300px; height: 300px;"
+	      />
+	    </div>
+	    <p class="qr-login-instructions">使用企业微信扫码授权登录</p>
+	  </div>
+	</el-dialog>
+
+	<el-dialog
+	  title="输入企微验证码"
+	  :visible.sync="qwCode.open"
+	  width="600px"
+	  append-to-body>
+	 <el-form  :model="qwCode"  label-width="80px" @submit.native.prevent="handleSubmit">
+	     <el-form-item label="验证码" prop="companyName">
+	       <el-input v-model="qwCode.code" placeholder="输入企微6位验证码" />
+	     </el-form-item>
+	</el-form>
+
+	<div slot="footer" class="dialog-footer">
+	  <el-button type="primary" @click="submitCodeForm">确 定</el-button>
+
+	</div>
+	</el-dialog>
+
+
+
+    <!-- 大图预览对话框 -->
+    <el-dialog
+      :visible.sync="dialogVisible"
+      :modal="false"
+      width="1200"
+      append-to-body>
+      <img
+        :src="this.dialogImageUrl"
+        style="display: block; max-width: 100%; margin: 0 auto"
+      />
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import {
+  updateUser,
+  exportUser,
+  getMyQwCompanyList,
+  relieveFastGptRoleById,
+  loginQwIpad,
+  loginQwCodeMsg,
+  twoCode,
+  twoCodeStatus,
+  qrCodeStatus,
+  getQwIpad,
+  delQwIpad,
+  qrCodeVerify,
+  outLoginQwIpad,
+  handleAllocateRemoteHost,
+  qwBindCloudHost, qwUnbindCloudHost, handleAuthAppKey, handleInputAuthAppKey, selectCloudAP, myDepartListUser
+} from '../../../api/qw/user'
+import fastGptRole from "@/views/fastGpt/fastGptRole/fastGptRole";
+
+export default {
+  name: "cuDeptIdIndex",
+  components: { fastGptRole},
+  data() {
+    return {
+      updateIp:{
+        open:false,
+        title: "修改云主机IP"
+      },
+      updateIpForm:{
+        id:null,
+        newIp:null,
+      },
+      authorizeKeyOpen:false,
+      authorizeKeyFrom:{
+        id:null,
+        appKey:null,
+        qwUserId:null,
+        qwUserName:null
+      },
+      updateIpRule:{},
+      newIp:null,
+      //放大图片
+      dialogImageUrl:null,
+      dialogVisible:false,
+      optionsStatus: [{
+        value: 0,
+        label: '正常'
+      }, {
+        value: 2,
+        label: '离职'
+      }],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      //公司列表
+      myQwCompanyList:[],
+      // 企微用户表格数据
+      userList: [],
+      allowSelectOptions:[],
+      // 弹出层标题
+      bindAiTitle: "",
+      bindAiOpen: false,
+      qwLogin:{
+        title:"",
+        open:false,
+        codeUrl:null,
+        code:null,
+        appKey:null,
+      },
+	 qwLoginTwo:{
+        title:"",
+        open:false,
+        codeUrl:null,
+        code:null,
+        appKey:null,
+     },
+	qwCode:{
+        title:"",
+        open:false,
+        code:null,
+      },
+      cloudAPOpen:{
+        open:false,
+        admin:null,
+        passWord:null,
+      },
+      callOpen:{
+        open:false,
+        title: '修改员工称呼',
+
+      },
+      callOpenFrom:{
+        id:null,
+        welcomeText:null,
+      },
+
+      editRemarkOpen: {
+        open: false,
+        title: '修改员工自动给完课客户打备注的规则',
+        id:null,
+        isSendMsg:null,
+      },
+
+      twoCodeInterval:null,
+      loginQwInterval:null,
+
+      imageLoading: true, // 控制加载状态
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        qwUserId: null,
+        corpId: null,
+        qwUserName: null,
+      },
+	  qwUserId:null,
+      companyUserList:[],
+      // 表单参数
+      form: {
+        isSendMsg: '2',
+      },
+      authorizeKeyRule:{
+        appKey:[{required:true,message:"授权码不能为空",trigger:"blur"}]
+      },
+      callOpenRule:{
+        welcomeText:[{required:true,message:"员工称呼不能为空",trigger:"blur"}]
+      },
+      // 表单校验
+      rules: {
+      },
+      //欢迎语表单校验
+      weclomeRules:{
+        welcomeText:[{required:true,message:"消息文本不能为空",trigger:"blur"}]
+      },
+    };
+  },
+  created() {
+
+    getMyQwCompanyList().then(response => {
+      this.myQwCompanyList = response.data;
+      if(this.myQwCompanyList!=null){
+        this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+        this.getList();
+      }
+    });
+
+
+  },
+  watch: {
+    // 监听弹窗的可见性变化
+    'qwLogin.open'(newVal) {
+      if (!newVal) {
+        // 如果弹窗关闭,清除定时器
+        clearInterval(this.loginQwInterval);
+
+      }
+    },
+  },
+  methods: {
+    getList() {
+      this.loading = true;
+      myDepartListUser(this.queryParams).then(response => {
+        this.userList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+
+    },
+    updateCorpId(){
+      this.reset();
+      this.getList();
+    },
+
+    //绑定AI客服
+    bindFastGptRole(row){
+      this.bindAiTitle="绑定AI客服";
+      this.bindAiOpen=true;
+      setTimeout(() => {
+        this.$refs.fastGptRole.handleBindAiData(row)
+      }, 200);
+
+    },
+
+    handleAppellation(val){
+      this.callOpen.open=true;
+      this.callOpenFrom.welcomeText=val.welcomeText;
+      this.callOpenFrom.id=val.id;
+    },
+
+    handleAutoRemark(val){
+      this.editRemarkOpen.open=true;
+      this.editRemarkOpen.id = val.id;
+      this.editRemarkOpen.isSendMsg = val.isSendMsg;
+    },
+    //登录
+    handleLoginQwCode(val){
+      if (val.appKey==null || val.appKey===''){
+        return this.$message.warning("没有授权码,无法登录企业微信,请授权");
+      }
+      loginQwIpad({qwUserId:val.id}).then(res => {
+		this.qwUserId=val.id;
+        this.qwLogin.code=null;
+        this.imageLoading=false;
+		console.log(res)
+		if(res.msg=="success"){
+			this.qwLogin.codeUrl=res.qrCode64
+			this.qwLogin.open=true;
+			this.loginQwPolling();
+		}else{
+			this.$message.success(res.msg);
+			this.getList()
+		}
+
+      })
+    },
+
+	handleTwoCode(val){
+
+		twoCode({ qwUserId: val.id }).then(res => {
+		console.log(res)
+		this.qwLoginTwo.open=true;
+		this.qwLoginTwo.codeUrl=res.qrCode
+
+        });
+
+
+	},
+	twoCodePolling() {
+	  this.twoCodeInterval = setInterval(() => {
+	    twoCodeStatus({ qwUserId: this.qwUserId }).then(res => {
+			console.log(res)
+
+	      if (res.msg==104001) {
+			this.$message.success('登录成功');
+			this.clearDl()
+	        clearInterval(this.loginQwInterval);
+	      }else if(res.msg==100004){
+			  this.clearDl()
+		  }
+	    });
+	  }, 3000);
+	},
+    loginQwPolling() {
+      this.loginQwInterval = setInterval(() => {
+        qrCodeStatus({ qwUserId: this.qwUserId }).then(res => {
+			console.log(res)
+			if (res.msg==22) {
+				this.$message.success('账号企业不一致请重新扫码登录');
+				this.clearDl();
+			}
+          if (res.msg==104001) {
+			this.$message.success('登录成功');
+			this.clearDl()
+
+          }else if(res.msg==100004){
+			  this.qwCode.open=true;
+			  clearInterval(this.loginQwInterval);
+		  }
+        });
+      }, 3000);
+    },
+	submitCodeForm(){
+
+		qrCodeVerify({ code: this.qwCode.code,qwUserId: this.qwUserId }).then(res => {
+			console.log(res)
+
+			this.$message.success('验证成功账号信息确认中。。。。');
+			this.qwCode.open=false;
+			 this.loginQwInterval = setTimeout(() => {
+			     qrCodeStatus({ qwUserId: this.qwUserId }).then(res => {
+			         console.log(res);
+			         if (res.msg == 23) {
+			             this.$message.error('账号不一致请重新扫码登录');
+			             this.clearDl();
+			         }
+					 if (res.msg == 22) {
+					     this.$message.error('账号企业不一致请重新扫码登录');
+					     this.clearDl();
+					 }
+			         if (res.msg == 104001) {
+			             this.$message.success('登录成功');
+			             this.clearDl();
+			         }
+			     });
+			 }, 4000);
+		});
+	},
+
+	clearDl(){
+		this.qwCode.open=false;
+		this.qwLogin.open=false;
+		clearInterval(this.loginQwInterval);
+		this.getList()
+	},
+
+
+
+    //退出
+    handleLoginOutQwStatus(val){
+      outLoginQwIpad({qwUserId: val.id}).then(res => {
+
+        this.$message.success("退出登录成功");
+		this.getList()
+      })
+
+    },
+
+
+	handleGetQwIpad(val){
+    getQwIpad({ qwUserId: val.id }).then(res => {
+      this.$message.success("获取主机成功");
+      this.getList();
+    }).catch(error => {
+      console.log(error);
+      if (error.code  === 501) {
+        this.$confirm(
+          '当前区域没有多余的名额,将为你分配异地名额,会导致企业微信需要扫脸重新登录,并且半个小时后需要进行验证',
+          '提示',
+          {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+            dangerouslyUseHTMLString: true
+          }
+        ).then(() => {
+          return handleAllocateRemoteHost({ qwUserId: val.id });
+        }).then(res => {
+          this.$message.success('异地主机分配成功');
+          this.getList();
+        }).catch(() => {
+          this.$message.info('已取消异地主机分配');
+        });
+      } else {
+        this.$message.error('获取主机失败');
+      }
+    });
+	},
+	handleDelQwIpad(val){
+	  delQwIpad({qwUserId: val.id}).then(res => {
+	    this.$message.success("解绑主机成功");
+		this.getList()
+	  })
+	},
+    //传验证码
+    handleLoginQwCodeMsg(){
+      loginQwCodeMsg({appKey: this.qwLogin.appKey,code:this.qwLogin.code}).then(res => {
+        this.qwLogin.open=false;
+        this.$message.success("登录成功");
+      })
+    },
+
+    validateCode() {
+      // 只允许输入数字并限制长度为6
+      this.qwLogin.code = this.qwLogin.code.replace(/\D/g, "").slice(0, 6);
+    },
+
+    handleCloudAP(urlAP){
+
+      selectCloudAP({ipAddress:urlAP}).then(res => {
+        this.cloudAPOpen.open=true
+        this.cloudAPOpen.admin=res.data.apAdmin;
+        this.cloudAPOpen.passWord=res.data.apPassword;
+      })
+    },
+
+    handleUnbindCloudHost(val){
+
+      const appKey=val.appKey;
+
+      this.$confirm(
+        '确定要给企微账号:<span style="color: green;">' +val.qwUserId + '' +
+        '</span><br>企微昵称:<span style="color: red;">【' + val.qwUserName + '】</span>' +
+        '</span><br><span style="color: orange;">解绑【Ps:解绑后此云主机可能会分配给他人】</span></span>',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        return  qwUnbindCloudHost(appKey);
+      }).then(response => {
+        this.$message.success('解绑成功');
+      }).finally(res=>{
+        this.getList();
+      })
+
+    },
+
+
+    handleAuthorizeKey(val){
+      this.authorizeKeyFrom.id=val.id;
+      this.authorizeKeyFrom.qwUserId=val.qwUserId;
+      this.authorizeKeyFrom.qwUserName=val.qwUserName;
+      this.authorizeKeyOpen=true;
+
+    },
+
+    submitAuthorizeKeyForm(){
+      this.$refs["authorizeKeyFrom"].validate(valid => {
+        if (valid) {
+          if (this.authorizeKeyFrom.id != null && this.authorizeKeyFrom.appKey != null) {
+            this.uploadAuthorizeKey();
+          }
+        }
+      });
+    },
+    submitCallOpenFrom(){
+
+      this.$refs["callOpenFrom"].validate(valid => {
+        if (valid) {
+
+          if (this.callOpenFrom.id != null && this.callOpenFrom.welcomeText != null) {
+            updateUser(this.callOpenFrom).then(res=>{
+              this.$message.success('修改成功');
+              this.callOpen.open=false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    submitEditRemarkOpenFrom(){
+      if (this.editRemarkOpen.id != null && this.editRemarkOpen.isSendMsg != null) {
+        updateUser(this.editRemarkOpen).then(res => {
+          this.$message.success('修改成功');
+          this.editRemarkOpen.open = false;
+          this.getList();
+        });
+      }else {
+        this.$message.error("请选择条件")
+      }
+    },
+
+
+    uploadAuthorizeKey(){
+      this.$confirm(
+        '确定要给企微账号:<span style="color: green;">' + this.authorizeKeyFrom.qwUserId + '' +
+        '</span><br>企微昵称:<span style="color: red;">【' + this.authorizeKeyFrom.qwUserName + '】</span>' +
+        '</span><br>授权key:<span style="color: #04adf6;">【' + this.authorizeKeyFrom.appKey + '】</span>?',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        this.authorizeKeyOpen=false;
+        return handleInputAuthAppKey(this.authorizeKeyFrom);
+      }).then(response => {
+        this.msgSuccess("授权key完成");
+      }).finally(res=>{
+        this.resetAuthorizeKeyFrom();
+        this.getList();
+      })
+
+    },
+
+    uploadAuthorizeKey2(val){
+      const id=val.id;
+      this.$confirm(
+        '确定要给企微账号:<span style="color: green;">' +val.qwUserId + '' +
+        '</span><br>企微昵称:<span style="color: red;">【' + val.qwUserName + '】</span>' +
+        '</span><br>授权key</span>?',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        return handleAuthAppKey({id:id});
+      }).then(response => {
+        this.msgSuccess("授权key完成");
+      }).finally(res=>{
+        this.resetAuthorizeKeyFrom();
+        this.getList();
+      })
+    },
+
+    handleBindCloudHost(val){
+
+      if (val.appKey == null || val.appKey == '') {
+        return this.$message.warning('没有授权码,无法绑定主机,请联系管理员');
+      }
+
+      const appKey=val.appKey;
+
+      this.$confirm(
+        '确定要给企微账号:<span style="color: green;">' +val.qwUserId + '' +
+        '</span><br>企微昵称:<span style="color: red;">【' + val.qwUserName + '】</span>' +
+        '</span><br><span style="color: dodgerblue;">绑定云主机?</span></span>',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        return qwBindCloudHost(appKey);
+      }).then(response => {
+        this.$message.success('绑定成功,请登录云主机进行配置~~');
+      }).finally(res=>{
+        this.getList();
+      })
+
+
+    },
+
+    openImageViewer(url) {
+      // 打开大图预览对话框
+      this.dialogImageUrl=url
+      this.dialogVisible = true;
+    },
+    //刷新页面
+    refreshFastGptList(){
+      this.bindAiOpen=false;
+      this.getList();
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        qwUserId: null,
+        corpId: null,
+        qwUserName: null,
+      };
+      this.resetForm("form");
+
+    },
+
+    //重置授权
+    resetAuthorizeKeyFrom(){
+      this.authorizeKeyFrom={
+          id:null,
+          appKey:null,
+          qwUserId:null,
+          qwUserName:null
+      };
+    },
+    //重置登录
+    resetQwLogin(){
+      this.qwLogin={
+        title:"",
+        open:false,
+        codeUrl:null,
+        code:null,
+        corpId:null,
+        qwUserId:null,
+      }
+      this.qwLogin.open=false;
+      this.loading=false;
+      this.getList();
+    },
+    //解绑AI客服
+    relieveFastGptRole(row){
+      this.$confirm('是否确认解绑AI客服?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return relieveFastGptRoleById(row.id);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("解绑成功");
+      })
+
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+
+            // updateUser(this.form).then(response => {
+            //   this.msgSuccess("绑定成功");
+            //   this.open = false;
+            //   this.getList();
+            //
+            // });
+          } else {
+            // addUser(this.form).then(response => {
+            //   this.msgSuccess("新增成功");
+            //   this.open = false;
+            //   this.getList();
+            // });
+          }
+        }
+      });
+    },
+
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企微用户数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportUser(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+<style>
+.text-container {
+  max-height: 7.5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+.qr-login-dialog .el-dialog__body {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  text-align: center;
+  padding: 20px;
+}
+
+.qr-login-container {
+  width: 100%;
+}
+
+.qr-login-instructions {
+  font-size: 14px;
+  color: #666;
+  margin: 10px 0;
+}
+
+.verification-code-input {
+  margin-top: 15px;
+  width: 80%;
+}
+
+</style>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 397 - 344
src/views/qw/user/index.vue


+ 701 - 0
src/views/qw/welcome/deptWelcomeIndex.vue

@@ -0,0 +1,701 @@
+<template>
+  <div>
+  <div class="app-container">
+    <el-alert
+      title="注意事项"
+      type="warning"
+      description="因企业微信接口限制,1、在【企业微信后台】群欢迎语素材库进行新增/编辑/删除操作,后台不会同步更新,建议在后台入群欢迎语处进行管理。
+       2、 注意:企业微信入群欢迎语素材库中,最多容纳100个素材,包括后台管理的以及企业微信后台管理的。
+       3、除图片外,其他附件素材均只有三天时效,若要续用,请点击修改-》直接点击-确认后,刷新时效"
+      :closable="false"
+      center
+      show-icon>
+    </el-alert>
+  </div>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" >
+      <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="createName">
+        <el-input
+          v-model="queryParams.textContent"
+          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-item>
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            size="mini"
+            icon="el-icon-plus"
+            @click="handleAdd"
+            v-hasPermi="['qw:welcome:add']"
+          >新增</el-button>
+        </el-col>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="welcomeList" border>
+      <el-table-column label="欢迎语类型" align="center" prop="welcomeType" >
+        <template slot-scope="scope">
+          <span   v-for="(item, index) in welcomeTypeOptions"    v-if="scope.row.welcomeType==item.dictValue">{{item.dictLabel}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="欢迎消息文本" align="left" width="600px" >
+        <template slot-scope="scope">
+          <div class="flex-container">
+            <el-tooltip class="item" effect="dark" :content="scope.row.textContent" placement="top">
+              <div style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; text-overflow: ellipsis;">
+                <span>文本消息:</span>{{ scope.row.textContent }}
+              </div>
+            </el-tooltip>
+            <div v-if="scope.row.welcomeType == '1'">
+              <div style="float: left">
+              <span>图片:</span>
+              <el-image v-if="scope.row.imagePicUrl"
+                style="width: 50px; height: 50px"
+                :src="scope.row.imagePicUrl"
+                fit="contain" />
+                <span v-if="!scope.row.imagePicUrl">无图片</span>
+              </div>
+            </div>
+            <div v-if="scope.row.welcomeType=='2'">
+              <div style="float: left;margin-top: 10px">
+                <el-tooltip class="item" effect="dark" :content="scope.row.linkTitle" placement="top">
+                  <div style="float: left; overflow-y: hidden; height: 50px">
+                    <span>图文标题:</span>{{ scope.row.linkTitle }}
+                  </div>
+                </el-tooltip>
+                <div>
+                  <el-image v-if="scope.row.linkPicurl"
+                            style="width: 50px; height: 50px"
+                            :src="scope.row.linkPicurl"
+                            fit="contain" />
+                </div>
+
+              </div>
+            </div>
+
+            <div v-if="scope.row.welcomeType=='3'">
+              <div style="float: left">
+                <span>小程序标题:</span>{{scope.row.miniprogramTitle}}
+                <div>
+                  <el-image v-if="scope.row.miniprogramPicUrl"
+                            style="width: 50px; height: 50px"
+                            :src="scope.row.miniprogramPicUrl"
+                            fit="contain" />
+                </div>
+              </div>
+            </div>
+
+            <div v-if="scope.row.welcomeType=='4'">
+              <div style="float: left">
+                <span>文件:</span>
+                <span>请查看详情</span>
+              </div>
+            </div>
+
+            <div v-if="scope.row.welcomeType=='5'">
+              <div style="float: left">
+                <span>视频:</span>
+                <span>请查看详情</span>
+              </div>
+            </div>
+          </div>
+        </template>
+
+      </el-table-column>
+      <el-table-column label="创建人" align="center" prop="createName" />
+      <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)"
+            v-hasPermi="['qw:welcome:query']"
+          >详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:welcome:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:welcome:remove']"
+          >删除</el-button>
+
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改入群欢迎语管理对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <div v-if="!form.welcomeId">
+          <el-form-item label="欢迎语类型" prop="welcomeType">
+              <el-radio-group v-model="form.welcomeType">
+                <el-radio :label="item.dictValue" v-for="item in welcomeTypeOptions">{{item.dictLabel}}</el-radio>
+              </el-radio-group>
+          </el-form-item>
+        </div>
+        <el-form-item label="消息文本内容" prop="textContent">
+          <el-input v-model="form.textContent" type="textarea" :rows="6" maxlength="1300" show-word-limit placeholder="请输入消息文本内容(图片,视频等附件不上传,则默认为纯文本欢迎语)" />
+        </el-form-item>
+        <div v-if="form.welcomeType=='1'">
+          <el-form-item label="图片" prop="imagePicUrl">
+            <ImageUpload v-model="form.imagePicUrl"  type="image" :num="10" :width="150" :height="150"  disabled/>
+          </el-form-item>
+        </div>
+        <div v-if="form.welcomeType=='2'">
+          <el-form-item label="图文标题" prop="linkTitle" required>
+            <el-input v-model="form.linkTitle" type="textarea" :rows="2" maxlength="42" show-word-limit placeholder="请输入图文消息标题,最长为42字节" />
+          </el-form-item>
+          <el-form-item label="上传图文封面" prop="linkPicurl">
+            <ImageUpload v-model="form.linkPicurl"  type="image" :num="10" :width="150" :height="150" />
+          </el-form-item>
+          <el-form-item label="图文的描述" prop="linkDesc">
+            <el-input v-model="form.linkDesc" type="textarea" :rows="3" maxlength="170" show-word-limit placeholder="请输入内容,,最长为170字节" />
+          </el-form-item>
+          <el-form-item label="图文的链接" prop="linkUrl" required>
+<!--            <ImageUpload v-model="form.linkUrl"   type="image" :num="10" :width="150" :height="150" />-->
+            <el-input v-model="form.linkUrl" placeholder="请输入图文的URL链接" />
+          </el-form-item>
+        </div>
+
+        <div v-if="form.welcomeType=='3'">
+          <el-form-item label="小程序标题" prop="miniprogramTitle">
+            <el-input v-model="form.miniprogramTitle" type="textarea" maxlength="21" show-word-limit placeholder="请输入小程序消息标题,最长为21字节"  />
+          </el-form-item>
+          <el-form-item label="上传小程序封面" prop="miniprogramPicUrl">
+            <ImageUpload v-model="form.miniprogramPicUrl"  type="image" :num="10" :width="150" :height="150" />
+          </el-form-item>
+          <el-form-item label="小程序appid" prop="miniprogramAppid">
+            <el-input v-model="form.miniprogramAppid" placeholder="请输入小程序appid,必须是关联到企业的小程序应用" />
+          </el-form-item>
+          <el-form-item label="小程序page路径" prop="miniprogramPage">
+            <el-input v-model="form.miniprogramPage" placeholder="请输入小程序page路径" />
+          </el-form-item>
+        </div>
+
+        <div v-if="form.welcomeType=='4'">
+          <el-form-item label="上传文件" prop="fileUrl">
+            <el-upload v-if="form.fileUrl==null || form.welcomeId"
+                       v-model="form.fileUrl"
+                       class="avatar-uploader"
+                       :action="uploadUrl"
+                       :show-file-list="false"
+                       :on-success="handleAvatarSuccessFile"
+                       :before-upload="beforeAvatarUploadFile">
+              <i class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <el-link v-if="form.fileUrl" type="primary" :href="downloadUrl(form.fileUrl)" download>
+              {{form.fileUrl}}
+            </el-link>
+          </el-form-item>
+        </div>
+
+        <div v-if="form.welcomeType=='5'">
+          <el-form-item label="上传视频" prop="videoUrl">
+            <el-upload v-if="form.videoUrl==null || form.welcomeId"
+                       v-model="form.videoUrl"
+                       class="avatar-uploader"
+                       :action="uploadUrl"
+                       :show-file-list="false"
+                       :on-success="handleAvatarSuccessVideo"
+                       :before-upload="beforeAvatarUploadVideo">
+              <i class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <video v-if="form.videoUrl"
+                   :src="form.videoUrl"
+                   controls style="width: 200px;height: 100px">
+            </video>
+          </el-form-item>
+        </div>
+        <div v-if="!form.welcomeId">
+          <el-form-item label="是否通知成员" prop="notify">
+            <el-radio-group v-model="form.notify">
+              <el-radio :label="item.dictValue" v-for="item in sysNoticeStatus">{{item.dictLabel}}</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </div>
+
+      </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>
+
+    <!-- 大图预览对话框 -->
+    <el-dialog
+      :visible.sync="dialogVisible"
+      :modal="false"
+      width="1200"
+      append-to-body>
+      <img
+        :src="this.dialogImageUrl"
+        style="display: block; max-width: 100%; margin: 0 auto"
+      />
+    </el-dialog>
+  </div>
+
+    <!--详情    -->
+  <el-drawer :title="details.title" :visible.sync="details.open" size="45%" append-to-body>
+      <el-card style="background-color:  rgb(240 242 245)">
+        <el-descriptions :column="1" border  :labelStyle="{width: '130px'}" >
+          <el-descriptions-item label="欢迎语企微id:">
+            <span>{{form.templateId}}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="消息文本内容:">
+            <span class="custom-span">{{form.textContent}}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="图片" v-if="form.welcomeType=='1'">
+            <el-image
+              v-if="form.imagePicUrl"
+              style="width: 100px; height: 100px"
+              :src="form.imagePicUrl"
+              fit="contain"
+              @click="openImageViewer(form.imagePicUrl)"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="图文标题:" v-if="form.welcomeType=='2'">
+            <span class="custom-span-title">{{form.linkTitle}}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="图文封面:" v-if="form.welcomeType=='2'">
+            <el-image
+              v-if="form.linkPicurl"
+              style="width: 100px; height: 100px"
+              :src="form.linkPicurl"
+              fit="contain"
+              @click="openImageViewer(form.linkPicurl)"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="图文的描述:" v-if="form.welcomeType=='2'">
+            <span class="custom-span">{{form.linkDesc}}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="图文的链接:" v-if="form.welcomeType=='2'">
+            <el-link>{{form.linkUrl}}</el-link>
+<!--            <el-image-->
+<!--              v-if="form.linkUrl"-->
+<!--              style="width: 100px; height: 100px"-->
+<!--              :src="form.linkUrl"-->
+<!--              fit="contain"-->
+<!--              @click="openImageViewer(form.linkUrl)"/>-->
+          </el-descriptions-item>
+          <el-descriptions-item label="小程序标题:" v-if="form.welcomeType=='3'">{{form.miniprogramTitle}}</el-descriptions-item>
+          <el-descriptions-item label="小程序封面:" v-if="form.welcomeType=='3'">
+            <el-image
+              v-if="form.miniprogramPicUrl"
+              style="width: 100px; height: 100px"
+              :src="form.miniprogramPicUrl"
+              fit="contain"
+              @click="openImageViewer(form.miniprogramPicUrl)"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="小程序appid:" v-if="form.welcomeType=='3'">{{form.miniprogramAppid}}</el-descriptions-item>
+          <el-descriptions-item label="小程序page路径:" v-if="form.welcomeType=='3'">{{form.miniprogramPage}}</el-descriptions-item>
+          <el-descriptions-item label="企微临时文件mediaId:" v-if="form.welcomeType=='4'">{{form.fileMediaId}}</el-descriptions-item>
+          <el-descriptions-item label="文件:" v-if="form.welcomeType=='4'">
+            <el-link v-if="form.fileUrl" type="primary" :href="form.fileUrl" download>
+              {{form.fileUrl}}
+            </el-link>
+          </el-descriptions-item>
+          <el-descriptions-item label="视频临时文件mediaId:" v-if="form.welcomeType=='5'">{{form.videoMediaId}}</el-descriptions-item>
+          <el-descriptions-item label="视频:" v-if="form.welcomeType=='5'">
+            <video v-if="form.videoUrl"
+                   :src="form.videoUrl"
+                   controls style="width: 200px;height: 100px">
+            </video>
+          </el-descriptions-item>
+          <el-descriptions-item label="是否通知成员:" >
+            <!-- 使用 v-if 来筛选并显示匹配的项 -->
+            <span v-if="findMatchingItem(sysNoticeStatus, form.notify)">
+            {{ findMatchingItem(sysNoticeStatus, form.notify).dictLabel }}
+          </span>
+          </el-descriptions-item>
+          <el-descriptions-item label="创建人:">{{form.createName}}</el-descriptions-item>
+
+        </el-descriptions>
+      </el-card>
+  </el-drawer>
+
+
+  </div>
+</template>
+
+<script>
+import { listWelcome, getWelcome, delWelcome, addWelcome, updateWelcome, exportWelcome } from "@/api/qw/welcome";
+import ImageUpload from "@/views/qw/material/ImageUpload";
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+
+export default {
+  name: "deptWelcomeIndex",
+  components: {ImageUpload},
+
+  data() {
+    return {
+      //上传地址
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      //放大图片
+      dialogImageUrl:null,
+      dialogVisible:false,
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      myQwCompanyList:[],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 入群欢迎语管理表格数据
+      welcomeList: [],
+      //欢迎语类型
+      welcomeTypeOptions:[],
+      //通知类型
+      sysNoticeStatus:[].map(item => {
+          return { ...item, dictValue: parseInt(item.dictValue, 10) }; // 转换为整数
+      }),
+      formData:null,
+      //文件1图片,文件,视频,音频,图文的封面
+      FileOne:'',
+
+      //文件2 用来存上传图文的图片
+      FileTwo:'',
+
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+
+      details:{
+        title:"",
+        open:false,
+      },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        templateId: null,
+        welcomeType: null,
+        textContent: null,
+        imageMediaId: null,
+        imagePicUrl: null,
+        linkTitle: null,
+        linkPicurl: null,
+        linkDesc: null,
+        linkUrl: null,
+        miniprogramTitle: null,
+        miniprogramPicMediaId: null,
+        miniprogramPicUrl: null,
+        miniprogramAppid: null,
+        miniprogramPage: null,
+        fileMediaId: null,
+        videoMediaId: null,
+        fileUrl: null,
+        notify: null,
+        corpId: null,
+        videoUrl: null,
+        companyId: null,
+        createName: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        welcomeType:[
+          {required:true,message:"类型不能为空",trigger:"blur"}
+        ],
+        textContent:[
+          {required:true,message:"消息文本不能为空",trigger:"blur"}
+        ],
+        linkUrl:[
+          {required:true,message:"链接不能为空",trigger:"blur"}
+        ]
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyList().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              this.getList();
+            }
+        });
+    //文本类型字典
+    this.getDicts("sys_qw_welcome_type").then(response => {
+      this.welcomeTypeOptions = response.data;
+    });
+
+    this.getDicts("sys_company_status").then(response => {
+      this.sysNoticeStatus = response.data;
+    });
+
+  },
+  methods: {
+    updateCorpId(){
+           this.getList();
+    },
+    /** 查询入群欢迎语管理列表 */
+    getList() {
+      this.loading = true;
+      listWelcome(this.queryParams).then(response => {
+        this.welcomeList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    handleAvatarSuccessFile(res, file) {
+      console.log("filefile",file)
+      if(res.code==200){
+        this.form.fileUrl=res.url;
+        // this.FileOne=file
+        this.FileOne=file.raw
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
+    handleAvatarSuccessVideo(res, file) {
+
+      if(res.code==200){
+        this.form.videoUrl=res.url;
+        // this.self.$forceUpdate()
+        this.FileOne=file.raw
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
+    beforeAvatarUploadFile(file){
+      const isLt1M = file.size / 1024 / 1024 < 10;
+      if (!isLt1M) {
+        this.$message.error('上传大小不能超过 10MB!');
+      }
+      return isLt1M;
+    },
+    beforeAvatarUploadVideo(file){
+      const isLt1M = file.size / 1024 / 1024 < 10;
+      if (!isLt1M) {
+        this.$message.error('上传大小不能超过 10MB!');
+      }
+      return isLt1M;
+    },
+    openImageViewer(url) {
+      // 打开大图预览对话框
+      this.dialogImageUrl=url
+      this.dialogVisible = true;
+    },
+    //下载文件
+    downloadUrl(materialUrl) {
+      // 直接返回文件 URL
+      return materialUrl;
+    },
+    findMatchingItem(items, value) {
+      // 遍历 items 数组以找到匹配项
+      return items.find(item => item.dictValue == value) || null;
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        welcomeId: null,
+        templateId: null,
+        welcomeType: null,
+        textContent: null,
+        imageMediaId: null,
+        imagePicUrl: null,
+        linkTitle: null,
+        linkPicurl: null,
+        linkDesc: null,
+        linkUrl: null,
+        miniprogramTitle: null,
+        miniprogramPicMediaId: null,
+        miniprogramPicUrl: null,
+        miniprogramAppid: null,
+        miniprogramPage: null,
+        fileMediaId: null,
+        fileUrl: null,
+        videoMediaId: null,
+        videoUrl: null,
+        notify: null,
+        corpId: null,
+        companyId: null,
+        updateTime: null,
+        createTime: null,
+        createName: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.welcomeId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.form.welcomeType="1"
+      this.form.notify="1"
+      this.title = "添加入群欢迎语";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const welcomeId = row.welcomeId || this.ids
+      getWelcome(welcomeId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改入群欢迎语";
+      });
+    },
+
+    hangdleDitels(row){
+      this.reset();
+      const welcomeId = row.welcomeId || this.ids
+      getWelcome(welcomeId).then(response => {
+        this.form = response.data;
+        this.details.open = true;
+        this.details.title = "欢迎语详情";
+      });
+    },
+    // async urlToFile(url) {
+    //   const response = await fetch(url);
+    //   const data = await response.blob();
+    //   const filename = url.split('/').pop();
+    //   return new File([data], filename, { type: data.type });
+    // },
+
+    /** 提交按钮 */
+    submitForm() {
+
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.corpId=this.queryParams.corpId;
+          if (this.form.welcomeId != null) {
+            updateWelcome(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addWelcome(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const welcomeIds = row.welcomeId || this.ids;
+      this.$confirm('是否确认删除入群欢迎语编号为"' + welcomeIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delWelcome(welcomeIds,row.templateId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+
+  }
+};
+</script>
+<style scoped>
+.flex-container {
+  display: flex; /* 启用Flexbox布局 */
+  flex-direction: column; /* 子元素垂直排列 */
+  align-items: flex-start; /* 子元素在主轴上(水平)从左到右排列 */
+}
+
+.flex-container > div {
+  width: 100%; /* 确保每个子div宽度充满容器宽度 */
+}
+.text-container {
+  max-height: 8.5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+.text-container-title{
+  margin-top: 10px;
+  max-height: 5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+.custom-span {
+  display: block; /* 确保元素是块级元素 */
+  height: 150px; /* 设置固定高度 */
+  overflow-y: auto; /* 超出高度时显示滚动条 */
+  word-wrap: break-word; /* 自动换行 */
+  word-break: break-all; /* 在必要时进行换行 */
+}
+.custom-span-title {
+  display: block; /* 确保元素是块级元素 */
+  height: 45px; /* 设置固定高度 */
+  overflow-y: auto; /* 超出高度时显示滚动条 */
+  word-wrap: break-word; /* 自动换行 */
+  word-break: break-all; /* 在必要时进行换行 */
+}
+</style>

+ 701 - 0
src/views/qw/welcome/myWelcome.vue

@@ -0,0 +1,701 @@
+<template>
+  <div>
+  <div class="app-container">
+    <el-alert
+      title="注意事项"
+      type="warning"
+      description="因企业微信接口限制,1、在【企业微信后台】群欢迎语素材库进行新增/编辑/删除操作,后台不会同步更新,建议在后台入群欢迎语处进行管理。
+       2、 注意:企业微信入群欢迎语素材库中,最多容纳100个素材,包括后台管理的以及企业微信后台管理的。
+       3、除图片外,其他附件素材均只有三天时效,若要续用,请点击修改-》直接点击-确认后,刷新时效"
+      :closable="false"
+      center
+      show-icon>
+    </el-alert>
+  </div>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" >
+      <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="createName">
+        <el-input
+          v-model="queryParams.textContent"
+          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-item>
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            size="mini"
+            icon="el-icon-plus"
+            @click="handleAdd"
+            v-hasPermi="['qw:welcome:add']"
+          >新增</el-button>
+        </el-col>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="welcomeList" border>
+      <el-table-column label="欢迎语类型" align="center" prop="welcomeType" >
+        <template slot-scope="scope">
+          <span   v-for="(item, index) in welcomeTypeOptions"    v-if="scope.row.welcomeType==item.dictValue">{{item.dictLabel}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="欢迎消息文本" align="left" width="600px" >
+        <template slot-scope="scope">
+          <div class="flex-container">
+            <el-tooltip class="item" effect="dark" :content="scope.row.textContent" placement="top">
+              <div style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; text-overflow: ellipsis;">
+                <span>文本消息:</span>{{ scope.row.textContent }}
+              </div>
+            </el-tooltip>
+            <div v-if="scope.row.welcomeType == '1'">
+              <div style="float: left">
+              <span>图片:</span>
+              <el-image v-if="scope.row.imagePicUrl"
+                style="width: 50px; height: 50px"
+                :src="scope.row.imagePicUrl"
+                fit="contain" />
+                <span v-if="!scope.row.imagePicUrl">无图片</span>
+              </div>
+            </div>
+            <div v-if="scope.row.welcomeType=='2'">
+              <div style="float: left;margin-top: 10px">
+                <el-tooltip class="item" effect="dark" :content="scope.row.linkTitle" placement="top">
+                  <div style="float: left; overflow-y: hidden; height: 50px">
+                    <span>图文标题:</span>{{ scope.row.linkTitle }}
+                  </div>
+                </el-tooltip>
+                <div>
+                  <el-image v-if="scope.row.linkPicurl"
+                            style="width: 50px; height: 50px"
+                            :src="scope.row.linkPicurl"
+                            fit="contain" />
+                </div>
+
+              </div>
+            </div>
+
+            <div v-if="scope.row.welcomeType=='3'">
+              <div style="float: left">
+                <span>小程序标题:</span>{{scope.row.miniprogramTitle}}
+                <div>
+                  <el-image v-if="scope.row.miniprogramPicUrl"
+                            style="width: 50px; height: 50px"
+                            :src="scope.row.miniprogramPicUrl"
+                            fit="contain" />
+                </div>
+              </div>
+            </div>
+
+            <div v-if="scope.row.welcomeType=='4'">
+              <div style="float: left">
+                <span>文件:</span>
+                <span>请查看详情</span>
+              </div>
+            </div>
+
+            <div v-if="scope.row.welcomeType=='5'">
+              <div style="float: left">
+                <span>视频:</span>
+                <span>请查看详情</span>
+              </div>
+            </div>
+          </div>
+        </template>
+
+      </el-table-column>
+      <el-table-column label="创建人" align="center" prop="createName" />
+      <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)"
+            v-hasPermi="['qw:welcome:query']"
+          >详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:welcome:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:welcome:remove']"
+          >删除</el-button>
+
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改入群欢迎语管理对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <div v-if="!form.welcomeId">
+          <el-form-item label="欢迎语类型" prop="welcomeType">
+              <el-radio-group v-model="form.welcomeType">
+                <el-radio :label="item.dictValue" v-for="item in welcomeTypeOptions">{{item.dictLabel}}</el-radio>
+              </el-radio-group>
+          </el-form-item>
+        </div>
+        <el-form-item label="消息文本内容" prop="textContent">
+          <el-input v-model="form.textContent" type="textarea" :rows="6" maxlength="1300" show-word-limit placeholder="请输入消息文本内容(图片,视频等附件不上传,则默认为纯文本欢迎语)" />
+        </el-form-item>
+        <div v-if="form.welcomeType=='1'">
+          <el-form-item label="图片" prop="imagePicUrl">
+            <ImageUpload v-model="form.imagePicUrl"  type="image" :num="10" :width="150" :height="150"  disabled/>
+          </el-form-item>
+        </div>
+        <div v-if="form.welcomeType=='2'">
+          <el-form-item label="图文标题" prop="linkTitle" required>
+            <el-input v-model="form.linkTitle" type="textarea" :rows="2" maxlength="42" show-word-limit placeholder="请输入图文消息标题,最长为42字节" />
+          </el-form-item>
+          <el-form-item label="上传图文封面" prop="linkPicurl">
+            <ImageUpload v-model="form.linkPicurl"  type="image" :num="10" :width="150" :height="150" />
+          </el-form-item>
+          <el-form-item label="图文的描述" prop="linkDesc">
+            <el-input v-model="form.linkDesc" type="textarea" :rows="3" maxlength="170" show-word-limit placeholder="请输入内容,,最长为170字节" />
+          </el-form-item>
+          <el-form-item label="图文的链接" prop="linkUrl" required>
+<!--            <ImageUpload v-model="form.linkUrl"   type="image" :num="10" :width="150" :height="150" />-->
+            <el-input v-model="form.linkUrl" placeholder="请输入图文的URL链接" />
+          </el-form-item>
+        </div>
+
+        <div v-if="form.welcomeType=='3'">
+          <el-form-item label="小程序标题" prop="miniprogramTitle">
+            <el-input v-model="form.miniprogramTitle" type="textarea" maxlength="21" show-word-limit placeholder="请输入小程序消息标题,最长为21字节"  />
+          </el-form-item>
+          <el-form-item label="上传小程序封面" prop="miniprogramPicUrl">
+            <ImageUpload v-model="form.miniprogramPicUrl"  type="image" :num="10" :width="150" :height="150" />
+          </el-form-item>
+          <el-form-item label="小程序appid" prop="miniprogramAppid">
+            <el-input v-model="form.miniprogramAppid" placeholder="请输入小程序appid,必须是关联到企业的小程序应用" />
+          </el-form-item>
+          <el-form-item label="小程序page路径" prop="miniprogramPage">
+            <el-input v-model="form.miniprogramPage" placeholder="请输入小程序page路径" />
+          </el-form-item>
+        </div>
+
+        <div v-if="form.welcomeType=='4'">
+          <el-form-item label="上传文件" prop="fileUrl">
+            <el-upload v-if="form.fileUrl==null || form.welcomeId"
+                       v-model="form.fileUrl"
+                       class="avatar-uploader"
+                       :action="uploadUrl"
+                       :show-file-list="false"
+                       :on-success="handleAvatarSuccessFile"
+                       :before-upload="beforeAvatarUploadFile">
+              <i class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <el-link v-if="form.fileUrl" type="primary" :href="downloadUrl(form.fileUrl)" download>
+              {{form.fileUrl}}
+            </el-link>
+          </el-form-item>
+        </div>
+
+        <div v-if="form.welcomeType=='5'">
+          <el-form-item label="上传视频" prop="videoUrl">
+            <el-upload v-if="form.videoUrl==null || form.welcomeId"
+                       v-model="form.videoUrl"
+                       class="avatar-uploader"
+                       :action="uploadUrl"
+                       :show-file-list="false"
+                       :on-success="handleAvatarSuccessVideo"
+                       :before-upload="beforeAvatarUploadVideo">
+              <i class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <video v-if="form.videoUrl"
+                   :src="form.videoUrl"
+                   controls style="width: 200px;height: 100px">
+            </video>
+          </el-form-item>
+        </div>
+        <div v-if="!form.welcomeId">
+          <el-form-item label="是否通知成员" prop="notify">
+            <el-radio-group v-model="form.notify">
+              <el-radio :label="item.dictValue" v-for="item in sysNoticeStatus">{{item.dictLabel}}</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </div>
+
+      </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>
+
+    <!-- 大图预览对话框 -->
+    <el-dialog
+      :visible.sync="dialogVisible"
+      :modal="false"
+      width="1200"
+      append-to-body>
+      <img
+        :src="this.dialogImageUrl"
+        style="display: block; max-width: 100%; margin: 0 auto"
+      />
+    </el-dialog>
+  </div>
+
+    <!--详情    -->
+  <el-drawer :title="details.title" :visible.sync="details.open" size="45%" append-to-body>
+      <el-card style="background-color:  rgb(240 242 245)">
+        <el-descriptions :column="1" border  :labelStyle="{width: '130px'}" >
+          <el-descriptions-item label="欢迎语企微id:">
+            <span>{{form.templateId}}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="消息文本内容:">
+            <span class="custom-span">{{form.textContent}}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="图片" v-if="form.welcomeType=='1'">
+            <el-image
+              v-if="form.imagePicUrl"
+              style="width: 100px; height: 100px"
+              :src="form.imagePicUrl"
+              fit="contain"
+              @click="openImageViewer(form.imagePicUrl)"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="图文标题:" v-if="form.welcomeType=='2'">
+            <span class="custom-span-title">{{form.linkTitle}}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="图文封面:" v-if="form.welcomeType=='2'">
+            <el-image
+              v-if="form.linkPicurl"
+              style="width: 100px; height: 100px"
+              :src="form.linkPicurl"
+              fit="contain"
+              @click="openImageViewer(form.linkPicurl)"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="图文的描述:" v-if="form.welcomeType=='2'">
+            <span class="custom-span">{{form.linkDesc}}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="图文的链接:" v-if="form.welcomeType=='2'">
+            <el-link>{{form.linkUrl}}</el-link>
+<!--            <el-image-->
+<!--              v-if="form.linkUrl"-->
+<!--              style="width: 100px; height: 100px"-->
+<!--              :src="form.linkUrl"-->
+<!--              fit="contain"-->
+<!--              @click="openImageViewer(form.linkUrl)"/>-->
+          </el-descriptions-item>
+          <el-descriptions-item label="小程序标题:" v-if="form.welcomeType=='3'">{{form.miniprogramTitle}}</el-descriptions-item>
+          <el-descriptions-item label="小程序封面:" v-if="form.welcomeType=='3'">
+            <el-image
+              v-if="form.miniprogramPicUrl"
+              style="width: 100px; height: 100px"
+              :src="form.miniprogramPicUrl"
+              fit="contain"
+              @click="openImageViewer(form.miniprogramPicUrl)"/>
+          </el-descriptions-item>
+          <el-descriptions-item label="小程序appid:" v-if="form.welcomeType=='3'">{{form.miniprogramAppid}}</el-descriptions-item>
+          <el-descriptions-item label="小程序page路径:" v-if="form.welcomeType=='3'">{{form.miniprogramPage}}</el-descriptions-item>
+          <el-descriptions-item label="企微临时文件mediaId:" v-if="form.welcomeType=='4'">{{form.fileMediaId}}</el-descriptions-item>
+          <el-descriptions-item label="文件:" v-if="form.welcomeType=='4'">
+            <el-link v-if="form.fileUrl" type="primary" :href="form.fileUrl" download>
+              {{form.fileUrl}}
+            </el-link>
+          </el-descriptions-item>
+          <el-descriptions-item label="视频临时文件mediaId:" v-if="form.welcomeType=='5'">{{form.videoMediaId}}</el-descriptions-item>
+          <el-descriptions-item label="视频:" v-if="form.welcomeType=='5'">
+            <video v-if="form.videoUrl"
+                   :src="form.videoUrl"
+                   controls style="width: 200px;height: 100px">
+            </video>
+          </el-descriptions-item>
+          <el-descriptions-item label="是否通知成员:" >
+            <!-- 使用 v-if 来筛选并显示匹配的项 -->
+            <span v-if="findMatchingItem(sysNoticeStatus, form.notify)">
+            {{ findMatchingItem(sysNoticeStatus, form.notify).dictLabel }}
+          </span>
+          </el-descriptions-item>
+          <el-descriptions-item label="创建人:">{{form.createName}}</el-descriptions-item>
+
+        </el-descriptions>
+      </el-card>
+  </el-drawer>
+
+
+  </div>
+</template>
+
+<script>
+import { listWelcome, getWelcome, delWelcome, addWelcome, updateWelcome, exportWelcome } from "@/api/qw/welcome";
+import ImageUpload from "@/views/qw/material/ImageUpload";
+import { getMyQwUserList,getMyQwCompanyList } from "@/api/qw/user";
+
+export default {
+  name: "myWelcome",
+  components: {ImageUpload},
+
+  data() {
+    return {
+      //上传地址
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      //放大图片
+      dialogImageUrl:null,
+      dialogVisible:false,
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      myQwCompanyList:[],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 入群欢迎语管理表格数据
+      welcomeList: [],
+      //欢迎语类型
+      welcomeTypeOptions:[],
+      //通知类型
+      sysNoticeStatus:[].map(item => {
+          return { ...item, dictValue: parseInt(item.dictValue, 10) }; // 转换为整数
+      }),
+      formData:null,
+      //文件1图片,文件,视频,音频,图文的封面
+      FileOne:'',
+
+      //文件2 用来存上传图文的图片
+      FileTwo:'',
+
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+
+      details:{
+        title:"",
+        open:false,
+      },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        templateId: null,
+        welcomeType: null,
+        textContent: null,
+        imageMediaId: null,
+        imagePicUrl: null,
+        linkTitle: null,
+        linkPicurl: null,
+        linkDesc: null,
+        linkUrl: null,
+        miniprogramTitle: null,
+        miniprogramPicMediaId: null,
+        miniprogramPicUrl: null,
+        miniprogramAppid: null,
+        miniprogramPage: null,
+        fileMediaId: null,
+        videoMediaId: null,
+        fileUrl: null,
+        notify: null,
+        corpId: null,
+        videoUrl: null,
+        companyId: null,
+        createName: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        welcomeType:[
+          {required:true,message:"类型不能为空",trigger:"blur"}
+        ],
+        textContent:[
+          {required:true,message:"消息文本不能为空",trigger:"blur"}
+        ],
+        linkUrl:[
+          {required:true,message:"链接不能为空",trigger:"blur"}
+        ]
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyList().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              this.getList();
+            }
+        });
+    //文本类型字典
+    this.getDicts("sys_qw_welcome_type").then(response => {
+      this.welcomeTypeOptions = response.data;
+    });
+
+    this.getDicts("sys_company_status").then(response => {
+      this.sysNoticeStatus = response.data;
+    });
+
+  },
+  methods: {
+    updateCorpId(){
+           this.getList();
+    },
+    /** 查询入群欢迎语管理列表 */
+    getList() {
+      this.loading = true;
+      listWelcome(this.queryParams).then(response => {
+        this.welcomeList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    handleAvatarSuccessFile(res, file) {
+      console.log("filefile",file)
+      if(res.code==200){
+        this.form.fileUrl=res.url;
+        // this.FileOne=file
+        this.FileOne=file.raw
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
+    handleAvatarSuccessVideo(res, file) {
+
+      if(res.code==200){
+        this.form.videoUrl=res.url;
+        // this.self.$forceUpdate()
+        this.FileOne=file.raw
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
+    beforeAvatarUploadFile(file){
+      const isLt1M = file.size / 1024 / 1024 < 10;
+      if (!isLt1M) {
+        this.$message.error('上传大小不能超过 10MB!');
+      }
+      return isLt1M;
+    },
+    beforeAvatarUploadVideo(file){
+      const isLt1M = file.size / 1024 / 1024 < 10;
+      if (!isLt1M) {
+        this.$message.error('上传大小不能超过 10MB!');
+      }
+      return isLt1M;
+    },
+    openImageViewer(url) {
+      // 打开大图预览对话框
+      this.dialogImageUrl=url
+      this.dialogVisible = true;
+    },
+    //下载文件
+    downloadUrl(materialUrl) {
+      // 直接返回文件 URL
+      return materialUrl;
+    },
+    findMatchingItem(items, value) {
+      // 遍历 items 数组以找到匹配项
+      return items.find(item => item.dictValue == value) || null;
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        welcomeId: null,
+        templateId: null,
+        welcomeType: null,
+        textContent: null,
+        imageMediaId: null,
+        imagePicUrl: null,
+        linkTitle: null,
+        linkPicurl: null,
+        linkDesc: null,
+        linkUrl: null,
+        miniprogramTitle: null,
+        miniprogramPicMediaId: null,
+        miniprogramPicUrl: null,
+        miniprogramAppid: null,
+        miniprogramPage: null,
+        fileMediaId: null,
+        fileUrl: null,
+        videoMediaId: null,
+        videoUrl: null,
+        notify: null,
+        corpId: null,
+        companyId: null,
+        updateTime: null,
+        createTime: null,
+        createName: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.welcomeId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.form.welcomeType="1"
+      this.form.notify="1"
+      this.title = "添加入群欢迎语";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const welcomeId = row.welcomeId || this.ids
+      getWelcome(welcomeId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改入群欢迎语";
+      });
+    },
+
+    hangdleDitels(row){
+      this.reset();
+      const welcomeId = row.welcomeId || this.ids
+      getWelcome(welcomeId).then(response => {
+        this.form = response.data;
+        this.details.open = true;
+        this.details.title = "欢迎语详情";
+      });
+    },
+    // async urlToFile(url) {
+    //   const response = await fetch(url);
+    //   const data = await response.blob();
+    //   const filename = url.split('/').pop();
+    //   return new File([data], filename, { type: data.type });
+    // },
+
+    /** 提交按钮 */
+    submitForm() {
+
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.corpId=this.queryParams.corpId;
+          if (this.form.welcomeId != null) {
+            updateWelcome(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addWelcome(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const welcomeIds = row.welcomeId || this.ids;
+      this.$confirm('是否确认删除入群欢迎语编号为"' + welcomeIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delWelcome(welcomeIds,row.templateId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+
+  }
+};
+</script>
+<style scoped>
+.flex-container {
+  display: flex; /* 启用Flexbox布局 */
+  flex-direction: column; /* 子元素垂直排列 */
+  align-items: flex-start; /* 子元素在主轴上(水平)从左到右排列 */
+}
+
+.flex-container > div {
+  width: 100%; /* 确保每个子div宽度充满容器宽度 */
+}
+.text-container {
+  max-height: 8.5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+.text-container-title{
+  margin-top: 10px;
+  max-height: 5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+.custom-span {
+  display: block; /* 确保元素是块级元素 */
+  height: 150px; /* 设置固定高度 */
+  overflow-y: auto; /* 超出高度时显示滚动条 */
+  word-wrap: break-word; /* 自动换行 */
+  word-break: break-all; /* 在必要时进行换行 */
+}
+.custom-span-title {
+  display: block; /* 确保元素是块级元素 */
+  height: 45px; /* 设置固定高度 */
+  overflow-y: auto; /* 超出高度时显示滚动条 */
+  word-wrap: break-word; /* 自动换行 */
+  word-break: break-all; /* 在必要时进行换行 */
+}
+</style>

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů