wangxy 3 часов назад
Родитель
Сommit
f4a7589b7f

+ 17 - 0
src/api/his/outboundCdr.js

@@ -0,0 +1,17 @@
+import request from '@/utils/request'
+
+export function listOutboundCdr(query) {
+  return request({
+    url: '/his/outboundCdr/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function exportOutboundCdr(query) {
+  return request({
+    url: '/his/outboundCdr/export',
+    method: 'get',
+    params: query
+  })
+}

+ 16 - 0
src/api/his/user.js

@@ -200,3 +200,19 @@ export function getAppUserCount() {
     method: 'get'
   })
 }
+
+export function listWatchProject(query) {
+  return request({
+    url: '/his/user/listWatchProject',
+    method: 'get',
+    params: query
+  })
+}
+
+export function exportWatchProject(query) {
+  return request({
+    url: '/his/user/exportWatchProject',
+    method: 'get',
+    params: query
+  })
+}

+ 80 - 348
src/views/company/companyVoiceLogs/index.vue

@@ -1,426 +1,158 @@
 <template>
   <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
-      <el-form-item label="公司名" prop="companyId">
-          <el-select filterable style="width: 220px" v-model="queryParams.companyId" placeholder="请选择公司名" @change="companyChange" clearable size="small">
-              <el-option
-                v-for="item in companys"
-                :key="item.companyId"
-                :label="item.companyName"
-                :value="item.companyId"
-              />
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
+      <el-form-item label="公司" prop="companyId">
+        <el-select filterable style="width: 200px" v-model="queryParams.companyId" placeholder="请选择公司" clearable size="small">
+          <el-option v-for="item in companys" :key="item.companyId" :label="item.companyName" :value="item.companyId" />
         </el-select>
       </el-form-item>
-     <el-form-item >
-          <treeselect style="width: 220px" :clearable="false"  v-model="queryParams.deptId"  :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
-     </el-form-item>
-
-       <el-form-item label="员工姓名" prop="userNickName">
-        <el-input
-        style="width: 220px"
-          v-model="queryParams.userNickName"
-          placeholder="请输入员工姓名"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="主叫" prop="callerPhone">
-        <el-input
-          style="width: 220px"
-          v-model="queryParams.callerPhone"
-          placeholder="请输入主叫"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="被叫" prop="calleePhone">
-        <el-input
-          style="width: 220px"
-          v-model="queryParams.calleePhone"
-          placeholder="请输入被叫"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
+      <el-form-item label="主叫" prop="caller">
+        <el-input style="width: 200px" v-model="queryParams.caller" 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 label="被叫" prop="callee">
+        <el-input style="width: 200px" v-model="queryParams.callee" placeholder="请输入被叫号码" clearable size="small" @keyup.enter.native="handleQuery" />
       </el-form-item>
-      <el-form-item label="来源渠道" prop="source">
-        <el-select v-model="queryParams.source" placeholder="请选择" clearable size="small">
-          <el-option
-            v-for="dict in sourceOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
-          />
-        </el-select>
+      <el-form-item label="销售账号" prop="companyUserName">
+        <el-input style="width: 200px" v-model="queryParams.companyUserName" placeholder="请输入销售账号" clearable size="small" @keyup.enter.native="handleQuery" />
       </el-form-item>
-      <el-form-item label="时长" prop="times">
-        <el-select v-model="queryParams.times" placeholder="请选择" clearable size="small">
-          <el-option
-            v-for="dict in timesOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
-          />
+      <el-form-item label="通话时长" prop="timeLen">
+        <el-select v-model="queryParams.timeLenFilter" placeholder="请选择" clearable size="small" style="width: 160px">
+          <el-option label="大于30秒" value="30" />
+          <el-option label="大于1分钟" value="60" />
+          <el-option label="大于3分钟" value="180" />
+          <el-option label="大于5分钟" value="300" />
         </el-select>
       </el-form-item>
-      <el-form-item label="开始时间" prop="startTime">
-         <el-date-picker v-model="dateRange" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
-      </el-form-item>
-
-      <el-form-item label="客户创建时间" prop="createTime">
-        <el-date-picker
-          style="width:205.4px"
-          clearable size="small"
-          v-model="createTimeRange"
-          type="daterange"
-          value-format="yyyy-MM-dd"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期">
-        </el-date-picker>
+      <el-form-item label="外呼时间">
+        <el-date-picker v-model="dateRange" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
       </el-form-item>
       <el-form-item>
-        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <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"
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['company:companyVoiceLogs:export']"
-        >导出</el-button>
+        <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['his:outboundCdr:export']">导出</el-button>
       </el-col>
-	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table  height="500" border v-loading="loading" :data="companyVoiceLogsList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="ID" align="center" prop="voiceId" />
-      <el-table-column label="公司名" align="center" prop="companyName" />
-      <el-table-column label="员工姓名" align="center" prop="userNickName" />
-       <el-table-column label="录制地址" align="center"  show-overflow-tooltip prop="voiceUrl" width="350">
-          <template slot-scope="scope">
-            <audio  v-if="scope.row.voiceUrl!=null"   controls :src="scope.row.voiceUrl"></audio>
-          </template>
-      </el-table-column>
-      <el-table-column label="开始时间" align="center" prop="startTime" width="100">
+    <el-table height="500" border v-loading="loading" :data="cdrList">
+      <el-table-column label="公司" align="center" prop="companyName" min-width="120" show-overflow-tooltip />
+      <el-table-column label="销售账号" align="center" prop="companyUserName" min-width="100" />
+      <el-table-column label="工号" align="center" prop="opnum" min-width="80" />
+      <el-table-column label="主叫" align="center" prop="caller" min-width="110" />
+      <el-table-column label="被叫" align="center" prop="callee" min-width="110" />
+      <el-table-column label="外呼时间" align="center" min-width="150">
         <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.startTime) }}</span>
+          <span>{{ scope.row.startTimeStr || '-' }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="结束时间" align="center" prop="finishTime" width="100">
+      <el-table-column label="接听时间" align="center" min-width="150">
         <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.finishTime) }}</span>
+          <span>{{ scope.row.answeredTimeStr || '-' }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="主叫" align="center" prop="callerPhone" />
-      <el-table-column label="被叫" align="center" prop="calleePhone" />
-      <el-table-column label="时长" align="center" prop="times" width="180">
+      <el-table-column label="挂断时间" align="center" min-width="150">
         <template slot-scope="scope">
-          <span v-if="scope.row.voiceUrl!=null">{{ formatTime(scope.row.times)}} </span>
-        </template>
-      </el-table-column>
-      <el-table-column label="计费时长(分)" align="center" prop="billingTime" width="180">
-      </el-table-column>
-      <el-table-column label="主叫显示号" align="center" prop="displayCallerNumber" width="110"/>
-      <el-table-column label="被叫显示号" align="center" prop="displayCalleeNumber" width="110"/>
-      <el-table-column label="状态" align="center" prop="status" >
-        <template slot-scope="scope">
-              <el-tag prop="status" v-for="(item, index) in statusOptions"    v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="备注" align="center" prop="remark" width="120" />
-      <el-table-column label="操作" fixed="right" align="center" prop="查看" >
-        <template slot-scope="scope">
-              <el-link  v-if="scope.row.voiceUrl!=null" :href="scope.row.voiceUrl" target="_blank" >下载录音</el-link>
+          <span>{{ scope.row.endTimeStr || '-' }}</span>
         </template>
       </el-table-column>
+      <el-table-column label="通话时长" align="center" prop="timeLenSec" min-width="90" />
+      <el-table-column label="有效时长" align="center" prop="timeLenValidStr" min-width="90" />
+      <el-table-column label="挂断原因" align="center" prop="hangupCause" min-width="120" show-overflow-tooltip />
     </el-table>
 
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-
+    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
   </div>
 </template>
 
 <script>
-import { listCompanyVoiceLogs, getCompanyVoiceLogs, delCompanyVoiceLogs, addCompanyVoiceLogs, updateCompanyVoiceLogs, exportCompanyVoiceLogs } from "@/api/company/companyVoiceLogs";
+import { listOutboundCdr, exportOutboundCdr } from "@/api/his/outboundCdr";
 import { getCompanyList } from "@/api/company/company";
 
-import { treeselect } from "@/api/company/companyDept";
-import Treeselect from "@riophae/vue-treeselect";
-import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-
 export default {
-  name: "CompanyVoiceLogs",
-  components: { Treeselect },
-  watch: {
-    // 监听deptId
-    'deptId': 'currDeptChange'
-  },
+  name: "OutboundCdr",
   data() {
     return {
-      timesOptions:[],
-      statusOptions:[],
-      companys:[],
-      deptOptions:[],
-      // 遮罩层
       loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
       showSearch: true,
-      // 总条数
       total: 0,
-      // 通话记录表格数据
-      companyVoiceLogsList: [],
-      // 弹出层标题
-      title: "",
+      cdrList: [],
+      companys: [],
       dateRange: [],
-      createTimeRange:[],
-      sourceOptions:[],
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
         companyId: null,
-        voiceTitle: null,
-        voiceUrl: null,
-        startTime: null,
-        endTime: null,
-        voiceType: null,
-        callerPhone: null,
-        calleePhone: null,
-        times: null,
-        moeny: null,
-        displayCallerNumber: null,
-        displayCalleeNumber: null,
-        deptId:null,
-
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
+        caller: null,
+        callee: null,
+        companyUserName: null,
+        timeLenFilter: null,
+        startTimeStart: null,
+        startTimeEnd: null,
+        timeLenStart: null
       }
     };
   },
   created() {
-    this.getDicts("crm_customer_source").then((response) => {
-      this.sourceOptions = response.data;
-    });
-    this.getDicts("sys_company_voice_logs_status").then((response) => {
-      this.statusOptions = response.data;
-    });
-    this.getDicts("sys_company_voice_logs_times").then((response) => {
-      this.timesOptions = response.data;
-    });
     getCompanyList().then(response => {
-       this.companys = response.data;
-       if(this.companys!=null&&this.companys.length>0){
-          this.companyId=this.companys[0].companyId;
-          this.getTreeselect();
-        }
+      this.companys = response.data || [];
     });
     this.getList();
   },
   methods: {
-    formatTime(value) {
-      const hours = Math.floor(value / 3600);
-      const minutes = Math.floor((value % 3600) / 60);
-      const seconds = value % 60;
-      if(hours == 0 && minutes == 0 ){
-        return `${seconds}秒`;
-      }else if(hours == 0 && minutes != 0 ){
-        return `${minutes}分钟${seconds}秒`;
-      }else{
-        return `${hours}小时${minutes}分钟${seconds}秒`;
-      }
-
-    },
-    /** 查询通话记录列表 */
     getList() {
       this.loading = true;
-      if(this.createTimeRange!=null&&this.createTimeRange.length==2){
-        this.queryParams.createTimeRange=this.createTimeRange[0]+"--"+this.createTimeRange[1]
-      }
-      else{
-        this.queryParams.createTimeRange=null;
-      }
-      if(this.dateRange!=null&&this.dateRange.length==2){
-        this.queryParams.dateRange=this.dateRange[0]+"--"+this.dateRange[1]
+      if (this.dateRange && this.dateRange.length === 2) {
+        const start = new Date(this.dateRange[0]);
+        const end = new Date(this.dateRange[1] + ' 23:59:59');
+        this.queryParams.startTimeStartLong = start.getTime();
+        this.queryParams.startTimeEndLong = end.getTime();
+      } else {
+        this.queryParams.startTimeStartLong = null;
+        this.queryParams.startTimeEndLong = null;
       }
-      else{
-        this.queryParams.dateRangee=null;
+      if (this.queryParams.timeLenFilter) {
+        this.queryParams.timeLenStart = parseInt(this.queryParams.timeLenFilter);
+      } else {
+        this.queryParams.timeLenStart = null;
       }
-
-      listCompanyVoiceLogs(this.queryParams).then(response => {
-        this.companyVoiceLogsList = response.rows;
+      listOutboundCdr(this.queryParams).then(response => {
+        this.cdrList = response.rows;
         this.total = response.total;
         this.loading = false;
       });
     },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        voiceId: null,
-        companyId: null,
-        voiceTitle: null,
-        voiceUrl: null,
-        startTime: null,
-        endTime: null,
-        voiceType: null,
-        remark: null,
-        callerPhone: null,
-        calleePhone: null,
-        times: null,
-        moeny: null,
-        displayCallerNumber: null,
-        displayCalleeNumber: null
-      };
-      this.resetForm("form");
-      this.dateRange=[];
+    formatDuration(seconds) {
+      if (!seconds && seconds !== 0) return '-';
+      const m = Math.floor(seconds / 60);
+      const s = seconds % 60;
+      if (m > 0) return m + '分' + s + '秒';
+      return s + '秒';
     },
-    /** 搜索按钮操作 */
     handleQuery() {
       this.queryParams.pageNum = 1;
       this.getList();
     },
-    /** 重置按钮操作 */
     resetQuery() {
+      this.dateRange = [];
       this.resetForm("queryForm");
       this.handleQuery();
     },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.voiceId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加通话记录";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const voiceId = row.voiceId || this.ids
-      getCompanyVoiceLogs(voiceId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改通话记录";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.voiceId != null) {
-            updateCompanyVoiceLogs(this.form).then(response => {
-              if (response.code === 200) {
-                this.msgSuccess("修改成功");
-                this.open = false;
-                this.getList();
-              }
-            });
-          } else {
-            addCompanyVoiceLogs(this.form).then(response => {
-              if (response.code === 200) {
-                this.msgSuccess("新增成功");
-                this.open = false;
-                this.getList();
-              }
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const voiceIds = row.voiceId || this.ids;
-      this.$confirm('是否确认删除通话记录编号为"' + voiceIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delCompanyVoiceLogs(voiceIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(function() {});
-    },
-    /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有通话记录数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return exportCompanyVoiceLogs(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-        }).catch(function() {});
-    },
-              /** 查询部门下拉树结构 */
-    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;
-          }
-        });
-    },
-    companyChange(val){
-      console.log(val);
-      this.companyId=val;
-      this.getTreeselect();
-    },
-    currDeptChange(val){
-          console.log(val)
-          this.queryParams.deptId=val;
-          this.getList();
-    },
-
+      this.$confirm('是否确认导出外呼通话记录?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return exportOutboundCdr(this.queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      });
+    }
   }
 };
 </script>

+ 6 - 4
src/views/course/courseTrafficLog/indexApp.vue

@@ -30,8 +30,8 @@
         </el-select>
       </el-form-item>
       <el-form-item label="公开课" v-if="activeTab === 'all' || activeTab === 'common'">
-        <el-select v-model="queryParams.courseId" placeholder="请选择课" filterable clearable size="small">
-          <el-option v-for="dict in courseLists" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+        <el-select v-model="queryParams.courseId" placeholder="请选择公开课" filterable clearable size="small">
+          <el-option v-for="dict in commonCourseLists" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
         </el-select>
       </el-form-item>
 
@@ -75,7 +75,7 @@
     <el-table border v-loading="loading" :data="courseTrafficLogList" @selection-change="handleSelectionChange" show-summary :summary-method="getSummaries">
       <el-table-column type="selection" width="55" align="center" />
       <!-- 公司列 -->
-      <el-table-column label="公司" align="center" prop="companyName" />
+      <el-table-column label="公司" align="center" prop="companyName" v-if="activeTab !== 'common'" />
       <!-- 项目列 -->
       <el-table-column label="项目" align="center" prop="projectName" v-if="activeTab === 'all' || activeTab === 'project'" />
       <!-- 课程列 -->
@@ -100,7 +100,7 @@
 </template>
 
 <script>
-import { listCourseTrafficLog, exportCourseTrafficLog } from "@/api/course/courseTrafficLog";
+import { listCourseTrafficLog, exportCourseTrafficLog, commonCourseList } from "@/api/course/courseTrafficLog";
 import { courseList } from "@/api/course/courseRedPacketLog";
 import { allList } from "@/api/company/company";
 
@@ -152,6 +152,7 @@ export default {
         ]
       },
       courseLists: [],
+      commonCourseLists: [],
       loading: false,
       exportLoading: false,
       showSearch: true,
@@ -173,6 +174,7 @@ export default {
   created() {
     this.queryParams.tabType = "project";
     courseList().then(res => this.courseLists = res.list);
+    commonCourseList().then(res => this.commonCourseLists = res.list || res.data || []);
     this.getDicts("sys_course_project").then(res => this.projectOptions = res.data);
     this.getAllCompany();
     this.getList();

+ 340 - 0
src/views/his/companyUser/index.vue

@@ -0,0 +1,340 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--公司列表-->
+      <el-col :span="5" :xs="24">
+        <div class="head-container">
+          <el-input v-model="companyName" placeholder="请输入公司名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
+        </div>
+        <div class="head-container">
+          <el-table :data="filteredCompanyList" v-loading="companyLoading" height="600" highlight-current-row @row-click="handleCompanyClick" size="small">
+            <el-table-column label="公司名称" align="center" prop="companyName" show-overflow-tooltip />
+          </el-table>
+        </div>
+      </el-col>
+      <!--员工数据-->
+      <el-col :span="19" :xs="24">
+        <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
+          <el-form-item label="员工姓名" prop="nickName">
+            <el-input v-model="queryParams.nickName" placeholder="请输入员工姓名" clearable size="small" style="width: 200px" @keyup.enter.native="handleQuery" />
+          </el-form-item>
+          <el-form-item label="手机号码" prop="phonenumber">
+            <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable size="small" style="width: 200px" @keyup.enter.native="handleQuery" />
+          </el-form-item>
+          <el-form-item label="状态" prop="status">
+            <el-select v-model="queryParams.status" placeholder="员工状态" clearable size="small" style="width: 200px">
+              <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" v-if="currentCompany">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['company:companyUser: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="['company:companyUser:export']">导出</el-button>
+          </el-col>
+          <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+
+        <div v-if="!currentCompany" class="empty-hint">请选择左侧公司查看员工列表</div>
+
+        <el-table v-if="currentCompany" v-loading="loading" height="500" border :data="userList">
+          <el-table-column label="员工ID" align="center" prop="userId" width="80" />
+          <el-table-column label="员工账号" align="center" prop="userName" show-overflow-tooltip width="120" />
+          <el-table-column label="员工姓名" align="center" prop="nickName" show-overflow-tooltip width="100" />
+          <el-table-column label="手机号码" align="center" prop="phonenumber" width="120" />
+          <el-table-column label="状态" align="center" width="80">
+            <template slot-scope="scope">
+              <el-tag :type="scope.row.status === '0' ? 'success' : 'danger'">
+                {{ scope.row.status === '0' ? '正常' : '停用' }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="创建时间" align="center" prop="createTime" width="160">
+            <template slot-scope="scope">
+              <span>{{ parseTime(scope.row.createTime) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" width="120" class-name="small-padding fixed-width" fixed="right">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['company:companyUser:edit']">修改</el-button>
+              <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['company:companyUser:remove']">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination v-if="currentCompany" v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
+      </el-col>
+    </el-row>
+
+    <!-- 新增/修改对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="650px" append-to-body :close-on-click-modal="false">
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="所属公司" prop="companyId">
+              <el-select v-model="form.companyId" placeholder="请选择公司" style="width: 100%" :disabled="!!currentCompany">
+                <el-option v-for="item in companyList" :key="item.companyId" :label="item.companyName" :value="item.companyId" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="员工账号" prop="userName">
+              <el-input v-model="form.userName" placeholder="请输入员工账号" :disabled="!!form.userId" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="员工姓名" prop="nickName">
+              <el-input v-model="form.nickName" placeholder="请输入员工姓名" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="手机号码" prop="phonenumber">
+              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="密码" prop="password" v-if="!form.userId">
+              <el-input v-model="form.password" placeholder="请输入密码" type="password" show-password />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="状态">
+              <el-radio-group v-model="form.status">
+                <el-radio v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictValue">{{ dict.dictLabel }}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="邮箱" prop="email">
+              <el-input v-model="form.email" placeholder="请输入邮箱" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="性别">
+              <el-select v-model="form.sex" placeholder="请选择">
+                <el-option label="男" value="0" />
+                <el-option label="女" value="1" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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 { listCompanyUser, getCompanyUser, addCompanyUser, updateCompanyUser, delCompanyUser, getAllUserlist, getCompanyList } from "@/api/company/companyUser";
+
+export default {
+  name: "CompanyUserManage",
+  data() {
+    return {
+      loading: false,
+      showSearch: true,
+      total: 0,
+      userList: [],
+      title: "",
+      open: false,
+      currentCompany: null,
+      companyLoading: false,
+      companyList: [],
+      filteredCompanyList: [],
+      companyName: "",
+      exportLoading: false,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        nickName: null,
+        phonenumber: null,
+        status: null,
+        companyId: null
+      },
+      form: {},
+      rules: {
+        companyId: [{ required: true, message: "所属公司不能为空", trigger: "blur" }],
+        userName: [{ required: true, message: "员工账号不能为空", trigger: "blur" }],
+        nickName: [{ required: true, message: "员工姓名不能为空", trigger: "blur" }],
+        phonenumber: [
+          { required: true, message: "手机号码不能为空", trigger: "blur" },
+          { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }
+        ],
+        password: [
+          { required: true, message: "密码不能为空", trigger: "blur" },
+          { min: 6, message: "密码长度不能少于6位", trigger: "blur" }
+        ]
+      },
+      statusOptions: [
+        { dictValue: "0", dictLabel: "正常" },
+        { dictValue: "1", dictLabel: "停用" }
+      ]
+    };
+  },
+  watch: {
+    companyName(val) {
+      if (val) {
+        this.filteredCompanyList = this.companyList.filter(item => item.companyName && item.companyName.indexOf(val) > -1);
+      } else {
+        this.filteredCompanyList = this.companyList;
+      }
+    }
+  },
+  created() {
+    this.loadCompanyList();
+  },
+  methods: {
+    loadCompanyList() {
+      this.companyLoading = true;
+      getCompanyList({}).then(response => {
+        this.companyList = response.data || [];
+        this.filteredCompanyList = this.companyList;
+        this.companyLoading = false;
+      }).catch(() => {
+        this.companyLoading = false;
+      });
+    },
+    handleCompanyClick(row) {
+      this.currentCompany = row;
+      this.queryParams.companyId = row.companyId;
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    getList() {
+      this.loading = true;
+      getAllUserlist({ companyId: this.queryParams.companyId }).then(response => {
+        let data = response.data || [];
+        if (this.queryParams.nickName) {
+          data = data.filter(item => item.nickName && item.nickName.indexOf(this.queryParams.nickName) > -1);
+        }
+        if (this.queryParams.phonenumber) {
+          data = data.filter(item => item.phonenumber && item.phonenumber.indexOf(this.queryParams.phonenumber) > -1);
+        }
+        if (this.queryParams.status) {
+          data = data.filter(item => item.status === this.queryParams.status);
+        }
+        this.total = data.length;
+        const start = (this.queryParams.pageNum - 1) * this.queryParams.pageSize;
+        this.userList = data.slice(start, start + this.queryParams.pageSize);
+        this.loading = false;
+      }).catch(() => {
+        this.loading = false;
+      });
+    },
+    reset() {
+      this.form = {
+        userId: null,
+        companyId: this.currentCompany ? this.currentCompany.companyId : null,
+        userName: null,
+        nickName: null,
+        phonenumber: null,
+        password: null,
+        status: "0",
+        email: null,
+        sex: "0"
+      };
+      if (this.$refs["form"]) {
+        this.$refs["form"].resetFields();
+      }
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    handleAdd() {
+      this.reset();
+      this.title = "新增员工";
+      this.open = true;
+    },
+    handleUpdate(row) {
+      this.reset();
+      this.title = "修改员工";
+      getCompanyUser(row.userId).then(response => {
+        this.form = response.data;
+        this.open = true;
+      });
+    },
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.userId != null) {
+            updateCompanyUser(this.form).then(() => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCompanyUser(this.form).then(() => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    handleDelete(row) {
+      this.$confirm('是否确认删除员工"' + row.nickName + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return delCompanyUser(row.userId);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      });
+    },
+    handleExport() {
+      this.$confirm("是否确认导出当前公司员工数据?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        import('@/api/company/companyUser').then(api => {
+          return api.exportCompanyUser(this.queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {
+          this.exportLoading = false;
+        });
+      });
+    }
+  }
+};
+</script>
+
+<style scoped>
+.empty-hint {
+  text-align: center;
+  color: #999;
+  font-size: 16px;
+  padding-top: 200px;
+}
+</style>

+ 2 - 51
src/views/his/lifeSaluteOrder/index.vue

@@ -10,24 +10,6 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="商家订单号" prop="merchantOrderNo">
-        <el-input
-          v-model="queryParams.merchantOrderNo"
-          placeholder="请输入商家订单号"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="平台订单号" prop="platformOrderNo">
-        <el-input
-          v-model="queryParams.platformOrderNo"
-          placeholder="请输入平台订单号"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
       <el-form-item label="运单号" prop="waybillNo">
         <el-input
           v-model="queryParams.waybillNo"
@@ -111,12 +93,9 @@
 
     <el-table v-loading="loading" border :data="orderList">
       <el-table-column label="系统订单号" align="center" prop="orderNo" width="180" show-overflow-tooltip />
-      <el-table-column label="商家订单号" align="center" prop="merchantOrderNo" width="150" show-overflow-tooltip />
-      <el-table-column label="平台订单号" align="center" prop="platformOrderNo" width="150" show-overflow-tooltip />
-      <el-table-column label="预制运单号" align="center" prop="preWaybillNo" width="150" show-overflow-tooltip />
+      <el-table-column label="销售姓名" align="center" prop="companyUserName" width="110" />
+      <el-table-column label="销售手机" align="center" prop="companyUserPhone" width="130" />
       <el-table-column label="运单号" align="center" prop="waybillNo" width="150" show-overflow-tooltip />
-      <el-table-column label="处方编号" align="center" prop="prescriptionNo" width="150" show-overflow-tooltip />
-      <el-table-column label="处方人姓名" align="center" prop="prescriptionName" width="120" show-overflow-tooltip />
       <el-table-column label="患者年龄" align="center" prop="age" width="80" />
       <el-table-column label="患者性别" align="center" prop="sex" width="80" />
       <el-table-column label="病情描述" align="center" prop="illnessCondition" width="120" show-overflow-tooltip />
@@ -187,25 +166,6 @@
 
     <el-dialog v-if="open" :title="title" :visible.sync="open" width="900px" append-to-body :close-on-click-modal="false">
       <el-form ref="form" :model="form" :rules="rules" label-width="130px">
-        <el-divider content-position="left">基础信息</el-divider>
-        <el-row :gutter="20">
-          <el-col :span="8">
-            <el-form-item label="预制运单号" prop="preWaybillNo">
-              <el-input v-model="form.preWaybillNo" placeholder="请输入预制运单号" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="商家订单号" prop="merchantOrderNo">
-              <el-input v-model="form.merchantOrderNo" placeholder="请输入商家订单号" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="平台订单号" prop="platformOrderNo">
-              <el-input v-model="form.platformOrderNo" placeholder="请输入平台订单号" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-
         <el-divider content-position="left">患者信息</el-divider>
         <el-row :gutter="20">
           <el-col :span="8">
@@ -586,17 +546,8 @@
           <el-col :span="8">
             <el-form-item label="系统订单号">{{ details.data.orderNo }}</el-form-item>
           </el-col>
-          <el-col :span="8">
-            <el-form-item label="商家订单号">{{ details.data.merchantOrderNo }}</el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="平台订单号">{{ details.data.platformOrderNo }}</el-form-item>
-          </el-col>
         </el-row>
         <el-row :gutter="20">
-          <el-col :span="8">
-            <el-form-item label="预制运单号">{{ details.data.preWaybillNo }}</el-form-item>
-          </el-col>
           <el-col :span="8">
             <el-form-item label="运单号">{{ details.data.waybillNo }}</el-form-item>
           </el-col>

+ 142 - 0
src/views/his/user/noProject.vue

@@ -0,0 +1,142 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+      <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="phone">
+        <el-input v-model="queryParams.phone" 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="['his:user:export']">导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" border :data="userList">
+      <el-table-column label="会员ID" align="center" prop="userId" width="100" />
+      <el-table-column label="会员昵称" align="center" prop="nickName" min-width="120" show-overflow-tooltip />
+      <el-table-column label="手机号" align="center" prop="phone" width="130" />
+      <el-table-column label="最后登录时间" align="center" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.lastAppLoginTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="小程序看课" align="center" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.lastMiniWatchTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="APP看课" align="center" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.lastAppWatchTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="经销商" align="center" min-width="140">
+        <template slot-scope="scope">
+          <span v-if="scope.row.projectRelations && scope.row.projectRelations.length > 0">
+            <div v-for="(rel, idx) in scope.row.projectRelations" :key="idx">{{ rel.companyName || '-' }}</div>
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="销售" align="center" min-width="100">
+        <template slot-scope="scope">
+          <span v-if="scope.row.projectRelations && scope.row.projectRelations.length > 0">
+            <div v-for="(rel, idx) in scope.row.projectRelations" :key="idx">{{ rel.companyUserName || '-' }}</div>
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="项目" align="center" min-width="120">
+        <template slot-scope="scope">
+          <span v-if="scope.row.projectRelations && scope.row.projectRelations.length > 0">
+            <div v-for="(rel, idx) in scope.row.projectRelations" :key="idx">{{ getProjectName(rel.projectId) }}</div>
+          </span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import { listWatchProject, exportWatchProject } from "@/api/his/user";
+
+export default {
+  name: "UserNoProject",
+  data() {
+    return {
+      loading: true,
+      showSearch: true,
+      exportLoading: false,
+      total: 0,
+      userList: [],
+      projectMap: {},
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        nickName: null,
+        phone: null
+      }
+    };
+  },
+  created() {
+    this.getDicts("sys_course_project").then(res => {
+      (res.data || []).forEach(d => { this.projectMap[d.dictValue] = d.dictLabel });
+    });
+    this.getList();
+  },
+  methods: {
+    getList(e) {
+      if (e) {
+        this.queryParams.pageNum = e.page;
+        this.queryParams.pageSize = e.limit;
+      }
+      this.loading = true;
+      listWatchProject(this.queryParams).then(response => {
+        this.userList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    getProjectName(projectId) {
+      if (!projectId) return '-';
+      return this.projectMap[projectId] || projectId;
+    },
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    handleExport() {
+      this.$confirm("确认导出无项目绑定会员数据?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportWatchProject(this.queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {
+        this.exportLoading = false;
+      });
+    }
+  }
+};
+</script>

+ 329 - 1
src/views/system/user/index.vue

@@ -1,5 +1,8 @@
 <template>
   <div class="app-container">
+    <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+      <el-tab-pane label="系统用户" name="sys">
+
     <el-row :gutter="20">
       <!--部门数据-->
       <el-col :span="4" :xs="24">
@@ -217,6 +220,79 @@
       </el-col>
     </el-row>
 
+      </el-tab-pane>
+      <el-tab-pane label="销售公司员工" name="company">
+
+    <!--销售公司员工数据-->
+    <el-row :gutter="20" v-loading="companyLoading">
+      <el-col :span="4" :xs="24">
+        <div class="head-container">
+          <el-input v-model="companySearchName" placeholder="请输入公司名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
+        </div>
+        <div class="head-container">
+          <el-table :data="filteredCompanyList" height="600" highlight-current-row @row-click="handleCompanyUserClick" size="small" class="company-list-table">
+            <el-table-column label="公司名称" align="center" prop="companyName" show-overflow-tooltip />
+          </el-table>
+        </div>
+      </el-col>
+      <el-col :span="20" :xs="24">
+        <el-form :model="companyQueryParams" ref="companyQueryForm" :inline="true" v-show="showSearch" label-width="80px">
+          <el-form-item label="员工姓名" prop="nickName">
+            <el-input v-model="companyQueryParams.nickName" placeholder="请输入员工姓名" clearable size="small" style="width: 200px" @keyup.enter.native="handleCompanyQuery" />
+          </el-form-item>
+          <el-form-item label="手机号码" prop="phonenumber">
+            <el-input v-model="companyQueryParams.phonenumber" placeholder="请输入手机号码" clearable size="small" style="width: 200px" @keyup.enter.native="handleCompanyQuery" />
+          </el-form-item>
+          <el-form-item label="状态" prop="status">
+            <el-select v-model="companyQueryParams.status" placeholder="员工状态" clearable size="small" style="width: 200px">
+              <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="handleCompanyQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetCompanyQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8" v-if="selectedCompany">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleCompanyAdd" v-hasPermi="['company:companyUser:add']">新增员工</el-button>
+          </el-col>
+          <right-toolbar :showSearch.sync="showSearch" @queryTable="getCompanyUserList"></right-toolbar>
+        </el-row>
+
+        <div v-if="!selectedCompany" class="empty-hint">请选择左侧公司查看员工列表</div>
+
+        <el-table v-if="selectedCompany" v-loading="companyUserLoading" height="500" border :data="companyUserList" @selection-change="handleCompanySelectionChange">
+          <el-table-column type="selection" width="50" align="center" />
+          <el-table-column label="员工ID" align="center" prop="userId" width="80" />
+          <el-table-column label="员工账号" align="center" prop="userName" show-overflow-tooltip width="120" />
+          <el-table-column label="员工姓名" align="center" prop="nickName" show-overflow-tooltip width="100" />
+          <el-table-column label="所属公司" align="center" prop="companyName" show-overflow-tooltip width="140" />
+          <el-table-column label="手机号码" align="center" prop="phonenumber" width="120" />
+          <el-table-column label="状态" align="center" width="80">
+            <template slot-scope="scope">
+              <el-tag :type="scope.row.status === '0' ? 'success' : 'danger'">{{ scope.row.status === '0' ? '正常' : '停用' }}</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="创建时间" align="center" prop="createTime" width="160">
+            <template slot-scope="scope"><span>{{ parseTime(scope.row.createTime) }}</span></template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" width="120" class-name="small-padding fixed-width" fixed="right">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleCompanyUpdate(scope.row)" v-hasPermi="['company:companyUser:edit']">修改</el-button>
+              <el-button size="mini" type="text" icon="el-icon-delete" @click="handleCompanyDelete(scope.row)" v-hasPermi="['company:companyUser:remove']">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination v-if="selectedCompany" v-show="companyTotal>0" :total="companyTotal" :page.sync="companyQueryParams.pageNum" :limit.sync="companyQueryParams.pageSize" @pagination="getCompanyUserList" />
+      </el-col>
+    </el-row>
+
+      </el-tab-pane>
+    </el-tabs>
+
     <!-- 添加或修改参数配置对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
@@ -352,6 +428,85 @@
         <el-button @click="upload.open = false">取 消</el-button>
       </div>
     </el-dialog>
+
+    <!-- 销售公司员工新增/修改 -->
+    <el-dialog :title="companyTitle" :visible.sync="companyOpen" width="700px" append-to-body :close-on-click-modal="false">
+      <el-form ref="companyForm" :model="companyForm" :rules="companyRules" label-width="100px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="所属公司" prop="companyId">
+              <el-select v-model="companyForm.companyId" placeholder="请选择公司" style="width: 100%" :disabled="!!selectedCompany" @change="handleCompanyIdChange">
+                <el-option v-for="item in fullCompanyList" :key="item.companyId" :label="item.companyName" :value="item.companyId" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="归属部门" prop="deptId">
+              <treeselect v-model="companyForm.deptId" :options="companyDeptOptions" placeholder="请选择归属部门" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="员工账号" prop="userName">
+              <el-input v-model="companyForm.userName" placeholder="请输入员工账号" :disabled="!!companyForm.userId" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="员工姓名" prop="nickName">
+              <el-input v-model="companyForm.nickName" placeholder="请输入员工姓名" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="手机号码" prop="phonenumber">
+              <el-input v-model="companyForm.phonenumber" placeholder="请输入手机号码" maxlength="11" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="密码" prop="password" v-if="!companyForm.userId">
+              <el-input v-model="companyForm.password" placeholder="请输入密码" type="password" show-password />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="角色" prop="roleIds">
+              <el-select v-model="companyForm.roleIds" multiple placeholder="请选择角色" style="width: 100%">
+                <el-option v-for="item in companyRoleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="状态">
+              <el-radio-group v-model="companyForm.status">
+                <el-radio v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictValue">{{ dict.dictLabel }}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="邮箱" prop="email">
+              <el-input v-model="companyForm.email" placeholder="请输入邮箱" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="性别">
+              <el-select v-model="companyForm.sex" placeholder="请选择">
+                <el-option label="男" value="0" />
+                <el-option label="女" value="1" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitCompanyForm">确 定</el-button>
+        <el-button @click="companyOpen = false">取 消</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -360,6 +515,9 @@ import { listUser, getUser, delUser, addUser, updateUser, exportUser, resetUserP
 import {addSet,getSet } from "@/api/system/set";
 import { getToken } from "@/utils/auth";
 import { treeselect } from "@/api/system/dept";
+import { listCompanyUser, getCompanyUser, addCompanyUser, updateCompanyUser, delCompanyUser, getAllUserlist, getCompanyList } from "@/api/company/companyUser";
+import { treeselect as companyTreeselect } from "@/api/company/companyDept";
+import { listCompanyRole } from "@/api/company/companyRole";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
@@ -472,6 +630,37 @@ export default {
             trigger: "blur"
           }
         ]
+      },
+      activeTab: "sys",
+      companyLoading: false,
+      companyUserLoading: false,
+      selectedCompany: null,
+      fullCompanyList: [],
+      filteredCompanyList: [],
+      companySearchName: "",
+      companyUserList: [],
+      companyTotal: 0,
+      companyIds: [],
+      companyQueryParams: { pageNum: 1, pageSize: 10, nickName: null, phonenumber: null, status: null, companyId: null },
+      companyTitle: "",
+      companyOpen: false,
+      companyForm: {},
+      companyDeptOptions: [],
+      companyRoleOptions: [],
+      companyRules: {
+        companyId: [{ required: true, message: "所属公司不能为空", trigger: "blur" }],
+        deptId: [{ required: true, message: "归属部门不能为空", trigger: "blur" }],
+        userName: [{ required: true, message: "员工账号不能为空", trigger: "blur" }],
+        nickName: [{ required: true, message: "员工姓名不能为空", trigger: "blur" }],
+        roleIds: [{ required: true, message: "角色不能为空", trigger: "change" }],
+        phonenumber: [
+          { required: true, message: "手机号码不能为空", trigger: "blur" },
+          { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }
+        ],
+        password: [
+          { required: true, message: "密码不能为空", trigger: "blur" },
+          { min: 6, message: "密码长度不能少于6位", trigger: "blur" }
+        ]
       }
     };
   },
@@ -479,6 +668,13 @@ export default {
     // 根据名称筛选部门树
     deptName(val) {
       this.$refs.tree.filter(val);
+    },
+    companySearchName(val) {
+      if (val) {
+        this.filteredCompanyList = this.fullCompanyList.filter(item => item.companyName && item.companyName.indexOf(val) > -1);
+      } else {
+        this.filteredCompanyList = this.fullCompanyList;
+      }
     }
   },
   created() {
@@ -757,7 +953,139 @@ export default {
     // 提交上传文件
     submitFileForm() {
       this.$refs.upload.submit();
+    },
+    /** 标签切换 */
+    handleTabClick(tab) {
+      if (tab.name === 'company' && this.fullCompanyList.length === 0) {
+        this.loadCompanyList();
+      }
+    },
+    loadCompanyList() {
+      this.companyLoading = true;
+      getCompanyList({}).then(response => {
+        this.fullCompanyList = response.data || [];
+        this.filteredCompanyList = this.fullCompanyList;
+        this.companyLoading = false;
+      }).catch(() => { this.companyLoading = false; });
+    },
+    handleCompanyUserClick(row) {
+      this.selectedCompany = row;
+      this.companyQueryParams.companyId = row.companyId;
+      this.companyQueryParams.pageNum = 1;
+      this.getCompanyUserList();
+    },
+    getCompanyUserList() {
+      this.companyUserLoading = true;
+      getAllUserlist({ companyId: this.companyQueryParams.companyId }).then(response => {
+        let data = response.data || [];
+        if (this.companyQueryParams.nickName) {
+          data = data.filter(item => item.nickName && item.nickName.indexOf(this.companyQueryParams.nickName) > -1);
+        }
+        if (this.companyQueryParams.phonenumber) {
+          data = data.filter(item => item.phonenumber && item.phonenumber.indexOf(this.companyQueryParams.phonenumber) > -1);
+        }
+        if (this.companyQueryParams.status) {
+          data = data.filter(item => item.status === this.companyQueryParams.status);
+        }
+        this.companyTotal = data.length;
+        const start = (this.companyQueryParams.pageNum - 1) * this.companyQueryParams.pageSize;
+        this.companyUserList = data.slice(start, start + this.companyQueryParams.pageSize);
+        this.companyUserLoading = false;
+      }).catch(() => { this.companyUserLoading = false; });
+    },
+    handleCompanyQuery() {
+      this.companyQueryParams.pageNum = 1;
+      this.getCompanyUserList();
+    },
+    resetCompanyQuery() {
+      this.resetForm("companyQueryForm");
+      this.handleCompanyQuery();
+    },
+    handleCompanySelectionChange(selection) {
+      this.companyIds = selection.map(item => item.userId);
+    },
+    companyReset() {
+      this.companyForm = {
+        userId: null,
+        companyId: this.selectedCompany ? this.selectedCompany.companyId : null,
+        deptId: null, userName: null, nickName: null, phonenumber: null,
+        password: null, status: "0", email: null, sex: "0", roleIds: []
+      };
+      this.companyDeptOptions = [];
+      this.companyRoleOptions = [];
+      if (this.$refs["companyForm"]) this.$refs["companyForm"].resetFields();
+    },
+    handleCompanyIdChange(val) {
+      if (val) {
+        companyTreeselect({ companyId: val }).then(response => {
+          this.companyDeptOptions = response.data || [];
+        });
+        listCompanyRole({ companyId: val, status: '0' }).then(response => {
+          this.companyRoleOptions = response.rows || [];
+        });
+      }
+    },
+    handleCompanyAdd() {
+      this.companyReset();
+      this.companyTitle = "新增员工";
+      if (this.companyForm.companyId) {
+        this.handleCompanyIdChange(this.companyForm.companyId);
+      }
+      this.companyOpen = true;
+    },
+    handleCompanyUpdate(row) {
+      this.companyReset();
+      this.companyTitle = "修改员工";
+      getCompanyUser(row.userId).then(response => {
+        const data = response.data;
+        if (data.companyId) {
+          this.handleCompanyIdChange(data.companyId);
+        }
+        this.companyForm = { ...data, roleIds: response.roleIds || [] };
+        this.companyOpen = true;
+      });
+    },
+    submitCompanyForm() {
+      this.$refs["companyForm"].validate(valid => {
+        if (valid) {
+          if (this.companyForm.userId != null) {
+            updateCompanyUser(this.companyForm).then(() => {
+              this.msgSuccess("修改成功");
+              this.companyOpen = false;
+              this.getCompanyUserList();
+            });
+          } else {
+            addCompanyUser(this.companyForm).then(() => {
+              this.msgSuccess("新增成功");
+              this.companyOpen = false;
+              this.getCompanyUserList();
+            });
+          }
+        }
+      });
+    },
+    handleCompanyDelete(row) {
+      this.$confirm('是否确认删除员工"' + row.nickName + '"的数据项?', "警告", {
+        confirmButtonText: "确定", cancelButtonText: "取消", type: "warning"
+      }).then(() => {
+        return delCompanyUser(row.userId);
+      }).then(() => {
+        this.getCompanyUserList();
+        this.msgSuccess("删除成功");
+      });
     }
   }
 };
-</script>
+</script>
+<style scoped>
+.empty-hint {
+  text-align: center;
+  color: #999;
+  font-size: 16px;
+  padding-top: 200px;
+}
+.company-list-table ::v-deep .el-table__body td {
+  font-size: 14px;
+  font-weight: 500;
+}
+</style>