Selaa lähdekoodia

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

ct 1 viikko sitten
vanhempi
commit
1d761a8c30

+ 17 - 1
src/api/qw/QwWorkTask.js

@@ -17,6 +17,14 @@ export function getQwWorkTask(id) {
   })
 }
 
+export function glList(query) {
+  return request({
+    url: '/qw/qw/QwWorkTask/glList',
+    method: 'get',
+    params: query
+  })
+}
+
 // 新增企微任务看板
 export function addQwWorkTask(data) {
   return request({
@@ -50,4 +58,12 @@ export function exportQwWorkTask(query) {
     method: 'get',
     params: query
   })
-}
+}
+
+export function allListQwWorkTask(query) {
+  return request({
+    url: '/qw/qw/QwWorkTask/allList',
+    method: 'get',
+    params: query
+  })
+}

+ 10 - 3
src/components/LemonUI/components/message/emotionDynamic.vue

@@ -16,7 +16,14 @@ export default {
 }
 </script>
 
-
-<style scoped>
-
+<style lang="stylus">
+@import '../../styles/utils/index'
++b(lemon-message-emotion-dynamic)
+  +b(lemon-message)
+    +e(content)
+      width 100px
+      height 100px
+      img
+        width 100%
+        height 100%
 </style>

+ 34 - 6
src/components/LemonUI/components/message/voice.vue

@@ -5,11 +5,11 @@ export default {
   inject: ["IMUI"],
   data() {
     return {
-       
+
     };
   },
   created() {
-    
+
   },
   render() {
     return (
@@ -25,9 +25,18 @@ export default {
     );
   },
    methods: {
-      renderHtml(data){       
-        return <audio block="true" showDuration='false' duration={data.duration} controls src={data.content}  ></audio>;
-        // return <span>{props.content}&nbsp;🔈</span>;
+      renderHtml(data){
+        const {url, content} = JSON.parse(data.content)
+        return <div class="lemon-message-voice-context">
+            <audio block="true" showDuration='false' controls src={url}
+            controlslist='nodownload noplaybackrate'
+            oncontextmenu="return false"/>
+            <div class="lemon-message-voice-context-text">
+              <span>{content}</span>
+              <span class="el-icon-check lemon-message-voice-context-text-transfer">转换完成</span>
+            </div>
+          </div>
+          ;
       }
   }
 };
@@ -38,10 +47,29 @@ export default {
 .lemon-message.lemon-message-voice
   user-select none
   .lemon-message__content
+    background-color unset
     border 0px solid #000
     font-size 12px
     cursor pointer
     &::before
       display none
-
+    .lemon-message-voice-context
+      display flex
+      flex-direction: column
+      audio
+        width 250px
+        height 35px
+        border solid 1px #CCC
+        border-radius 15px
+      .lemon-message-voice-context-text
+        display flex
+        flex-direction: column
+        background-color #FFF
+        padding 5px 10px
+        margin-top 10px
+        border-radius 5px
+        .lemon-message-voice-context-text-transfer
+          margin 10px 0
+          font-size x-small
+          color #999
 </style>

+ 1 - 1
src/views/index.vue

@@ -41,7 +41,7 @@
               企微数量
             </div>
             <div class="card-value highlight">
-              <count-to :start-val="0" :end-val="memberCount" :duration="3600" class="card-panel-num" /></div>
+              <count-to :start-val="0" :end-val="qwMemberNum" :duration="3600" class="card-panel-num" /></div>
             <div class="card-badge">
             </div>
           </div>

+ 46 - 0
src/views/qw/QwWorkTask/index.vue

@@ -53,6 +53,27 @@
           <span :style="getScoreStyle(scope.row.score)">{{ scope.row.score }}</span>
         </template>
       </el-table-column>
+      <el-table-column label="用户过往看课记录" align="center" width="200px">
+        <template slot-scope="scope">
+          <div style="display: flex; gap: 4px; justify-content: center;">
+	        <span
+            v-for="(log, index) in scope.row.logs"
+            :key="index"
+            :style="{
+	            display: 'inline-block',
+	            width: '16px',
+	            height: '16px',
+	            borderRadius: '2px',
+	            backgroundColor:
+	              log === 2 ? '#67C23A' :
+				  log === 3 ? '#f55a4f' :
+				  log === 4 ? '#FFD700' :
+				  '#909399'
+	          }"
+          ></span>
+          </div>
+        </template>
+      </el-table-column>
       <el-table-column label="sop编号" align="center" prop="sopId" />
       <el-table-column label="公司id" align="center" prop="companyName" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@@ -67,6 +88,31 @@
       </el-table-column>
     </el-table>
 
+    <div style="margin-top: 20px; padding: 12px; background: #f8f8f8; border-radius: 4px;" v-if="!isSM">
+      <div style="display: flex; gap: 20px; flex-wrap: wrap;">
+        <div style="display: flex; align-items: center; gap: 8px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #67C23A;"></span>
+          <span>完课</span>
+        </div>
+        <div style="display: flex; align-items: center; gap: 4px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #f55a4f;"></span>
+          <span>待看课</span>
+        </div>
+        <div style="display: flex; align-items: center; gap: 4px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #FFD700;"></span>
+          <span>看课中断</span>
+        </div>
+        <div style="display: flex; align-items: center; gap: 4px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #909399;"></span>
+          <span>没发课</span>
+        </div>
+        <div style="display: flex; align-items: center; gap: 4px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #0bc6ff;"></span>
+          <span>看课中</span>
+        </div>
+      </div>
+    </div>
+
     <pagination
       v-show="total>0"
       :total="total"

+ 102 - 83
src/views/qw/QwWorkTask/qw/allTask.vue

@@ -2,15 +2,17 @@
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
       <el-form-item label="企微账号" prop="qwUserName">
-             <el-input
-               v-model="queryParams.qwUserName"
-               placeholder="请输入企微昵称"
-               clearable
-               size="small"
-               @keyup.enter.native="handleQuery"
-             />
+        <el-input
+          v-model="queryParams.qwUserName"
+          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>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@@ -18,17 +20,17 @@
       </el-form-item>
     </el-form>
 
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
+    <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
 
     <el-table border v-loading="loading" :data="QwWorkTaskList" @selection-change="handleSelectionChange">
-    <el-table-column type="selection" width="55" align="center" />
-    <el-table-column label="企微账号" align="center" prop="qwUserName" />
-	<el-table-column label="销售昵称" align="center" prop="companyUserName" />
-	<el-table-column label="待处理" align="center" prop="status0" />
-	<el-table-column label="已处理" align="center" prop="status1" />
-	<el-table-column label="待处理完课" align="center" prop="status2" />
-	<el-table-column label="已处理完课" align="center" prop="status3" />
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="企微账号" align="center" prop="qwUserName" />
+      <el-table-column label="销售昵称" align="center" prop="companyUserName" />
+      <el-table-column label="待处理" align="center" prop="status0" />
+      <el-table-column label="已处理" align="center" prop="status1" />
+      <el-table-column label="待处理完课" align="center" prop="status2" />
+      <el-table-column label="已处理完课" align="center" prop="status3" />
+      <el-table-column label="时间" align="center" prop="createTime" />
     </el-table>
 
     <pagination
@@ -61,14 +63,14 @@ export default {
   name: "QwWorkTask",
   data() {
     return {
-	  actName:"0",
+      actName:"0",
       // 遮罩层
       loading: true,
       // 导出遮罩层
       exportLoading: false,
       // 选中数组
       ids: [],
-	  myQwUserList:[],
+      myQwUserList:[],
       // 非单个禁用
       single: true,
       // 非多个禁用
@@ -77,6 +79,9 @@ export default {
       showSearch: true,
       // 总条数
       total: 0,
+      sTime:null,
+      eTime:null,
+      createTime:null,
       // 企微任务看板表格数据
       QwWorkTaskList: [],
       // 弹出层标题
@@ -100,7 +105,6 @@ export default {
         sopId: null,
         companyId: null,
         companyUserId: null,
-		qwUserId: null,
       },
       // 表单参数
       form: {},
@@ -110,7 +114,7 @@ export default {
     };
   },
   created() {
-	this.handleGetMyQwUserList();
+    this.handleGetMyQwUserList();
     this.getDicts("sys_qw_work_task_status").then(response => {
       this.statusOptions = response.data;
     });
@@ -119,38 +123,38 @@ export default {
     });
   },
   methods: {
-	getScoreStyle(score) {
-	let backgroundColor = '';
-	  if (score >= 15) {
-		backgroundColor = '#ff4d4f';    // 红色
-	  } else if (score >= 9) {
-		backgroundColor = '#ff7d45';    // 橘红
-	  } else if (score >= 4) {
-		backgroundColor = '#ffec3d';    // 黄色
-	  } else {
-		backgroundColor = '#ffffff';    // 白色
-	  }
-	  return { 
-		'background-color': backgroundColor,
-		'padding': '5px 10px',
-		'border-radius': '4px'
-	  };
-	},
-	formatTime(timeStr) {
-	      if (!timeStr && timeStr !== 0) return '';
-	      
-	      // 处理数字和字符串输入
-	      const str = String(timeStr).padStart(4, '0');
-	      
-	      // 提取有效部分
-	      const hours = str.substring(0, 2);
-	      const minutes = str.substring(2, 4);
-	      
-	      // 简单验证
-	      if (hours > 23 || minutes > 59) return '无效时间';
-	      
-	      return `${hours}:${minutes}`;
-	    },
+    getScoreStyle(score) {
+      let backgroundColor = '';
+      if (score >= 15) {
+        backgroundColor = '#ff4d4f';    // 红色
+      } else if (score >= 9) {
+        backgroundColor = '#ff7d45';    // 橘红
+      } else if (score >= 4) {
+        backgroundColor = '#ffec3d';    // 黄色
+      } else {
+        backgroundColor = '#ffffff';    // 白色
+      }
+      return {
+        'background-color': backgroundColor,
+        'padding': '5px 10px',
+        'border-radius': '4px'
+      };
+    },
+    formatTime(timeStr) {
+      if (!timeStr && timeStr !== 0) return '';
+
+      // 处理数字和字符串输入
+      const str = String(timeStr).padStart(4, '0');
+
+      // 提取有效部分
+      const hours = str.substring(0, 2);
+      const minutes = str.substring(2, 4);
+
+      // 简单验证
+      if (hours > 23 || minutes > 59) return '无效时间';
+
+      return `${hours}:${minutes}`;
+    },
     /** 查询企微任务看板列表 */
     getList() {
       this.loading = true;
@@ -160,10 +164,20 @@ export default {
         this.loading = false;
       });
     },
-	handleClickX(tab, event) {
-	  this.queryParams.status=tab.name;
-	  this.handleQuery();
-	},
+    handleClickX(tab, event) {
+      this.queryParams.status=tab.name;
+      this.handleQuery();
+    },
+    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;
+      }
+
+    },
     // 取消按钮
     cancel() {
       this.open = false;
@@ -184,7 +198,9 @@ export default {
         companyId: null,
         companyUserId: null,
         createTime: null,
-        updateTime: null
+        updateTime: null,
+        sTime:null,
+        eTime:null
       };
       this.resetForm("form");
     },
@@ -193,12 +209,15 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
-	handleGetMyQwUserList(){
-	 this.getList();
-	},
+    handleGetMyQwUserList(){
+      this.getList();
+    },
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.createTime=null;
+      this.queryParams.sTime=null;
+      this.queryParams.eTime=null;
       this.handleQuery();
     },
     // 多选框选中数据
@@ -217,9 +236,9 @@ export default {
     handleUpdate(row) {
       this.reset();
       const id = row.id || this.ids
-        this.form = row;
-        this.open = true;
-        this.title = "处理任务";
+      this.form = row;
+      this.open = true;
+      this.title = "处理任务";
 
     },
     /** 提交按钮 */
@@ -246,30 +265,30 @@ export default {
     handleDelete(row) {
       const ids = row.id || this.ids;
       this.$confirm('是否确认删除企微任务看板编号为"' + ids + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delQwWorkTask(ids);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delQwWorkTask(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有企微任务看板数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportQwWorkTask(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportQwWorkTask(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 415 - 170
src/views/qw/QwWorkTask/qw/index.vue

@@ -2,14 +2,14 @@
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
       <el-form-item label="企微账号" prop="qwUserId">
-              <el-select v-model="queryParams.qwUserId" placeholder="企微账号"  size="small" @change="updateQwuser()">
-                <el-option
-                  v-for="dict in myQwUserList"
-                  :key="dict.dictValue"
-                  :label="dict.dictLabel+'('+dict.corpName+')'"
-                  :value="dict.dictValue"
-                />
-              </el-select>
+        <el-select v-model="queryParams.qwUserId" placeholder="企微账号"  size="small" @change="updateQwuser()">
+          <el-option
+            v-for="dict in myQwUserList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel+'('+dict.corpName+')'"
+            :value="dict.dictValue"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item label="类别" prop="type">
         <el-select v-model="queryParams.type" placeholder="请选择类别" clearable size="small">
@@ -22,16 +22,16 @@
         </el-select>
       </el-form-item>
 
-	  <el-form-item label="处理状态" prop="trackType">
-	    <el-select v-model="queryParams.trackType" placeholder="处理状态" clearable size="small">
-	      <el-option
-	        v-for="dict in trackTypeOptions"
-	        :key="dict.dictValue"
-	        :label="dict.dictLabel"
-	        :value="dict.dictValue"
-	      />
-	    </el-select>
-	  </el-form-item>
+      <el-form-item label="处理状态" prop="trackType">
+        <el-select v-model="queryParams.trackType" placeholder="处理状态" clearable size="small">
+          <el-option
+            v-for="dict in trackTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
 
       <el-form-item label="sop编号" prop="sopId">
         <el-input
@@ -45,33 +45,35 @@
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="sm()">色盲模式</el-button>
+
       </el-form-item>
     </el-form>
 
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
-	<el-tabs type="card" v-model="actName" @tab-click="handleClickX">
-	  <el-tab-pane v-for="(item,index) in statusOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
-	</el-tabs>
+    <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
+      <el-tab-pane v-for="(item,index) in statusOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+    </el-tabs>
     <el-table border v-loading="loading" :data="QwWorkTaskList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="客户昵称" align="center" prop="name" />
       <el-table-column label="企微账号" align="center" prop="qwUserName" />
       <el-table-column label="状态" align="center" prop="status">
-		 <template slot-scope="scope">
-		   <dict-tag :options="statusOptions" :value="scope.row.status"/>
-		 </template>
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
       </el-table-column>
       <el-table-column label="类别" align="center" prop="type">
         <template slot-scope="scope">
           <dict-tag :options="typeOptions" :value="scope.row.type"/>
         </template>
       </el-table-column>
-	  <el-table-column label="处理状态" align="center" prop="trackType">
-	    <template slot-scope="scope">
-	      <dict-tag :options="trackTypeOptions" :value="scope.row.trackType"/>
-	    </template>
-	  </el-table-column>
+      <el-table-column label="处理状态" align="center" prop="trackType">
+        <template slot-scope="scope">
+          <dict-tag :options="trackTypeOptions" :value="scope.row.trackType"/>
+        </template>
+      </el-table-column>
       <el-table-column label="标题" align="center" prop="title" />
       <el-table-column label="描述" align="center" prop="description" />
       <el-table-column label="分值" align="center" prop="score">
@@ -79,54 +81,136 @@
           <span :style="getScoreStyle(scope.row.score)">{{ scope.row.score }}</span>
         </template>
       </el-table-column>
-	  <el-table-column label="用户过往看课记录" align="center" width="200px">
-	    <template slot-scope="scope">
-	      <div style="display: flex; gap: 4px; justify-content: center;">
+      <el-table-column label="用户过往看课记录" align="center" width="200px">
+        <template slot-scope="scope">
+          <div style="display: flex; gap: 4px; justify-content: center;" v-if="!isSM">
+			  <span
+          v-for="(log, index) in scope.row.logs"
+          :key="index"
+          :style="{
+				  display: 'inline-block',
+				  width: '16px',
+				  height: '16px',
+				  borderRadius: '2px',
+				  backgroundColor:
+					log === 2 ? '#67C23A' :
+							  log === 3 ? '#f55a4f' :
+							  log === 4 ? '#FFD700' :
+							  log === 1 ? '#0bc6ff' :
+							  '#909399'
+				}"
+        ></span>
+          </div>
+
+          <div style="display: flex; gap: 4px; justify-content: center;" v-if="isSM">
 	        <span
-	          v-for="(log, index) in scope.row.logs"
-	          :key="index"
-	          :style="{
+            v-for="(log, index) in scope.row.logs"
+            :key="index"
+            :style="{
 	            display: 'inline-block',
 	            width: '16px',
 	            height: '16px',
-	            borderRadius: '2px',
-	            backgroundColor:
-	              log === 2 ? '#67C23A' :
-				  log === 3 ? '#f55a4f' :
-				  log === 4 ? '#FFD700' :
-				  '#909399'
+	            borderRadius: log === 2 ? '50%' : log === 4 ? '2px 8px' : '2px',
+	            backgroundColor: log === 3 ? 'transparent' : '#f0f0f0',
+	            border: log === 3 ? '2px solid #666' : '1px solid #ddd',
+	            position: 'relative',
+	            transform: log === 4 ? 'rotate(45deg)' : 'none'
 	          }"
-	        ></span>
-	      </div>
-	    </template>
-	  </el-table-column>
-	    <el-table-column label="最晚看课时间" align="center">
-	        <template slot-scope="scope">
-	          {{ formatTime(scope.row.lastWatchTime) }}
-	        </template>
-	      </el-table-column>
+          >
+	          <!-- 已完成 - 圆形 + 对勾 -->
+	          <span v-if="log === 2" style="
+	            position: absolute;
+	            top: 45%;
+	            left: 50%;
+	            width: 6px;
+	            height: 3px;
+	            border: solid #333;
+	            border-width: 0 0 2px 2px;
+	            transform: translate(-50%, -50%) rotate(-45deg);
+	          "></span>
+
+            <!-- 未完成 - 方框 + 叉 -->
+	          <span v-if="log === 3" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #666;
+	            transform: translate(-50%, -50%) rotate(45deg);"></span>
+	          <span v-if="log === 1" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #666;
+	            transform: translate(-50%, -10%) rotate(-15deg);
+	          "></span>
+
+            <!-- 部分完成 - 菱形 -->
+	          <span v-if="log === 4" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 6px;
+	            height: 6px;
+	            border: 2px solid #333;
+	            transform: translate(-50%, -50%) rotate(-45deg);
+	          "></span>
+
+            <!-- 未开始 - 减号 -->
+	          <span v-if="!log" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 8px;
+	            height: 2px;
+	            background: #999;
+	            transform: translate(-50%, -50%);
+	          "></span>
+
+            <!-- 图像 - 使用img标签 -->
+	          <img v-if="log === 5" src="/path/to/your-image.png" alt="Custom icon" style="
+	            position: absolute;
+	            top: 50%;
+	            left: 50%;
+	            width: 12px;
+	            height: 12px;
+	            transform: translate(-50%, -50%);
+	          ">
+	        </span>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="最晚看课时间" align="center">
+        <template slot-scope="scope">
+          {{ formatTime(scope.row.lastWatchTime) }}
+        </template>
+      </el-table-column>
 
       <el-table-column label="sopId" align="center" prop="sopId" />
+      <el-table-column label="通话时长" align="center" prop="duration" />
       <el-table-column label="创建时间" align="center" prop="createTime" />
       <el-table-column label="修改时间" align="center" prop="updateTime" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button v-if="scope.row.status==0"
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
+                     size="mini"
+                     type="text"
+                     icon="el-icon-edit"
+                     @click="handleUpdate(scope.row)"
           >处理</el-button>
-		  <el-button v-if="scope.row.status==0"
-		    size="mini"
-		    type="text"
-		    @click="handleUpdate2(scope.row)"
-		  >未接通</el-button>
-		  <el-button v-if="scope.row.status==0"
-		    size="mini"
-		    type="text"
-		    @click="handleUpdate3(scope.row)"
-		  >接通</el-button>
+          <el-button v-if="scope.row.status==0"
+                     size="mini"
+                     type="text"
+                     @click="handleUpdate2(scope.row)"
+          >未接通</el-button>
+          <el-button v-if="scope.row.status==0"
+                     size="mini"
+                     type="text"
+                     @click="handleUpdate3(scope.row)"
+          >接通</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -138,20 +222,177 @@
       :limit.sync="queryParams.pageSize"
       @pagination="getList"
     />
+    <div style="margin-top: 20px; padding: 12px; background: #f8f8f8; border-radius: 4px;" v-if="!isSM">
+      <div style="display: flex; gap: 20px; flex-wrap: wrap;">
+        <div style="display: flex; align-items: center; gap: 8px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #67C23A;"></span>
+          <span>完课</span>
+        </div>
+        <div style="display: flex; align-items: center; gap: 4px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #f55a4f;"></span>
+          <span>待看课</span>
+        </div>
+        <div style="display: flex; align-items: center; gap: 4px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #FFD700;"></span>
+          <span>看课中断</span>
+        </div>
+        <div style="display: flex; align-items: center; gap: 4px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #909399;"></span>
+          <span>没发课</span>
+        </div>
+        <div style="display: flex; align-items: center; gap: 4px;">
+          <span style="display: inline-block; width: 16px; height: 16px; border-radius: 2px; background-color: #0bc6ff;"></span>
+          <span>看课中</span>
+        </div>
+      </div>
+    </div>
+
+    <!-- 新增的解释说明区域 -->
+    <div style="margin-top: 20px; padding: 12px; background: #f8f8f8; border-radius: 4px;" v-if="isSM">
+      <div style="display: flex; gap: 20px; flex-wrap: wrap;">
+        <div style="display: flex; align-items: center; gap: 8px;">
+	            <span style="
+	              display: inline-block;
+	              width: 16px;
+	              height: 16px;
+	              border-radius: 50%;
+	              background-color: #f0f0f0;
+	              position: relative;
+	            ">
+	              <span style="
+	                position: absolute;
+	                top: 45%;
+	                left: 50%;
+	                width: 6px;
+	                height: 3px;
+	                border: solid #333;
+	                border-width: 0 0 2px 2px;
+	                transform: translate(-50%, -50%) rotate(-45deg);
+	              "></span>
+	            </span>
+          <span>完课</span>
+        </div>
+
+        <div style="display: flex; align-items: center; gap: 8px;">
+	            <span style="
+	              display: inline-block;
+	              width: 16px;
+	              height: 16px;
+	              border-radius: 2px;
+	              border: 2px solid #666;
+	              background-color: transparent;
+	              position: relative;
+	            ">
+	              <span style="
+	                position: absolute;
+	                top: 50%;
+	                left: 50%;
+	                width: 8px;
+	                height: 2px;
+	                background: #666;
+	                transform: translate(-50%, -50%) rotate(45deg);
+	              "></span>
+	              <span style="
+	                position: absolute;
+	                top: 50%;
+	                left: 50%;
+	                width: 8px;
+	                height: 2px;
+	                background: #666;
+	                transform: translate(-50%, -50%) rotate(-45deg);
+	              "></span>
+	            </span>
+          <span>待看课</span>
+        </div>
+
+        <div style="display: flex; align-items: center; gap: 8px;">
+	            <span style="
+	              display: inline-block;
+	              width: 16px;
+	              height: 16px;
+	              border-radius: 2px 8px;
+	              background-color: #f0f0f0;
+	              border: 1px solid #ddd;
+	              position: relative;
+	              transform: rotate(45deg);
+	            ">
+	              <span style="
+	                position: absolute;
+	                top: 50%;
+	                left: 50%;
+	                width: 6px;
+	                height: 6px;
+	                border: 2px solid #333;
+	                transform: translate(-50%, -50%) rotate(-45deg);
+	              "></span>
+	            </span>
+          <span>看课中断</span>
+        </div>
+
+        <div style="display: flex; align-items: center; gap: 8px;">
+	            <span style="
+	              display: inline-block;
+	              width: 16px;
+	              height: 16px;
+	              border-radius: 2px;
+	              background-color: #f0f0f0;
+	              border: 1px solid #ddd;
+	              position: relative;
+	            ">
+	              <span style="
+	                position: absolute;
+	                top: 50%;
+	                left: 50%;
+	                width: 8px;
+	                height: 2px;
+	                background: #999;
+	                transform: translate(-50%, -50%);
+	              "></span>
+	            </span>
+          <span>没发课</span>
+        </div>
+
+        <div style="display: flex; align-items: center; gap: 8px;">
+			    <span style="
+			      display: inline-block;
+			      width: 16px;
+			      height: 16px;
+			      border-radius: 2px;
+			      background-color: #f0f0f0;
+			      border: 1px solid #ddd;
+			      position: relative;
+			    ">
+			      <span  style="
+			        position: absolute;
+			        top: 50%;
+			        left: 50%;
+			        width: 8px;
+			        height: 2px;
+			        background: #666;
+			        transform: translate(-50%, -10%) rotate(-15deg);
+			      "></span>
+			    </span>
+          <span>看课中</span>
+        </div>
+
+
+      </div>
+    </div>
+
 
     <!-- 添加或修改企微任务看板对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-		<el-form-item label="处理类型" prop="trackType">
-		  <el-select v-model="form.trackType" placeholder="状态" clearable size="small">
-			  <el-option
-				v-for="dict in trackTypeOptions"
-				:key="dict.dictValue"
-				:label="dict.dictLabel"
-				:value="dict.dictValue"
-			  />
-		  </el-select>
-		</el-form-item>
+        <el-form-item label="处理类型" prop="trackType">
+          <el-select v-model="form.trackType" placeholder="状态" clearable size="small">
+            <el-option
+              v-for="dict in trackTypeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item label="描述" prop="description">
           <el-input  v-model="form.description" placeholder="请输入描述"  type="textarea" :rows="3"/>
         </el-form-item>
@@ -165,20 +406,21 @@
 </template>
 
 <script>
-import { listQwWorkTask, getQwWorkTask, delQwWorkTask, addQwWorkTask, updateQwWorkTask, exportQwWorkTask,updateQwWorkTask2,updateQwWorkTask3 } from "@/api/qw/qw/QwWorkTask";
+import { listQwWorkTask, getQwWorkTask, delQwWorkTask, addQwWorkTask, updateQwWorkTask, exportQwWorkTask,updateQwWorkTask2,updateQwWorkTask3 } from "@/api/qw/QwWorkTask";
 import {getMyQwUserList, getMyQwCompanyList, handleInputAuthAppKey, updateUser} from "@/api/qw/user";
 export default {
   name: "QwWorkTask",
   data() {
     return {
-	  actName:"0",
+      actName:"0",
       // 遮罩层
       loading: true,
       // 导出遮罩层
       exportLoading: false,
       // 选中数组
       ids: [],
-	  myQwUserList:[],
+      isSM:false,
+      myQwUserList:[],
       // 非单个禁用
       single: true,
       // 非多个禁用
@@ -195,7 +437,7 @@ export default {
       open: false,
       // 状态 0 待处理 1 已处理 3 过期字典
       statusOptions: [],
-	  trackTypeOptions:[],
+      trackTypeOptions:[],
       // 类别 1先导 2 课程 3 大小转 4 转人工字典
       typeOptions: [],
       // 查询参数
@@ -216,59 +458,59 @@ export default {
       form: {},
       // 表单校验
       rules: {
-		   trackType: [
-		      { required: true, message: '请选择处理类型', trigger: 'change' }
-		    ]
+        trackType: [
+          { required: true, message: '请选择处理类型', trigger: 'change' }
+        ]
       }
     };
   },
   created() {
-	this.handleGetMyQwUserList();
+    this.handleGetMyQwUserList();
     this.getDicts("sys_qw_work_task_status").then(response => {
       this.statusOptions = response.data;
     });
     this.getDicts("sys_qw_work_task_type").then(response => {
       this.typeOptions = response.data;
     });
-	this.getDicts("sys_qw_work_task_track_type").then(response => {
-	  this.trackTypeOptions = response.data;
-	});
+    this.getDicts("sys_qw_work_task_track_type").then(response => {
+      this.trackTypeOptions = response.data;
+    });
 
 
   },
   methods: {
-	getScoreStyle(score) {
-	let backgroundColor = '';
-	  if (score >= 15) {
-		backgroundColor = '#ff4d4f';    // 红色
-	  } else if (score >= 9) {
-		backgroundColor = '#ff7d45';    // 橘红
-	  } else if (score >= 4) {
-		backgroundColor = '#ffec3d';    // 黄色
-	  } else {
-		backgroundColor = '#ffffff';    // 白色
-	  }
-	  return {
-		'background-color': backgroundColor,
-		'padding': '5px 10px',
-		'border-radius': '4px'
-	  };
-	},
-	formatTime(timeStr) {
-	      if (!timeStr && timeStr !== 0) return '';
-
-	      // 处理数字和字符串输入
-	      const str = String(timeStr).padStart(4, '0');
-
-	      // 提取有效部分
-	      const hours = str.substring(0, 2);
-	      const minutes = str.substring(2, 4);
-
-	      // 简单验证
-	      if (hours > 23 || minutes > 59) return '无效时间';
-
-	      return `${hours}:${minutes}`;
-	    },
+    getScoreStyle(score) {
+      let backgroundColor = '';
+      if (score >= 15) {
+        backgroundColor = '#ff4d4f';    // 红色
+      } else if (score >= 9) {
+        backgroundColor = '#ff7d45';    // 橘红
+      } else if (score >= 4) {
+        backgroundColor = '#ffec3d';    // 黄色
+      } else {
+        backgroundColor = '#ffffff';    // 白色
+      }
+      return {
+        'background-color': backgroundColor,
+        'padding': '5px 10px',
+        'border-radius': '4px'
+      };
+    },
+    formatTime(timeStr) {
+      if (!timeStr && timeStr !== 0) return '';
+
+      // 处理数字和字符串输入
+      const str = String(timeStr).padStart(4, '0');
+
+      // 提取有效部分
+      const hours = str.substring(0, 2);
+      const minutes = str.substring(2, 4);
+
+      // 简单验证
+      if (hours > 23 || minutes > 59) return '无效时间';
+
+      return `${hours}:${minutes}`;
+    },
     /** 查询企微任务看板列表 */
     getList() {
       this.loading = true;
@@ -278,10 +520,13 @@ export default {
         this.loading = false;
       });
     },
-	handleClickX(tab, event) {
-	  this.queryParams.status=tab.name;
-	  this.handleQuery();
-	},
+    sm(){
+      this.isSM = this.isSM ? false : true;
+    },
+    handleClickX(tab, event) {
+      this.queryParams.status=tab.name;
+      this.handleQuery();
+    },
     // 取消按钮
     cancel() {
       this.open = false;
@@ -311,18 +556,18 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
-	handleGetMyQwUserList(){
-
-	  getMyQwUserList().then(response => {
-	    this.myQwUserList = response.data;
-	    if(this.myQwUserList!=null){
-	      this.queryParams.qwUserId=this.myQwUserList[0].dictValue
-	      this.queryParams.corpId=this.myQwUserList[0].corpId
-	      this.getList();
-	    }
-	  });
-
-	},
+    handleGetMyQwUserList(){
+
+      getMyQwUserList().then(response => {
+        this.myQwUserList = response.data;
+        if(this.myQwUserList!=null){
+          this.queryParams.qwUserId=this.myQwUserList[0].dictValue
+          this.queryParams.corpId=this.myQwUserList[0].corpId
+          this.getList();
+        }
+      });
+
+    },
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
@@ -344,29 +589,29 @@ export default {
     handleUpdate(row) {
       this.reset();
       const id = row.id || this.ids
-        this.form = row;
-        this.open = true;
-        this.title = "处理任务";
+      this.form = row;
+      this.open = true;
+      this.title = "处理任务";
 
     },
 
-	handleUpdate2(row) {
-	  var from={id:row.id }
-	  	updateQwWorkTask2(from).then(response => {
-	    this.msgSuccess("修改成功");
+    handleUpdate2(row) {
+      var from={id:row.id }
+      updateQwWorkTask2(from).then(response => {
+        this.msgSuccess("修改成功");
 
-	    this.getList();
-	  });
+        this.getList();
+      });
 
-	},
-	handleUpdate3(row) {
-	  var from={id:row.id }
-		updateQwWorkTask3(from).then(response => {
-	  this.msgSuccess("修改成功");
+    },
+    handleUpdate3(row) {
+      var from={id:row.id }
+      updateQwWorkTask3(from).then(response => {
+        this.msgSuccess("修改成功");
 
-	  this.getList();
-	});
-	},
+        this.getList();
+      });
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {
@@ -391,30 +636,30 @@ export default {
     handleDelete(row) {
       const ids = row.id || this.ids;
       this.$confirm('是否确认删除企微任务看板编号为"' + ids + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delQwWorkTask(ids);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delQwWorkTask(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有企微任务看板数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportQwWorkTask(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportQwWorkTask(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 447 - 133
src/views/qw/QwWorkTask/qw/qwWorkTask.vue

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

+ 31 - 22
src/views/qw/qwChat/qq.vue

@@ -30,27 +30,17 @@
                    @menu-avatar-click="handleMenuAvatarClick"
                    @pick-image="handleImageClick"
                    @send="handleSend">
-        <template #cover>
-          <div>
-          </div>
-        </template>
-        <template #message-title="contact">
-          <div>
-          </div>
-        </template>
-
-        <template #sidebar-contact-fixedtop="contact">
-          <div>
-          </div>
-        </template>
-
-        <template #sidebar-message-fixedtop="message">
-          <div>
-          </div>
-        </template>
-
-        <template #message-side="contact">
-          <div>
+        <template #sidebar-message-top>
+          <div style="padding: 8px;">
+            <el-input
+              v-model="searchKeyword"
+              prefix-icon="el-icon-search"
+              placeholder="搜索"
+              size="small"
+              clearable
+              @input="handleSearch"
+              style="width: 100%;"
+            />
           </div>
         </template>
       </lemon-imui>
@@ -157,7 +147,8 @@ export default {
         open: false
       },
       imSocket: null,
-      imUrl: process.env.VUE_APP_IM_WS_URL
+      imUrl: process.env.VUE_APP_IM_WS_URL,
+      searchKeyword: '',
     };
   },
   created(){
@@ -521,6 +512,24 @@ export default {
         this.$refs.userDetail.getDetail(sessionId);
       }, 1);
     },
+    // 搜索
+    handleSearch() {
+      const keyword = this.searchKeyword.trim().toLowerCase();
+      if (!keyword) {
+        // 为空时显示全部
+        this.$refs.IMUI.initConversations(this.conversationData);
+        return;
+      }
+      // 过滤会话列表
+      const filtered = this.conversationData.filter(item => {
+        // 搜索最后一条消息内容和联系人名
+        return (
+          (item.lastContent && item.lastContent.toLowerCase().includes(keyword)) ||
+          (item.displayName && item.displayName.toLowerCase().includes(keyword))
+        );
+      });
+      this.$refs.IMUI.initConversations(filtered);
+    },
   },
 };
 </script>