Browse Source

合并代码

yfh 1 tháng trước cách đây
mục cha
commit
a366a919b0
85 tập tin đã thay đổi với 10755 bổ sung2049 xóa
  1. 3 0
      src/views/chat/chatSession/index.vue
  2. 100 47
      src/views/components/course/userCourseCatalogDetails.vue
  3. 695 264
      src/views/components/his/integralOrderDetails.vue
  4. 26 0
      src/views/components/his/packageDetails.vue
  5. 6 1
      src/views/components/his/storeAfterSalesDetails.vue
  6. 6 6
      src/views/components/his/storeDetails.vue
  7. 199 18
      src/views/components/his/storeOrderDetails.vue
  8. 14 2
      src/views/components/his/userDetails.vue
  9. 111 0
      src/views/components/his/userIntegralDetails.vue
  10. 10 0
      src/views/course/courseAnswerlogs/index.vue
  11. 12 2
      src/views/course/courseFinishTempParent/index.vue
  12. 32 0
      src/views/course/coursePlaySourceConfig/index.vue
  13. 3 5
      src/views/course/courseTrafficLog/index.vue
  14. 2 0
      src/views/course/courseUserStatistics/qw/index.vue
  15. 2 1
      src/views/course/courseUserStatistics/qw/my.vue
  16. 2 1
      src/views/course/courseUserStatistics/qw/myStatistics.vue
  17. 3 2
      src/views/course/courseUserStatistics/qw/statistics.vue
  18. 1 84
      src/views/course/courseUserStatistics/statistics.vue
  19. 7 7
      src/views/course/courseWatchComment/index.vue
  20. 165 20
      src/views/course/courseWatchLog/index.vue
  21. 5 2
      src/views/course/courseWatchLog/qw/statistics.vue
  22. 299 0
      src/views/course/courseWatchLog/qw/statisticsCompany.vue
  23. 65 20
      src/views/course/courseWatchLog/statistics.vue
  24. 3 3
      src/views/course/courseWatchLog/watchLogStatistics.vue
  25. 253 0
      src/views/course/statistics/index.vue
  26. 266 11
      src/views/course/userCourse/index.vue
  27. 10 10
      src/views/course/userCourse/public.vue
  28. 3 0
      src/views/course/userCourseComplaintRecord/index.vue
  29. 1 1
      src/views/course/userCoursePeriod/statistics.vue
  30. 2 1
      src/views/course/userVideo/index.vue
  31. 13 1
      src/views/course/userWatchCourseStatistics/index.vue
  32. 14 1
      src/views/course/userWatchCourseTotalStatistics/index.vue
  33. 14 1
      src/views/course/userWatchStatistics/index.vue
  34. 38 118
      src/views/course/videoResource/index.vue
  35. 17 13
      src/views/crm/components/assignCompany.vue
  36. 22 60
      src/views/crm/customer/index.vue
  37. 21 41
      src/views/crm/customer/line.vue
  38. 2056 0
      src/views/crm/externalContact/index.vue
  39. 1 0
      src/views/fastGpt/fastGptExtUserTag/index.vue
  40. 259 0
      src/views/fastGpt/fastGptPushTokenTotal/index.vue
  41. 20 4
      src/views/fastGpt/fastgptEventLogTotal/index.vue
  42. 22 2
      src/views/his/adv/index.vue
  43. 3 0
      src/views/his/aiDoctorChatSession/index.vue
  44. 525 0
      src/views/his/answer/index.vue
  45. 4 6
      src/views/his/article/index.vue
  46. 414 133
      src/views/his/company/index.vue
  47. 23 1
      src/views/his/companyDeduct/index.vue
  48. 22 0
      src/views/his/companyRecharge/index.vue
  49. 442 0
      src/views/his/dfAccount/index.vue
  50. 378 0
      src/views/his/divItem/index.vue
  51. 30 2
      src/views/his/doctor/type1.vue
  52. 30 2
      src/views/his/doctor/type2.vue
  53. 7 10
      src/views/his/hospital/index.vue
  54. 26 1
      src/views/his/inquiryOrder/order1.vue
  55. 25 1
      src/views/his/inquiryOrder/order2.vue
  56. 27 0
      src/views/his/inquiryOrder/order3.vue
  57. 77 30
      src/views/his/inquiryOrderReport/index.vue
  58. 26 1
      src/views/his/integralOrder/index.vue
  59. 90 6
      src/views/his/package/index.vue
  60. 59 6
      src/views/his/packageOrder/index.vue
  61. 147 0
      src/views/his/promotionalActive/ChooseCourseVideoComponent.vue
  62. 213 0
      src/views/his/promotionalActive/ChooseDoctorComponent.vue
  63. 176 0
      src/views/his/promotionalActive/ChooseIntegralGoodsComponent.vue
  64. 202 0
      src/views/his/promotionalActive/ChoosePackageComponent.vue
  65. 689 0
      src/views/his/promotionalActive/index.vue
  66. 103 0
      src/views/his/promotionalActive/stats.vue
  67. 352 0
      src/views/his/statistics/afterSalesOrder.vue
  68. 178 0
      src/views/his/statistics/appOrderCountStats.vue
  69. 420 0
      src/views/his/statistics/comprehensiveStatistics.vue
  70. 170 0
      src/views/his/statistics/hisOrderCountStats.vue
  71. 2 2
      src/views/his/store/index.vue
  72. 275 41
      src/views/his/storeOrder/order1.vue
  73. 10 2
      src/views/his/storeOrder/order2.vue
  74. 33 4
      src/views/his/storePayment/index.vue
  75. 52 3
      src/views/his/user/index.vue
  76. 1 1
      src/views/his/user/indexProject.vue
  77. 0 310
      src/views/his/userTag/index.vue
  78. 0 580
      src/views/hospital/hospital/index.vue
  79. 1 1
      src/views/qw/externalContact/index.vue
  80. 342 0
      src/views/qw/externalContactTransferAudit/index.vue
  81. 39 1
      src/views/qw/qwCompany/index.vue
  82. 18 1
      src/views/qw/sop/sop.vue
  83. 152 0
      src/views/qw/user/selectDoctor.vue
  84. 159 154
      src/views/sop/companySopRole/index.vue
  85. 10 1
      src/views/system/user/index.vue

+ 3 - 0
src/views/chat/chatSession/index.vue

@@ -327,6 +327,9 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.dateRange = [];
+      this.queryParams.beginTime=null;
+      this.queryParams.endTime=null;
       this.resetForm("queryForm");
       this.handleQuery();
     },

+ 100 - 47
src/views/components/course/userCourseCatalogDetails.vue

@@ -34,12 +34,15 @@
         <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
                    v-hasPermi="['course:userCourseVideo:remove']">删除</el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button type="warning" plain icon="el-icon-edit" size="mini" @click="handleCourseSort"
+                   v-hasPermi="['course:userCourseVideo:sort']">修改课节排序</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
     <el-table border v-loading="loading" :data="userCourseVideoList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="视频ID" align="center" prop="videoId" />
-      <!--      <el-table-column label="轮次" align="center" prop="round" />-->
       <el-table-column label="小节名称" align="center" show-overflow-tooltip prop="title" />
       <el-table-column label="视频文件名称" align="center" show-overflow-tooltip prop="fileName">
       </el-table-column>
@@ -91,32 +94,9 @@
         <el-form-item label="视频描述" prop="description">
           <el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入内容" />
         </el-form-item>
-        <!--        <el-form-item label="轮次" prop="round">-->
-        <!--          <el-input v-model="form.round"  placeholder="请输入内容" />-->
-        <!--        </el-form-item>-->
         <el-form-item label="课程排序" prop="courseSort">
           <el-input-number v-model="form.courseSort" :min="1"></el-input-number>
         </el-form-item>
-        <!--        <el-form-item label="看课时间" prop="timeRange" v-if="isPrivate === 1">-->
-        <!--          <el-time-picker-->
-        <!--            is-range-->
-        <!--            v-model="form.timeRange"-->
-        <!--            range-separator="至"-->
-        <!--            start-placeholder="开始时间"-->
-        <!--            value-format="HH:mm:ss"-->
-        <!--            end-placeholder="结束时间"-->
-        <!--            placeholder="选择时间范围">-->
-        <!--          </el-time-picker>-->
-        <!--        </el-form-item>-->
-        <!--        <el-form-item label="领取红包时间" prop="lastJoinTime" v-if="isPrivate === 1">-->
-        <!--          <el-time-picker-->
-        <!--            v-model="form.lastJoinTime"-->
-        <!--            :selectableRange="form.timeRange"-->
-        <!--            value-format="HH:mm:ss"-->
-        <!--            placeholder="选择时间范围">-->
-        <!--          </el-time-picker>-->
-        <!--          <p style="color: red;margin: 0;font-size: 12px">超过领取红包时间,只允许看课,不允许领取红包</p>-->
-        <!--        </el-form-item>-->
 
         <el-form-item label="视频缩略图" prop="thumbnail">
           <el-upload v-model="form.thumbnail" class="avatar-uploader" :action="uploadUrl" :show-file-list="false"
@@ -135,7 +115,6 @@
         <el-form-item label="课题选择" prop="questionBankId">
           <el-button size="small" type="primary" @click="chooseQuestionBank">选取课题</el-button>
           <el-table border width="100%" style="margin-top:5px;" :data="form.questionBankList">
-
             <el-table-column label="问题" align="center" prop="title">
               <template slot-scope="scope">
                 <el-tooltip class="item" effect="dark" :content="scope.row.title" placement="top">
@@ -167,6 +146,12 @@
           <el-radio v-model="form.isProduct" :label=0>否</el-radio>
           <el-radio v-model="form.isProduct" :label=1>是</el-radio>
         </el-form-item>
+        <el-form-item label="是否先导课" prop="isFirst">
+          <el-radio-group v-model="form.isFirst">
+            <el-radio :label="1">是</el-radio>
+            <el-radio :label="0">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
         <el-form-item label="商品选择" v-if="form.isProduct === 1">
           <el-button size="small" type="primary" @click="chooseCourseProduct">选取商品</el-button>
           <el-table border width="100%" style="margin-top:5px;" :data="form.courseProducts">
@@ -189,7 +174,7 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item v-if="form.isProduct === 1"  label="结束售卖时间" prop="listingStartTime">
+            <el-form-item v-if="form.isProduct === 1" label="结束售卖时间" prop="listingStartTime">
               <el-input-number v-model="form.listingEndTime" :min="0" label="结束售卖时间"></el-input-number>
             </el-form-item>
           </el-col>
@@ -310,6 +295,19 @@
       </course-watch-comment>
     </el-dialog>
 
+
+    <el-dialog title="修改课节排序" :visible.sync="openVideoSort" style="width: 1600px;" append-to-body>
+      <draggable v-model="userCourseVideoSortList" @end="onDragEndDay" style="padding: 10px">
+        <el-button style="margin: 8px 4px;" v-for="(item, index) in userCourseVideoSortList" :class="item.newCourseSort != item.courseSort ? 'red':''">第{{
+            item.newCourseSort
+          }}序(原排序第{{ item.courseSort }})
+        </el-button>
+      </draggable>
+      <div style="float: right;margin-top: -20px">
+        <el-button type="primary" @click="saveSorts">保存</el-button>
+      </div>
+    </el-dialog>
+
   </div>
 </template>
 
@@ -323,8 +321,8 @@ import {
   updates,
   batchSaveVideo,
   batchUpdateRed,
-  updateUserCourseVideo
-} from "@/api/course/userCourseVideo";
+  updateUserCourseVideo, getVideoListByCourseIdAll, sortCourseVideo
+} from '@/api/course/userCourseVideo'
 import QuestionBank from "@/views/course/courseQuestionBank/QuestionBank.vue";
 import CourseProduct from "@/views/course/fsCourseProduct/CourseProduct.vue";
 import VideoUpload from "@/components/VideoUpload/index.vue";
@@ -332,10 +330,11 @@ import { listVideoResource } from '@/api/course/videoResource';
 import { getByIds } from '@/api/course/courseQuestionBank'
 import CourseWatchComment from "./courseWatchComment.vue";
 import { getCateListByPid, getCatePidList } from '@/api/course/userCourseCategory'
+import draggable from 'vuedraggable'
 
 export default {
   name: "userCourseCatalog",
-  components: { VideoUpload, QuestionBank, CourseWatchComment, CourseProduct,},
+  components: { VideoUpload, QuestionBank, CourseWatchComment, CourseProduct, draggable },
   data() {
     return {
       duration: null,
@@ -359,7 +358,6 @@ export default {
       videoUrl: "",
       uploadTypeOptions: [
         { dictLabel: "线路一", dictValue: 2 },
-
         { dictLabel: "线路二", dictValue: 3 },
       ],
       uploadLoading: false,
@@ -381,6 +379,7 @@ export default {
       fileId: '',
       courseName: null,
       userCourseVideoList: [],
+      userCourseVideoSortList: [],
       total: 0,
       redData: {
         queryParams: {
@@ -404,7 +403,7 @@ export default {
         open: false,
         loading: true,
         form: {},
-        select: [],
+        select: [], // 按用户选择顺序存储视频ID
         total: 0,
         queryParams: {
           pageNum: 1,
@@ -428,9 +427,11 @@ export default {
       single: true,
       // 非多个禁用
       multiple: true,
+      loading3: false,
+      openVideoSort: false,
       // 表单参数
       form: {
-        courseProducts:[]
+        courseProducts: []
       },
       updateBatchData: {
         open: false,
@@ -496,6 +497,7 @@ export default {
       this.courseProduct.title = '拍商品选择';
     },
 
+
     //选择疗法
     selectPackage(row) {
       const drug = {};
@@ -518,7 +520,7 @@ export default {
 
     },
 
-    courseProductResult(val){
+    courseProductResult(val) {
       this.form.courseProducts = this.form.courseProducts || [];
       for (var i = 0; i < this.form.courseProducts.length; i++) {
         if (this.form.courseProducts[i].id == val.id) {
@@ -571,7 +573,6 @@ export default {
       } else if (this.form.uploadType == 3) {
         this.videoUrl = this.form.lineThree;
       }
-      // console.log("选择的video=======>>>>>>>",this.videoUrl)
     },
     // 视频库课题
     handleSelectProjects(projectIds) {
@@ -597,7 +598,7 @@ export default {
     },
     formatDuration(seconds) {
       if (seconds === null || seconds === undefined) {
-        return '未上传视频'; // 或者您可以根据具体需求返回其他默认值
+        return '未上传视频';
       }
       const hours = Math.floor(seconds / 3600);
       const minutes = Math.floor((seconds % 3600) / 60);
@@ -614,8 +615,7 @@ export default {
       if (res.code == 200) {
         this.form.thumbnail = res.url;
         this.$forceUpdate()
-      }
-      else {
+      } else {
         this.msgError(res.msg);
       }
     },
@@ -687,6 +687,7 @@ export default {
         isTranscode: 0,
         transcodeFileKey: null,
         isProduct: 0,
+        isFirst: 0,
         listingStartTime: null,
         listingEndTime: null,
       };
@@ -710,9 +711,18 @@ export default {
       this.single = selection.length !== 1
       this.multiple = !selection.length
     },
-    // 多选框选中数据
+    // 视频库多选框选中数据(按用户点击顺序记录)
     handVideoleSelectionChange(selection) {
-      this.addBatchData.select = selection.map(item => item.id);
+      // 提取当前选中的所有ID
+      const selectedIds = selection.map(item => item.id);
+      // 处理新增选中项:保留用户点击顺序
+      selectedIds.forEach(id => {
+        if (!this.addBatchData.select.includes(id)) {
+          this.addBatchData.select.push(id);
+        }
+      });
+      // 处理取消选中项:移除已取消的ID
+      this.addBatchData.select = this.addBatchData.select.filter(id => selectedIds.includes(id));
     },
     handleAdd() {
       this.reset();
@@ -787,13 +797,6 @@ export default {
             });
             return
           }
-          // if(this.form.uploadType==null){
-          //   this.$message({
-          //     message: '请选择播放线路!',
-          //     type: 'warning'
-          //   });
-          //   return
-          // }
           if (this.form.questionBankList !== null) {
             this.form.questionBankId = this.form.questionBankList.map(item => item.id).join(',');
           }
@@ -850,12 +853,51 @@ export default {
         this.msgSuccess("删除成功");
       }).catch(() => { });
     },
+
+    handleCourseSort() {
+
+      getVideoListByCourseIdAll(this.queryParams.courseId).then(response => {
+
+        response.rows.forEach((item) => item.newCourseSort = item.courseSort);
+        this.userCourseVideoSortList = response.rows.sort((a, b) => a.courseSort - b.courseSort);
+        if (this.userCourseVideoSortList == null || this.userCourseVideoSortList.length == 0) {
+          this.$message.error("暂无课节天数")
+        } else {
+          this.openVideoSort = true;
+        }
+      })
+
+
+    },
+
+    onDragEndDay() {
+      this.userCourseVideoSortList.forEach((item, index) => {
+        item.newCourseSort = index + 1;
+      })
+      this.$forceUpdate()
+    },
+
+    saveSorts() {
+      let list = this.userCourseVideoSortList.filter(e => e.courseSort != e.newCourseSort).map(e => {
+        return { courseSort: e.newCourseSort, videoId: e.videoId }
+      })
+      this.loading3 = true;
+      sortCourseVideo(list).then(e => {
+        this.getList();
+      }).finally(() => {
+        this.userCourseVideoSortList = [];
+        this.openVideoSort = false;
+      })
+    },
+
     openAdds() {
       this.addBatchData.open = true;
       this.getRootTypeList();
       this.addBatchData.form = {
         courseId: this.courseId,
       };
+      // 重置选择顺序数组
+      this.addBatchData.select = [];
       this.resourceList();
     },
     getRootTypeList() {
@@ -889,7 +931,7 @@ export default {
         });
         return
       }
-      this.addBatchData.form.ids = this.addBatchData.select;
+      this.addBatchData.form.ids = this.addBatchData.select; // 按用户选择顺序提交
       batchSaveVideo(this.addBatchData.form).then(response => {
         this.addBatchData.open = false;
         this.getList();
@@ -941,4 +983,15 @@ export default {
   line-height: 150px;
   text-align: center;
 }
+
+
+.red:hover {
+  color: #dbdbdb !important;
+}
+
+.red {
+  background-color: #F56C6C !important;
+  color: #fff !important;
+}
+
 </style>

+ 695 - 264
src/views/components/his/integralOrderDetails.vue

@@ -1,316 +1,747 @@
 <template>
-    <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; " >
-      <div style="padding: 20px; background-color: #fff;">
-         积分订单详情
+  <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; ">
+    <div style="padding: 20px; background-color: #fff;">
+      积分订单详情
+    </div>
+    <div class="contentx" v-if="item != null">
+      <div class="desct"> 积分订单信息</div>
+      <div class="order-status" v-if="item != null && item.status != 5">
+        <el-steps :active="getStepActive(item.status)" align-center finish-status="success">
+          <el-step title="待支付"></el-step>
+          <el-step title="待发货"></el-step>
+          <el-step title="待收货"></el-step>
+          <el-step title="已完成"></el-step>
+        </el-steps>
       </div>
-<div class="contentx" v-if="item!=null">
-        <div class="desct"> 积分订单信息</div>
-        <div class="order-status" v-if="item!=null && item.status != 5" >
-                  <el-steps  :active="item.status==4?0:item.status" align-center finish-status="success">
-                    <el-step title="待支付"></el-step>
-                    <el-step title="待发货"></el-step>
-                    <el-step title="待收货"></el-step>
-                    <el-step title="已完成"></el-step>
-                  </el-steps>
+      <el-card shadow="never" style="margin-top: 15px">
+        <div class="operate-container" v-if="item != null">
+          <span style="margin-left: 20px" class="color-danger">订单状态:
+            <el-tag prop="status" v-for="(ite, index) in statusOptions" v-if="item.status == ite.dictValue">{{
+              ite.dictLabel }}</el-tag>
+          </span>
+          <div class="operate-button-container" v-if="item.status == 1" v-hasPermi="['his:integralOrder:sendGoods']">
+            <!-- <el-button size="mini" @click="sendVisible=true" >发货</el-button> -->
+            <el-button size="mini" @click="showSend()">发货</el-button>
+          </div>
+          <div class="operate-button-container" v-if="item.deliverySn != null"
+            v-hasPermi="['his:integralOrder:express']">
+            <el-button size="mini" @click="showExpress()">查看物流</el-button>
+          </div>
+
+          <div class="operate-button-container" v-if="item.status!=-1" v-hasPermi="['his:integralOrder:edit']">
+            <el-button size="mini" @click="updateOrder()">修改订单</el-button>
+          </div>
+
+          <div class="operate-button-container" v-if="item.status==2">
+            <el-button size="mini" @click="handleFinishOrder">确认收货</el-button>
+          </div>
+          <div class="operate-button-container" v-if="item.status>1" v-hasPermi="['his:integralOrder:cancel']">
+            <el-button size="mini" @click="applyRefund">申请退款</el-button>
+          </div>
         </div>
-         <el-card shadow="never" style="margin-top: 15px">
-           <div class="operate-container"  v-if="item!=null">
-             <span style="margin-left: 20px" class="color-danger">订单状态:
-                <el-tag prop="status" v-for="(ite, index) in statusOptions"    v-if="item.status==ite.dictValue">{{ite.dictLabel}}</el-tag>
-             </span>
-             <div class="operate-button-container"  v-if="item.status==1" v-hasPermi="['his:integralOrder:sendGoods']">
-                <el-button size="mini" @click="sendVisible=true" >发货</el-button>
-             </div>
-            <div class="operate-button-container"   v-if="item.deliverySn!=null" v-hasPermi="['his:integralOrder:express']">
-              <el-button size="mini" @click="showExpress()" >查看物流</el-button>
-            </div>
+        <div class="desct">
+          基本信息
+        </div>
+        <el-descriptions title="" :column="3" border>
+          <el-descriptions-item label="订单编号"><span v-if="item != null">{{ item.orderCode
+              }}</span></el-descriptions-item>
+          <el-descriptions-item label="会员ID"><span v-if="item != null">{{ item.userId }}</span></el-descriptions-item>
+          <el-descriptions-item label="会员"><span v-if="item.nickName != null">{{ item.nickName }}({{ item.phone
+              }})</span></el-descriptions-item>
+          <el-descriptions-item label="用户名称"><span v-if="item != null">{{ item.userName }}</span></el-descriptions-item>
+          <el-descriptions-item label="用户电话"><span v-if="item != null">{{ item.userPhone }}</span>
+            <el-button icon="el-icon-search" size="mini" @click="handlePhone()" style="margin-left: 20px;" circle
+              v-hasPermi="['his:integralOrder:queryPhone']"></el-button>
+          </el-descriptions-item>
+          <el-descriptions-item label="用户地址"><span v-if="item != null">{{ item.userAddress
+              }}</span></el-descriptions-item>
+          <el-descriptions-item label="支付积分"><span v-if="item != null">{{ item.integral }}</span></el-descriptions-item>
+          <el-descriptions-item label="状态"><span v-if="item != null"> <dict-tag :options="statusOptions"
+                :value="item.status" /></span></el-descriptions-item>
+          <el-descriptions-item label="快递公司编号"><span v-if="item != null">{{ item.deliveryCode
+              }}</span></el-descriptions-item>
+          <el-descriptions-item label="快递名称"><span v-if="item != null">{{ item.deliveryName
+              }}</span></el-descriptions-item>
+          <el-descriptions-item label="快递单号"><span v-if="item != null">{{ item.deliverySn
+              }}</span></el-descriptions-item>
+          <el-descriptions-item label="发货时间"><span v-if="item != null">{{ item.deliveryTime
+              }}</span></el-descriptions-item>
+          <el-descriptions-item label="提交时间"><span v-if="item != null">{{ item.createTime
+              }}</span></el-descriptions-item>
+        </el-descriptions>
+      </el-card>
 
-            <div class="operate-button-container"  v-hasPermi="['his:integralOrder:edit']">
-              <el-button size="mini" @click="updateOrder()" >修改订单</el-button>
-            </div>
-           </div>
-           <div class="desct">
-            基本信息
-           </div>
-           <el-descriptions title="" :column="3" border>
-             <el-descriptions-item label="订单编号"><span v-if="item!=null">{{item.orderCode}}</span></el-descriptions-item>
-              <el-descriptions-item label="会员ID"><span v-if="item!=null">{{item.userId}}</span></el-descriptions-item>
-             <el-descriptions-item label="会员"><span v-if="item.nickName!=null">{{item.nickName}}({{item.phone}})</span></el-descriptions-item>
-             <el-descriptions-item label="用户名称"><span v-if="item!=null">{{item.userName}}</span></el-descriptions-item>
-             <el-descriptions-item label="用户电话"><span v-if="item!=null">{{item.userPhone}}</span>
-              <el-button icon="el-icon-search" size="mini" @click="handlePhone()" style="margin-left: 20px;" circle v-hasPermi="['his:integralOrder:queryPhone']"></el-button>
-            </el-descriptions-item>
-              <el-descriptions-item label="用户地址"><span v-if="item!=null">{{item.userAddress}}</span></el-descriptions-item>
-             <el-descriptions-item label="支付积分"><span v-if="item!=null">{{item.integral}}</span></el-descriptions-item>
-             <el-descriptions-item label="状态"><span v-if="item!=null"> <dict-tag :options="statusOptions" :value="item.status"/></span></el-descriptions-item>
-             <el-descriptions-item label="快递公司编号"><span v-if="item!=null">{{item.deliveryCode}}</span></el-descriptions-item>
-             <el-descriptions-item label="快递名称"><span v-if="item!=null">{{item.deliveryName}}</span></el-descriptions-item>
-             <el-descriptions-item label="快递单号"><span v-if="item!=null">{{item.deliverySn}}</span></el-descriptions-item>
-             <el-descriptions-item label="发货时间"><span v-if="item!=null">{{item.deliveryTime}}</span></el-descriptions-item>
-             <el-descriptions-item label="提交时间"><span v-if="item!=null">{{item.createTime}}</span></el-descriptions-item>
-           </el-descriptions>
-         </el-card>
+    </div>
+    <div class="contentx" v-if="item != null" style="padding-bottom: 70px;">
+      <div class="desct">
+        商品信息
+      </div>
+      <el-table border v-if="prod != null" :data="prod" size="small" style="margin-top: 20px">
+        <el-table-column label="商品图片" align="center">
+          <template slot-scope="scope">
+            <img :src="scope.row.imgUrl" style="height: 80px">
+          </template>
+        </el-table-column>
+        <el-table-column label="商品名称" align="center">
+          <template slot-scope="scope">
+            <p>{{ scope.row.goodsName }}</p>
+          </template>
+        </el-table-column>
+        <el-table-column label="积分" align="center">
+          <template slot-scope="scope">
+            <p>¥{{ scope.row.integral }}</p>
+          </template>
+        </el-table-column>
+        <el-table-column label="金额" align="center">
+          <template slot-scope="scope">
+            <p>¥{{ scope.row.cash || 0 }}</p>
+          </template>
+        </el-table-column>
 
+      </el-table>
     </div>
-      <div class="contentx" v-if="item!=null" style="padding-bottom: 70px;">
-       <div class="desct">
-           商品信息
-          </div>
-       <el-table
-              border
-              v-if="prod!=null"
-              :data="prod"
-              size="small"
-              style="margin-top: 20px" >
-              <el-table-column label="商品图片"  align="center">
-                <template slot-scope="scope">
-                  <img :src="scope.row.imgUrl" style="height: 80px">
-                </template>
-              </el-table-column>
-              <el-table-column label="商品名称"  align="center">
-                <template slot-scope="scope">
-                  <p>{{scope.row.goodsName}}</p>
-                </template>
-              </el-table-column>
-              <el-table-column label="积分" align="center">
+    <el-dialog width="50%" title="发货" :visible.sync="sendVisible" append-to-body @close="sendCancel">
+      <el-form ref="form" :model="form" label-width="120px">
+        <el-form-item label="快递名称" prop="deliveryName">
+          <el-select v-model="selectedExpress" placeholder="请选择快递名称" value-key="name">
+            <el-option v-for="item in expressOption" :key="item.name" :label="item.name" :value="item">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="快递公司编号" prop="deliveryCode">
+          <el-input v-model="form.deliveryCode" placeholder="请输入快递公司编号" disabled />
+
+        </el-form-item>
+
+        <el-form-item label="快递单号" prop="deliverySn">
+          <el-input v-model="form.deliverySn" placeholder="请输入快递单号" />
+        </el-form-item>
+
+        <!-- 代服账号选择表格 -->
+        <el-form-item label="代服账号选择" prop="selectedAccount" required>
+          <div style="border: 1px solid #e6ebf5; border-radius: 4px; padding: 10px;">
+            <el-table ref="accountTable" :data="tableData" highlight-current-row
+              @current-change="handleAccountSelectionChange" style="width: 100%" size="small" max-height="400">
+              <!-- 固定高度,超出滚动 -->
+
+              <el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
+              <el-table-column prop="loginAccount" label="登录账号" align="center" width="120"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="monthlyCard" label="月结账号" align="center" width="120"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="expressProductCode" label="物流产品" align="center" width="120" show-overflow-tooltip>
                 <template slot-scope="scope">
-                  <p>¥{{scope.row.integral}}</p>
+                  <dict-tag :options="expressOptions" :value="scope.row.expressProductCode" />
                 </template>
               </el-table-column>
-              <el-table-column label="金额" align="center">
-               <template slot-scope="scope">
-                 <p>¥{{scope.row.cash || 0}}</p>
-               </template>
-              </el-table-column>
+              <el-table-column prop="senderName" label="寄件人姓名" align="center" width="100"></el-table-column>
+              <el-table-column prop="senderPhone" label="寄件人手机" align="center" width="120"></el-table-column>
+              <el-table-column prop="senderProvince" label="寄件人省" align="center" width="100"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="senderCity" label="寄件人市" align="center" width="100"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="senderDistrict" label="寄件人区" align="center" width="100"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="senderAddress" label="寄件人地址" align="center" min-width="150"
+                show-overflow-tooltip></el-table-column>
 
             </el-table>
-       </div>
-      <el-dialog
-           width="50%"
-           title="发货"
-           :visible.sync="sendVisible"
-           append-to-body @close="sendCancel">
-      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
-          <el-form-item label="快递公司编号" prop="deliveryCode">
-                    <el-input v-model="form.deliveryCode" placeholder="请输入快递公司编号" />
-                  </el-form-item>
-                  <el-form-item label="快递名称" prop="deliveryName">
-                    <el-input v-model="form.deliveryName" placeholder="请输入快递名称" />
-                  </el-form-item>
-                  <el-form-item label="快递单号" prop="deliverySn">
-                    <el-input v-model="form.deliverySn" placeholder="请输入快递单号" />
-                  </el-form-item>
-        </el-form>
-        <div slot="footer" class="dialog-footer">
-                          <el-button type="primary" @click="sendGoods">确 定</el-button>
-                          <el-button @click="sendCancel">取 消</el-button>
-        </div>
 
-          </el-dialog>
+            <!-- 分页 -->
+            <el-pagination small layout="prev, pager, next" :total="total" :page-size="queryParams.pageSize"
+              :current-page="queryParams.pageNum" @current-change="handlePageChange"
+              style="margin-top: 10px; text-align: center;">
+            </el-pagination>
 
-          <el-dialog :title="expressDialog.title" :visible.sync="expressDialog.open" width="600px" append-to-body>
-            <el-table style="margin-top: 20px;width: 100%"
-                      ref="orderHistoryTable"
-                      :data="traces" border>
-              <el-table-column label="操作时间"  width="160" align="center">
-                <template slot-scope="scope">
-                  {{scope.row.AcceptTime}}
-                </template>
-              </el-table-column>
-               <el-table-column label="位置" align="center">
-                <template slot-scope="scope">
-                  {{scope.row.Location}}
-                </template>
-              </el-table-column>
-              <el-table-column label="描述" align="center">
+            <div style="margin-top: 10px; color: #909399; font-size: 12px; text-align: center;">
+              提示:点击表格行选择代服账号
+            </div>
+
+            <!-- 显示选中信息 -->
+            <div v-if="selectedRow" style="margin-top: 10px; padding: 8px; background: #f5f7fa; border-radius: 4px;">
+              <span style="color: #67C23A;">已选择:</span>
+              <span>{{ selectedRow.loginAccount }} ({{ selectedRow.senderName }})</span>
+            </div>
+          </div>
+        </el-form-item>
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="sendGoods">确 定</el-button>
+        <el-button @click="sendCancel">取 消</el-button>
+      </div>
+
+    </el-dialog>
+
+    <el-dialog :title="expressDialog.title" :visible.sync="expressDialog.open" width="600px" append-to-body>
+      <el-table style="margin-top: 20px;width: 100%" ref="orderHistoryTable" :data="traces" border>
+        <el-table-column label="操作时间" width="160" align="center">
+          <template slot-scope="scope">
+            {{ scope.row.AcceptTime }}
+          </template>
+        </el-table-column>
+        <el-table-column label="位置" align="center">
+          <template slot-scope="scope">
+            {{ scope.row.Location }}
+          </template>
+        </el-table-column>
+        <el-table-column label="描述" align="center">
+          <template slot-scope="scope">
+            {{ scope.row.AcceptStation }}
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-dialog>
+
+    <el-dialog :title="editOrder.title" :visible.sync="editOrder.open" width="600px" append-to-body>
+      <el-form ref="editForm" :model="editForm" :rules="editRules" label-width="100px">
+        <el-form-item label="订单状态" prop="status">
+          <el-select v-model="editForm.status" placeholder="请选择状态" clearable size="small" filterable>
+            <el-option v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictLabel"
+              :value="dict.dictValue" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="详情地址" prop="userAddress">
+          <el-input v-model="editForm.userAddress" placeholder="请输入" />
+        </el-form-item>
+
+        <!-- 修改:快递信息改为下拉选择 -->
+        <el-form-item label="快递名称" prop="deliveryName">
+          <el-select v-model="editSelectedExpress" placeholder="请选择快递名称" value-key="name" clearable>
+            <el-option v-for="item in expressOption" :key="item.name" :label="item.name" :value="item">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="快递公司编号" prop="deliveryCode">
+          <el-input v-model="editForm.deliveryCode" placeholder="快递公司编号" disabled />
+        </el-form-item>
+        <el-form-item label="快递单号" prop="deliverySn">
+          <el-input v-model="editForm.deliverySn" placeholder="请输入快递单号" />
+        </el-form-item>
+
+        <!-- 代服账号选择表格 - 使用同一个数据源 -->
+        <el-form-item label="代服账号" prop="loginAccount">
+          <div style="border: 1px solid #e6ebf5; border-radius: 4px; padding: 10px;">
+            <el-table ref="editAccountTable" :data="tableData" highlight-current-row
+              @current-change="handleEditAccountSelectionChange" style="width: 100%" size="small" max-height="300">
+
+              <!-- 列定义与发货弹窗相同 -->
+              <el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
+              <el-table-column prop="loginAccount" label="登录账号" align="center" width="120"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="monthlyCard" label="月结账号" align="center" width="120"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="expressProductCode" label="物流产品" align="center" width="120" show-overflow-tooltip>
                 <template slot-scope="scope">
-                  {{scope.row.AcceptStation}}
+                  <dict-tag :options="expressOptions" :value="scope.row.expressProductCode" />
                 </template>
               </el-table-column>
+              <el-table-column prop="senderName" label="寄件人姓名" align="center" width="100"></el-table-column>
+              <el-table-column prop="senderPhone" label="寄件人手机" align="center" width="120"></el-table-column>
+              <el-table-column prop="senderProvince" label="寄件人省" align="center" width="100"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="senderCity" label="寄件人市" align="center" width="100"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="senderDistrict" label="寄件人区" align="center" width="100"
+                show-overflow-tooltip></el-table-column>
+              <el-table-column prop="senderAddress" label="寄件人地址" align="center" min-width="150"
+                show-overflow-tooltip></el-table-column>
+
             </el-table>
-          </el-dialog>
-
-          <el-dialog :title="editOrder.title" :visible.sync="editOrder.open" width="600px" append-to-body>
-            <el-form ref="editForm" :model="editForm" :rules="editRules" label-width="100px">
-              <el-form-item label="订单状态" prop="status" >
-                <el-select v-model="editForm.status" placeholder="请选择状态" clearable size="small" filterable>
-                    <el-option
-                      v-for="dict in statusOptions "
-                      :key="dict.dictValue"
-                      :label="dict.dictLabel"
-                      :value="dict.dictValue"
-                    />
-                  </el-select>
-                </el-form-item>
-              <el-form-item label="详情地址" prop="userAddress"  >
-                <el-input v-model="editForm.userAddress" placeholder="请输入" />
-              </el-form-item>
-              <el-form-item label="备注" prop="remark"  >
-                <el-input v-model="editForm.remark" placeholder="请输入备注" />
-              </el-form-item>
-            </el-form>
-            <div slot="footer" class="dialog-footer">
-              <el-button type="primary" @click="submitEditForm">确 定</el-button>
+
+            <!-- 分页 - 使用同一个分页数据 -->
+            <el-pagination small layout="prev, pager, next" :total="total" :page-size="queryParams.pageSize"
+              :current-page="queryParams.pageNum" @current-change="handlePageChange"
+              style="margin-top: 10px; text-align: center;">
+            </el-pagination>
+
+            <div style="margin-top: 10px; color: #909399; font-size: 12px; text-align: center;">
+              提示:点击表格行选择代服账号
             </div>
-          </el-dialog>
-    </div>
+
+            <!-- 显示选中信息 -->
+            <div v-if="editSelectedRow"
+              style="margin-top: 10px; padding: 8px; background: #f5f7fa; border-radius: 4px;">
+              <span style="color: #67C23A;">已选择:</span>
+              <span>{{ editSelectedRow.loginAccount }} ({{ editSelectedRow.senderName }})</span>
+            </div>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="editForm.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitEditForm">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
 </template>
 
 <script>
-import {getExpress, listIntegralOrder, sendgoods,getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder,getOrderUserPhone } from "@/api/his/integralOrder";
-  export default {
-    name: "integralOrder",
-    data() {
-      return {
-        expressDialog:{
-          title:"物流信息",
-          open:false,
-        },
-        editOrder:{
-          title:"修改订单",
-          open:false,
-        },
-        editForm:{
-          orderId:null,
-          status:null,
-          userAddress:null,
-          remark:"",
-        },
-        editRules:{},
-        item:null,
-        express:null,
-        traces:[],
-        rules:{
-      deliveryCode: [
-        { required: true, message: '请输入快递公司编号', trigger: 'blur' }
-      ],
-      deliveryName: [
-        { required: true, message: '请输入快递名称', trigger: 'blur' }
-      ],
-      deliverySn: [
-        { required: true, message: '请输入快递单号', trigger: 'blur' }
-      ]
+import { getExpress,mandatoryRefunds,finishOrder, listIntegralOrder, sendgoods, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder, getOrderUserPhone } from "@/api/his/integralOrder";
+import { getExpressList } from "@/api/his/express";
+import { listAccount } from "@/api/his/dfAccount";
+export default {
+  name: "integralOrder",
+  data() {
+    return {
+      selectedExpress: null,
+      expressOption: [],
+      expressDialog: {
+        title: "物流信息",
+        open: false,
+      },
+      editOrder: {
+        title: "修改订单",
+        open: false,
+      },
+      editForm: {
+        orderId: null,
+        status: null,
+        userAddress: null,
+        remark: "",
+        loginAccount: null,
+        // 新增快递相关字段
+        deliveryName: null,
+        deliveryCode: null,
+        deliverySn: null
+      },
+      editRules: {
+        deliveryName: [
+          { required: false, message: '请输入快递名称', trigger: 'blur' }
+        ],
+        deliveryCode: [
+          { required: false, message: '请输入快递公司编号', trigger: 'blur' }
+        ],
+        deliverySn: [
+          { required: false, message: '请输入快递单号', trigger: 'blur' }
+        ]
+      },
+      item: null,
+      express: null,
+      traces: [],
+      rules: {
+        deliveryCode: [
+          { required: true, message: '请输入快递公司编号', trigger: 'blur' }
+        ],
+        deliveryName: [
+          { required: true, message: '请输入快递名称', trigger: 'blur' }
+        ],
+        deliverySn: [
+          { required: true, message: '请输入快递单号', trigger: 'blur' }
+        ],
+        selectedAccount: [  // 添加这一项
+          { required: true, message: '请选择代服账号', trigger: 'change' }
+        ]
+      },
+      sendVisible: false,
+      form: {
+        deliveryCode: null,
+        deliveryName: null,
+        deliverySn: null,
+        orderId: null,
+        loginAccount: null  // 在 form 中也添加这个字段
+      },
+      tableData: [], // 清空模拟数据,改为空数组
+      selectedRow: null,
+      editSelectedRow: null, // 修改订单弹窗选中的行
+      queryParams: { // 查询参数
+        pageNum: 1,
+        pageSize: 10
+      },
+      total: 0, // 总条数,
+      expressOptions: [], // 物流产品字典
+      editSelectedExpress: null,
+    }
+  },
+  created() {
+    this.getDicts("sys_integral_order_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("df_account_express").then(response => {
+      this.expressOptions = response.data;
+    });
+  },
+  watch: {
+    selectedExpress(newVal) {
+      console.log('选中的快递:', newVal); // 调试用
+      if (newVal && newVal.name && newVal.code) {
+        this.form.deliveryName = newVal.name;
+        this.form.deliveryCode = newVal.code;
+      } else {
+        this.form.deliveryName = '';
+        this.form.deliveryCode = '';
+      }
     },
-        sendVisible:false,
-        form: {
-          deliveryCode: null,
-          deliveryName:null,
-          deliverySn:null,
-          orderId:null,
+    // 新增:修改订单弹窗的快递选择监听
+    editSelectedExpress(newVal) {
+      console.log('修改订单弹窗选中的快递:', newVal);
+      if (newVal && newVal.name && newVal.code) {
+        this.editForm.deliveryName = newVal.name;
+        this.editForm.deliveryCode = newVal.code;
+      } else {
+        this.editForm.deliveryName = '';
+        this.editForm.deliveryCode = '';
+      }
+    },
+    'editOrder.open': function (newVal) {
+      if (!newVal) {
+        // 修改订单弹窗关闭时清理选择状态
+        this.editSelectedRow = null;
+        if (this.$refs.editAccountTable) {
+          this.$refs.editAccountTable.setCurrentRow();
         }
       }
     },
-    created() {
-      this.getDicts("sys_integral_order_status").then(response => {
-        this.statusOptions = response.data;
-      });
+    'expressDialog.open': function (newVal) {
+      if (!newVal) {
+        // 查看物流弹窗关闭时清理数据
+        this.express = null;
+        this.traces = [];
+      }
     },
-    methods: {
-      handlePhone(){
-        const orderId = this.item.orderId;
-        getOrderUserPhone(orderId).then(response =>{
-            this.item.userPhone = response.userPhone;
-        })
-      },
-      updateOrder(){
-        this.editOrder.open=true;
-        this.editForm.orderId=this.item.orderId;
-        this.editForm.remark=this.item.remark;
-        this.editForm.status = this.item.status.toString();
-        this.editForm.userAddress = this.item.userAddress.toString();
-      },
-     //修改订单状态
-     submitEditForm(){
-        this.$refs["editForm"].validate(valid => {
+  },
+  methods: {
+    getStepActive(status) {
+      const statusMap = {
+        4: 1, // 待支付 -> 激活第1步(显示到待支付)
+        1: 2, // 待发货 -> 激活第2步(显示到待发货)
+        2: 3, // 待收货 -> 激活第3步(显示到待收货)
+        3: 4  // 已完成 -> 激活第4步(全部完成)
+      };
+      return statusMap[status] || 0;
+    },
+    handlePhone() {
+      const orderId = this.item.orderId;
+      getOrderUserPhone(orderId).then(response => {
+        this.item.userPhone = response.userPhone;
+      })
+    },
+    async updateOrder() {
+      this.editOrder.open = true;
+      this.editForm.orderId = this.item.orderId;
+      this.editForm.remark = this.item.remark;
+      this.editForm.status = this.item.status.toString();
+      this.editForm.userAddress = this.item.userAddress.toString();
+      this.editForm.loginAccount = this.item.loginAccount;
+
+      // 设置快递字段的初始值
+      this.editForm.deliveryName = this.item.deliveryName;
+      this.editForm.deliveryCode = this.item.deliveryCode;
+      this.editForm.deliverySn = this.item.deliverySn;
+
+      // 重置选择状态
+      this.editSelectedRow = null;
+      this.editSelectedExpress = null;
+
+      try {
+        // 1. 先确保快递选项数据已加载
+        if (this.expressOption.length === 0) {
+          await getExpressList().then(response => {
+            this.expressOption = response.data;
+          });
+        }
+
+        // 2. 设置选中的快递(在快递数据加载完成后)
+        if (this.item.deliveryName && this.expressOption.length > 0) {
+          const currentExpress = this.expressOption.find(item =>
+            item.name === this.item.deliveryName
+          );
+          if (currentExpress) {
+            this.editSelectedExpress = currentExpress;
+          }
+        }
+
+        // 3. 等待代服账号数据加载完成
+        await this.getAccountList();
+
+        // 4. 在数据都加载完成后尝试选中对应的行
+        if (this.item.loginAccount) {
+          this.$nextTick(() => {
+            this.selectCurrentAccount();
+          });
+        }
+      } catch (error) {
+        console.error('加载数据失败:', error);
+      }
+    },
+    // 选中当前账号(修改订单弹窗使用)
+    selectCurrentAccount() {
+      if (!this.item.loginAccount || !this.tableData || this.tableData.length === 0) {
+        console.log('无法选中账号:数据未就绪');
+        return;
+      }
+
+      const currentAccount = this.tableData.find(item =>
+        item.loginAccount === this.item.loginAccount
+      );
+
+      if (currentAccount) {
+        this.editSelectedRow = currentAccount;
+        this.$nextTick(() => {
+          if (this.$refs.editAccountTable) {
+            this.$refs.editAccountTable.setCurrentRow(currentAccount);
+            console.log('成功选中代服账号:', currentAccount.loginAccount);
+          }
+        });
+      } else {
+        console.log('未找到对应的代服账号:', this.item.loginAccount);
+      }
+    },
+    //修改订单状态
+    submitEditForm() {
+      this.$refs["editForm"].validate(valid => {
         if (valid) {
           updateIntegralOrder(this.editForm).then(response => {
             if (response.code === 200) {
               this.msgSuccess("操作成功");
               this.editOrder.open = false;
               this.getDetails(this.item.orderId);
-              }
-            });
-          }
-        });
-      },
-      sendCancel(){
-           this.sendVisible = false;
-           this.form={
-             deliveryCode: null,
-             deliveryName:null,
-             deliverySn:null,
-             orderId:null,
-           }
-      },
-      showExpress(){
-        this.expressDialog.open=true;
-        getExpress(this.item.orderId).then(response => {
-            this.express = response.data;
-            if(this.express!=null&&this.express.Traces!=null){
-                this.traces=this.express.Traces
             }
+          });
+        }
+      });
+    },
+    sendCancel() {
+      this.sendVisible = false;
+      this.form = {
+        deliveryCode: null,
+        deliveryName: null,
+        deliverySn: null,
+        orderId: null,
+        loginAccount: null
+      };
+      this.selectedExpress = null;
+      this.selectedRow = null;
+      if (this.$refs.accountTable) {
+        this.$refs.accountTable.setCurrentRow();
+      }
+    },
+    showSend() {
+      // 重置表单和选择状态
+      this.form = {
+        deliveryCode: null,
+        deliveryName: null,
+        deliverySn: null,
+        orderId: null,
+        loginAccount: null
+      };
+      this.selectedExpress = null;
+      this.selectedRow = null;
+
+      // 获取快递公司信息
+      getExpressList().then(response => {
+        this.expressOption = response.data;
+      });
+
+      // 获取代服账号列表
+      this.getAccountList();
+
+      this.sendVisible = true;
+    },
+    showExpress() {
+      this.expressDialog.open = true;
+      getExpress(this.item.orderId).then(response => {
+        this.express = response.data;
+        if (this.express != null && this.express.Traces != null) {
+          this.traces = this.express.Traces
+        }
+      });
+    },
+    sendGoods() {
+      // 手动验证所有必填字段
+      if (!this.selectedRow) {
+        this.msgError('请选择代服账号');
+        return;
+      }
+
+      if (!this.form.deliveryName || !this.form.deliveryCode) {
+        this.msgError('请选择快递公司');
+        return;
+      }
+
+      if (!this.form.deliverySn) {
+        this.msgError('请输入快递单号');
+        return;
+      }
+
+      // 所有验证通过,直接发送
+      this.form.orderId = this.item.orderId;
+      sendgoods(this.form).then(response => {
+        this.msgSuccess("发货成功");
+        this.sendVisible = false;
+        getIntegralOrder(this.item.orderId).then(response => {
+          this.item = response.data;
+          this.$parent.$parent.getList();
         });
-      },
-          sendGoods(){
-              this.form.orderId=this.item.orderId;
-              sendgoods(this.form).then(response => {
-                    this.msgSuccess("修改成功");
-                    this.sendVisible = false;
-                    getIntegralOrder(this.item.orderId).then(response => {
-                        this.item = response.data;
-                        this.$parent.$parent.getList();
-                    });
-
-                    this.form={
-                    deliveryCode: null,
-                    deliveryName:null,
-                    deliverySn:null,
-                    orderId:null,
-                  }
-              });
-            },
-      getDetails(orderId) {
-        this.item=null;
-        getIntegralOrder(orderId).then(response => {
-            this.item = response.data;
-            this.prod=[JSON.parse(this.item.itemJson)];
+
+        this.form = {
+          deliveryCode: null,
+          deliveryName: null,
+          deliverySn: null,
+          orderId: null,
+          loginAccount: null
+        };
+        this.selectedRow = null;
+      });
+    },
+    getDetails(orderId) {
+      this.item = null;
+      getIntegralOrder(orderId).then(response => {
+        this.item = response.data;
+        this.prod = [JSON.parse(this.item.itemJson)][0];
+      });
+    },
+    // 代服账号选择变化
+    handleAccountSelectionChange(currentRow, oldRow) {
+      this.selectedRow = currentRow;
+      if (currentRow) {
+        this.form.loginAccount = currentRow.loginAccount;
+      }
+    },
+    // 修改订单弹窗的代服账号选择
+    handleEditAccountSelectionChange(currentRow, oldRow) {
+      this.editSelectedRow = currentRow;
+      if (currentRow) {
+        this.editForm.loginAccount = currentRow.loginAccount;
+      }
+    },
+    // 获取代服账号列表
+    getAccountList() {
+      return new Promise((resolve, reject) => {
+        listAccount(this.queryParams).then(response => {
+          this.tableData = response.rows || response.data || [];
+          this.total = response.total || 0;
+          resolve(this.tableData); // 数据加载完成
+        }).catch(error => {
+          this.tableData = [];
+          reject(error);
         });
-      },
-    }
+      });
+    },
+    handlePageChange(page) {
+      this.queryParams.pageNum = page;
+      this.getAccountList();
+    },
+    // 取消订单
+    applyRefund() {
+      this.$confirm('确定要取消该订单吗?取消后订单将无法恢复。', '取消订单确认', {
+        confirmButtonText: '确定取消',
+        cancelButtonText: '再想想',
+        type: 'warning',
+        confirmButtonClass: 'el-button--danger'
+      }).then(() => {
+        this.cancelOrder();
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消操作'
+        });
+      });
+    },
+
+    // 执行取消订单请求
+    cancelOrder() {
+      const orderCode = this.item.orderCode;
+      mandatoryRefunds(orderCode).then(response => {
+        if (response.code === 200) {
+          this.msgSuccess("取消订单成功");
+          // 刷新订单详情
+          this.getDetails(this.item.orderId);
+          // 刷新父组件列表(如果有)
+          if (this.$parent && this.$parent.$parent && this.$parent.$parent.getList) {
+            this.$parent.$parent.getList();
+          }
+        } else {
+          this.msgError(response.msg || "取消订单失败");
+        }
+      }).catch(error => {
+        this.msgError("取消订单失败");
+        console.error('取消订单失败:', error);
+      });
+    },
+    // 完成订单
+    handleFinishOrder() {
+      this.$confirm('确定要完成该订单吗?完成后订单状态将变为已完成。', '完成订单确认', {
+        confirmButtonText: '确定完成',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        // 用户点击确定
+        this.executeFinishOrder();
+      }).catch(() => {
+        // 用户点击取消
+        this.$message({
+          type: 'info',
+          message: '已取消操作'
+        });
+      });
+    },
+    
+    // 执行完成订单请求
+    executeFinishOrder() {
+      const orderCode = this.item.orderCode;
+      console.log("请问请问",orderCode)
+      finishOrder(orderCode).then(response => {
+        if (response.code === 200) {
+          this.msgSuccess("订单完成成功");
+          // 刷新订单详情
+          this.getDetails(this.item.orderId);
+          // 刷新父组件列表(如果有)
+          if (this.$parent && this.$parent.$parent && this.$parent.$parent.getList) {
+            this.$parent.$parent.getList();
+          }
+        } else {
+          this.msgError(response.msg || "订单完成失败");
+        }
+      }).catch(error => {
+        this.msgError("订单完成失败");
+        console.error('完成订单失败:', error);
+      });
+    },
   }
+}
 </script>
 <style>
-  .contentx{
-      height: 100%;
-      background-color: #fff;
-      padding: 0px 20px 20px;
+.contentx {
+  height: 100%;
+  background-color: #fff;
+  padding: 0px 20px 20px;
 
 
-      margin: 20px;
-  }
-  .el-descriptions-item__label.is-bordered-label{
-    font-weight: normal;
-  }
-  .el-descriptions-item__content {
-    max-width: 150px;
-    min-width: 100px;
-  }
-  .desct{
-      padding-top: 20px;
-      padding-bottom: 20px;
-      color: #524b4a;
-      font-weight: bold;
-    }
+  margin: 20px;
+}
+
+.el-descriptions-item__label.is-bordered-label {
+  font-weight: normal;
+}
+
+.el-descriptions-item__content {
+  max-width: 150px;
+  min-width: 100px;
+}
+
+.desct {
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #524b4a;
+  font-weight: bold;
+}
+
 .operate-container {
   background: #F2F6FC;
   height: 60px;
   margin: -20px -20px 0;
   line-height: 60px;
 }
-.order-content{
+
+.order-content {
   margin: 10px;
 
 }
+
 .operate-button-container {
   float: right;
   margin-right: 20px

+ 26 - 0
src/views/components/his/packageDetails.vue

@@ -60,6 +60,15 @@
             :src="img"
             :preview-src-list="[img]">
         </el-image>
+    </el-descriptions-item>
+    <el-descriptions-item label="所属小程序">
+      <el-tag
+        v-for="name in appNames"
+        :key="name"
+        style="margin-right: 4px"
+      >
+        {{ name }}
+      </el-tag>
     </el-descriptions-item>
         </el-descriptions>
             </div>
@@ -116,6 +125,7 @@
 
 <script>
 import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportPackage } from "@/api/his/package";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
   export default {
     name: "patientdetails",
     props:["data"],
@@ -129,6 +139,7 @@ import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportP
        orOptions:[],
        packageTypeOptions: [],
        diseaseTypeOptions: [],
+       appMallOptions:[],
        // 是否删除字典
        isDelOptions: [],
        packageSubTypeOptions:[],
@@ -136,6 +147,15 @@ import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportP
         productJson:[],
       }
     },
+    computed: {
+      appNames() {
+        if (!this.item.appIds) return [];
+        const ids = this.item.appIds.split(',');
+        return ids
+          .map(id => this.appMallOptions.find(opt => opt.appid === id)?.name)
+          .filter(Boolean); // 过滤掉找不到的
+      }
+    },
     created() {
      this.getDicts("sys_company_status").then(response => {
        this.statusOptions = response.data;
@@ -159,9 +179,15 @@ import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportP
      this.getDicts("sys_prescribe_disease_type").then(response => {
        this.diseaseTypeOptions = response.data;
      });
+     this.getAppMallOptions();
 
     },
     methods: {
+      getAppMallOptions() {
+        getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+          this.appMallOptions = response.rows;
+        })
+      },
       getDetails(orderId) {
           this.item=null;
           getPackage(orderId).then(response => {

+ 6 - 1
src/views/components/his/storeAfterSalesDetails.vue

@@ -114,7 +114,12 @@
           </el-table-column>
           <el-table-column label="小计"  align="center">
             <template slot-scope="scope">
-              ¥{{JSON.parse(scope.row.jsonInfo).num*JSON.parse(scope.row.jsonInfo).price}}
+              ¥{{
+                  (
+                    Number(JSON.parse(scope.row.jsonInfo).num) *
+                    Number(JSON.parse(scope.row.jsonInfo).price)
+                  ).toFixed(2)
+                }}
             </template>
           </el-table-column>
         </el-table>

+ 6 - 6
src/views/components/his/storeDetails.vue

@@ -34,13 +34,13 @@
                   :preview-src-list="[item.licenseImages]">
               </el-image>
             </el-descriptions-item>
-<!--            <el-descriptions-item label="商品总数" >
+            <el-descriptions-item label="商品总数" >
                 <span v-if="item!=null">{{item.productCount}}</span>
-            </el-descriptions-item>-->
+            </el-descriptions-item>
             <el-descriptions-item label="状态" >
                <dict-tag :options="statusOptions" :value="item.status"/>
             </el-descriptions-item>
-<!--            <el-descriptions-item label="销量" >
+            <el-descriptions-item label="销量" >
                 <span v-if="item!=null">{{item.salesCount}}</span>
             </el-descriptions-item>
             <el-descriptions-item label="余额" >
@@ -48,13 +48,13 @@
             </el-descriptions-item>
             <el-descriptions-item label="累计金额" >
                 <span v-if="item!=null">{{item.totalMoney}}</span>
-            </el-descriptions-item>-->
+            </el-descriptions-item>
             <el-descriptions-item label="审核状态" >
                 <dict-tag :options="isAuditOptions" :value="item.isAudit"/>
             </el-descriptions-item>
-<!--            <el-descriptions-item label="登录帐号" >
+            <el-descriptions-item label="登录帐号" >
                 <span v-if="item!=null">{{item.account}}</span>
-            </el-descriptions-item>-->
+            </el-descriptions-item>
             <el-descriptions-item label="创建时间" >
                 <span v-if="item!=null">{{item.createTime}}</span>
             </el-descriptions-item>

+ 199 - 18
src/views/components/his/storeOrderDetails.vue

@@ -60,7 +60,7 @@
                  </div>
 
                <div class="operate-button-container" v-if="item.status>1">
-                   <el-button size="mini" @click="refund()" v-hasPermi="['his:storeOrder:afterSales']">申请退款</el-button>
+                   <el-button size="mini" @click="chooseRefund()" v-hasPermi="['his:storeOrder:afterSales']">申请退款</el-button>
                </div>
                <div class="operate-button-container" v-if="item.prescribeId!=null&&item.prescribeId!=''" >
                   <el-button size="mini" @click="getPrescribeOrder()" >处方单</el-button>
@@ -125,7 +125,7 @@
      <el-tooltip class="item" effect="dark" :content="showList ? '显示全部' : '隐藏'" placement="top" style="float: right;">
        <el-button size="mini" circle icon="el-icon-search" @click="showListD()" />
      </el-tooltip>
-  <el-table border v-if="showProd!=null" :data="showProd" size="small" style="width: 100%;margin-top: 20px" >
+     <el-table border v-if="showProd!=null" :data="showProd" size="small" style="width: 100%;margin-top: 20px" >
          <el-table-column label="商品图片" width="150" align="center">
            <template slot-scope="scope">
              <img :src="JSON.parse(scope.row.jsonInfo).image" style="height: 80px">
@@ -342,10 +342,25 @@
                           :key="dict.dictValue"
                           :label="dict.dictLabel"
                           :value="dict.dictValue"
-                          :disabled="dict.dictLabel == '待推送'"
+                          :disabled="dict.dictLabel == '待推送' || dict.dictLabel == '退款中' || dict.dictLabel == '退款成功'"
                         />
                       </el-select>
                    </el-form-item>
+                   <el-form-item label="实付金额" prop="payMoney">
+                    <el-input-number
+                      v-model="payMoney"
+                      :precision="2"
+                      :step="0.1"
+                      disabled   
+                    />
+                  </el-form-item>
+                  <el-form-item label="物流代收金额">
+                    <el-input-number v-model="payRemain" :precision="2" :step="0.1" :disabled="isUpdatePayRemain==0"/>
+                  </el-form-item>
+
+                  <el-form-item label="应付金额">
+                    <el-input-number v-model="payPrice" :precision="2" :step="0.1" disabled/>
+                  </el-form-item>
                    <el-form-item label="物流状态" prop="deliveryStatus" >
                    <el-select v-model="editForm.deliveryStatus" placeholder="请选择物流状态" clearable size="small" filterable>
                         <el-option
@@ -423,6 +438,70 @@
                 <prescribeDetails  ref="prescribeDetails" />
               </el-drawer>
 
+              <el-dialog
+                :title="refundDialog.title"
+                :visible.sync="refundDialog.open"
+                width="50%"
+                append-to-body
+                >
+                <el-table border v-if="refundShowProd!=null" :data="refundShowProd" ref="refundTable" size="small"  @selection-change="handleSelectionChange">
+                  <el-table-column type="selection" width="55" align="center" />
+                  
+                  <el-table-column label="商品编码" width="110" align="center">
+                    <template slot-scope="scope">
+                      <p>{{ JSON.parse(scope.row.jsonInfo).barCode }}</p>
+                    </template>
+                  </el-table-column>
+
+                  <el-table-column label="商品名称" align="center">
+                    <template slot-scope="scope">
+                      <p>{{ JSON.parse(scope.row.jsonInfo).productName }}</p>
+                    </template>
+                  </el-table-column>
+
+                  <el-table-column label="原单价" width="100" align="center">
+                    <template slot-scope="scope">
+                      <p>¥{{JSON.parse(scope.row.jsonInfo).price.toFixed(2)}}</p>
+                    </template>
+                  </el-table-column>
+
+                  <el-table-column label="退款单价" width="200" align="center">
+                    <template slot-scope="scope">
+                      <el-input-number 
+                        v-model="scope.row.money" 
+                        :precision="2" 
+                        :step="0.1" 
+                        :min="0"
+                        size="mini"
+                      />
+                    </template>
+                  </el-table-column>
+
+                  <el-table-column label="退款数量" width="200" align="center">
+                    <template slot-scope="scope">
+                      <el-input-number 
+                        v-model="scope.row.num" 
+                        :min="0" 
+                        :max="scope.row.originNum"   
+                        size="mini"
+                      />
+                    </template>
+                  </el-table-column>
+
+                </el-table>
+               
+                <div style="margin-top:10px;">
+                  合计退款金额:
+                  <span style="color:red; font-weight:bold;">
+                    ¥{{ refundForm.refundAmount ? refundForm.refundAmount.toFixed(2) : '0.00' }}
+                  </span>
+                </div>
+                <div slot="footer" class="dialog-footer">
+                  <el-button type="primary" @click="submitRefundForm">确 定</el-button>
+                </div>
+
+              </el-dialog>
+
 
 
 
@@ -443,6 +522,19 @@ import {getCitys} from "@/api/store/city";
     components: { inquiryOrderDetails,packageOrderDetails,prescribeDetails ,msgDetails},
     data() {
       return {
+        isUpdateRefund:0, //是否支持修改退款金额 默认0不支持
+        isUpdatePayRemain:0, //是否支持修改物流代收金额 默认0不支持
+        refundShowProd:[],//原退款明细
+        refundForm:{
+          refundAmount:0
+        },
+        selectedRows:[],
+        refundDialog:{
+          title:"申请退款",
+          open:false,
+        },
+        payRemain: 0,   // 物流代收金额,可改
+        payMoney: 0,    // 实收金额,固定
         expressDialog:{
           title:"物流信息",
           open:false,
@@ -451,7 +543,7 @@ import {getCitys} from "@/api/store/city";
           title:"修改物流单号",
           open:false,
         },
-		sourceOptions:[],
+		    sourceOptions:[],
         prescribeDialog:{
           title:"处方单",
           open:false,
@@ -531,6 +623,8 @@ import {getCitys} from "@/api/store/city";
           deliveryType:null,
           userPhone:null,
           remark:"",
+          payRemain:null,
+          payPrice:null
         },
         editDyRules:{
           deliverySn: [
@@ -613,7 +707,24 @@ import {getCitys} from "@/api/store/city";
             });
 
     },
+    computed: {
+       // 应收金额 = 实收金额 + 代收金额
+      payPrice() {
+        const v = (this.payMoney * 100 + this.payRemain * 100) / 100;
+        return Number(v.toFixed(2));
+      }
+    },
     methods: {
+      updateRefund(row) {
+        // 默认退款金额 = 数量 × 单价
+        row.refundAmount = (row.num * row.money).toFixed(2);
+      },
+      handleSelectionChange(val) {
+        this.refundForm.refundAmount = val
+          .reduce((sum, row) => sum + row.num * row.money, 0)
+          ;
+        this.selectedRows = val;
+      },
       getCitys() {
         return getCitys().then(res => {
           this.citys = res.data || [];
@@ -764,6 +875,8 @@ import {getCitys} from "@/api/store/city";
         const payload = {
           ...this.editForm,
           userAddress: this.buildFullAddress(),
+          payRemain :this.payRemain,
+          payPrice: this.payPrice,
         };
 
         updateStoreOrder(payload).then(response => {
@@ -793,7 +906,9 @@ import {getCitys} from "@/api/store/city";
       this.editForm.status = this.item.status != null ? this.item.status.toString() : "";
       this.editForm.deliveryType = this.item.deliveryType;
       this.editForm.deliveryStatus = this.item.deliveryStatus;
-
+      this.payMoney= this.item.payMoney;
+      this.payRemain = this.item.payRemain;
+      this.payPrice= this.item.payPrice;
       // 等城市数据加载后再解析地址
       const currentAddress = (this.item.userAddress || "").toString().trim();
       this.getCitys().then(() => {
@@ -926,7 +1041,71 @@ import {getCitys} from "@/api/store/city";
       moneyCancel(){
         this.money=null;
         this.moneyVisible=false;
-    },
+      },
+      chooseRefund(){
+        if(this.isUpdateRefund == 1){
+          this.refundShowProd = this.showProd.map(item => {
+            const info = JSON.parse(item.jsonInfo);
+            return {
+              ...item,
+              originNum: item.num, // 原始购买数量
+              num: item.num,       // 可编辑的退款数量
+              price: info.price,
+              money: 0.00,
+              // refundAmount: (item.num * info.price).toFixed(2),
+              refundAmount: 0,
+              jsonInfo: item.jsonInfo
+            }
+          })
+          this.refundForm.refundAmount = 0
+          this.refundDialog.open = true
+          // this.$nextTick(() => {
+          //   // 默认全选表格
+          //   this.$refs.refundTable.toggleAllSelection();
+          // });
+          this.$alert('请先设置退款单价和退款数量,再选择商品', '提示');
+        } else {
+          this.refund(); //正常退款
+        }
+        
+      },
+      submitRefundForm(){
+        if(this.refundForm.refundAmount<=0){
+          return this.$message("退款金额不能为0");
+        }
+        if(this.refundForm.refundAmount>this.item.payMoney){
+          return this.$message("退款金额不能大于实付金额" + this.item.payMoney + "元");
+        }
+        if(this.selectedRows.length==0){
+          return this.$message("请选择退款商品");
+        }
+        const refundList = this.selectedRows.map(row => ({
+          itemId: row.itemId,
+          num: row.num,
+          money:row.money
+        }))
+        const param = {
+          orderId:this.item.orderId,
+          refundList:refundList,
+          refundAmount:this.refundForm.refundAmount
+        }
+        console.log("申请退款数据", param);
+        this.$confirm('是否确认申请退款?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return afterSales(param);
+        }).then(() => {
+          this.msgSuccess("操作成功");
+          getOrder(this.item.orderId).then(response => {
+              this.item = response.data;
+              this.getlogList(this.item.orderId);
+              this.$parent.$parent.getList();
+              this.refundDialog.open = false
+          });
+        }).catch(function() {});
+      },
       refund(){
         var that=this;
         this.$confirm('是否确认申请退款?', "警告", {
@@ -1056,18 +1235,20 @@ import {getCitys} from "@/api/store/city";
         this.storeName=storeName;
         this.item=null;
         this.tuiMoneyLogs=null;
-          getOrder(orderId).then(response => {
-              this.item = response.data;
-              this.tuiMoneyLogs = response.tuiMoneyLogs;
-              this.getlistOrderitem(orderId);
-              this.getlogList(orderId);
-              this.getPayment(orderId);
-              this.msgForm.userId=response.data.userId;
-              this.msgForm.followDoctorId=response.data.followDoctorId;
-              if(this.item.orderType==2){
-                this.getCount(this.item.prescribeId);
-              }
-          });
+        getOrder(orderId).then(response => {
+            this.item = response.data;
+            this.tuiMoneyLogs = response.tuiMoneyLogs;
+            this.getlistOrderitem(orderId);
+            this.getlogList(orderId);
+            this.getPayment(orderId);
+            this.msgForm.userId=response.data.userId;
+            this.msgForm.followDoctorId=response.data.followDoctorId;
+            if(this.item.orderType==2){
+              this.getCount(this.item.prescribeId);
+            }
+            this.isUpdateRefund = response.isUpdateRefund;
+            this.isUpdatePayRemain = response.isUpdatePayRemain
+        });
       },
       getCount(id){
         getPrescribe(id).then(response => {

+ 14 - 2
src/views/components/his/userDetails.vue

@@ -133,6 +133,15 @@
  </div>
     <userInquiryOrderDetails  ref="InquiryDetails" />
    </div>
+
+    <!-- 积分记录 -->
+    <div class="contentx" v-if="item!=null" >
+      <div class="desct">
+            用户积分记录
+      </div>
+          <userIntegralDetails  ref="userIntegralDetail" />
+    </div>
+
  </div>
 </template>
 
@@ -146,10 +155,11 @@ import userStorerDetails from "../his/userStorerDetails.vue";
 import userPatietDetails from "../his/userPatietDetails.vue";
 import userInquiryOrderDetails from "../his/userInquiryOrderDetails.vue";
 import userAddDetails from "../his/userAddDetails.vue";
+    import userIntegralDetails from "../his/userIntegralDetails.vue";
   export default {
     name: "storedet",
     props:["data"],
-     components: { userStorerDetails ,userInquiryOrderDetails,userPatietDetails,userAddDetails},
+     components: { userStorerDetails ,userInquiryOrderDetails,userPatietDetails,userAddDetails,userIntegralDetails},
     data() {
       return {
         patientInfo: process.env.VUE_APP_PATIENT_INFO,
@@ -232,7 +242,9 @@ import userAddDetails from "../his/userAddDetails.vue";
               setTimeout(() => {
                    this.$refs.userAddDetail.getAddList(orderId);
               }, 1);
-
+              setTimeout(() => {
+                  this.$refs.userIntegralDetail.getIntegralLogs(orderId);
+              }, 1);
           });
           this.patient=null;
           getPatientByUserId(orderId).then(response => {

+ 111 - 0
src/views/components/his/userIntegralDetails.vue

@@ -0,0 +1,111 @@
+<!-- UserIntegralLogs.vue -->
+<template>
+  <div class="integral-logs-container">
+    <el-table 
+      v-loading="loading" 
+      border 
+      :data="userIntegralLogsList" 
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column label="用户id" align="center" prop="userId" />
+      <el-table-column label="用户昵称" align="center" prop="nickName" />
+      <el-table-column label="用户电话" align="center" prop="phone" />
+      <el-table-column label="类别" align="center" prop="logType">
+        <template slot-scope="scope">
+          <dict-tag :options="intefralLogTypeOptions" :value="scope.row.logType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="积分" align="center" prop="integral" />
+      <el-table-column label="积分余额" align="center" prop="balance" />
+      <el-table-column label="订单关联id" align="center" prop="businessId" />
+      <el-table-column label="时间" align="center" prop="createTime" />
+    </el-table>
+    
+    <!-- 分页组件 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listUserIntegralLogs} from "@/api/his/userIntegralLogs";
+
+export default {
+  name: 'UserIntegralLogs',
+  props: {
+    fsUserId: {
+      type: [String, Number],
+      required: false
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      userIntegralLogsList: [],
+      total: 0,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: this.fsUserId
+      },
+      intefralLogTypeOptions: [],
+      selections: []
+    }
+  },
+  watch: {
+    fsUserId: {
+      handler(newVal) {
+        this.queryParams.userId = newVal;
+        this.getList();
+      },
+      immediate: true
+    }
+  },
+
+  created() {
+    this.getList();
+    this.getDictOptions();
+  },
+  methods: {
+    // 获取积分日志列表
+    getList() {
+
+      if (!this.queryParams.userId) return;
+      
+      this.loading = true;
+      listUserIntegralLogs(this.queryParams).then(response => {
+        this.userIntegralLogsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    getIntegralLogs(fsUserId){
+        this.queryParams.userId=fsUserId;
+        this.getList();
+    },
+    // 获取字典选项
+    getDictOptions() {
+      // 获取积分日志类型字典
+        this.getDicts("sys_integral_log_type").then(response => {
+            this.intefralLogTypeOptions = response.data;
+        });
+    },
+    
+    // 处理选择变化
+    handleSelectionChange(selection) {
+      this.selections = selection;
+    }
+  }
+}
+</script>
+
+<style scoped>
+.integral-logs-container {
+  padding: 20px;
+}
+</style>

+ 10 - 0
src/views/course/courseAnswerlogs/index.vue

@@ -1,6 +1,16 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+      <el-form-item label="销售公司" prop="companyId">
+        <el-select filterable v-model="queryParams.companyId" clearable placeholder="请选择公司名" 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 label="客户电话" prop="phone">
         <el-input
           v-model="queryParams.phone"

+ 12 - 2
src/views/course/courseFinishTempParent/index.vue

@@ -1,6 +1,16 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="销售公司" prop="companyId">
+        <el-select filterable v-model="queryParams.companyId" clearable placeholder="请选择公司名" size="small">
+          <el-option
+            v-for="item in companyList"
+            :key="item.companyId"
+            :label="item.companyName"
+            :value="item.companyId"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item label="名称" prop="name">
         <el-input
           v-model="queryParams.name"
@@ -434,6 +444,7 @@ export default {
         pageSize: 10,
         name: null,
         courseId: null,
+        companyId: null
       },
       // 表单参数
       form: {},
@@ -496,7 +507,7 @@ export default {
       this.form = {
         id: null,
         status: 1,
-        companyId: 1,
+        companyId: null,
         name: null,
         setting: [],
         chatSetting: [],
@@ -508,7 +519,6 @@ export default {
         companyUserIds: null,
         remark: null
       };
-      this.resetForm("form");
     },
     /** 搜索按钮操作 */
     handleQuery() {

+ 32 - 0
src/views/course/coursePlaySourceConfig/index.vue

@@ -137,6 +137,11 @@
           <dict-tag  :options="typesOptions" :value="scope.row.type"/>
         </template>
       </el-table-column>
+      <el-table-column label="互医/商城小程序" align="center" prop="isMall" width="80px">
+        <template slot-scope="scope">
+          <el-tag prop="isMall" v-for="(item, index) in isMallOptions" v-if="scope.row.isMall==item.dictValue">{{item.dictLabel}}</el-tag>
+        </template>
+      </el-table-column>
       <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">
@@ -200,6 +205,21 @@
             />
           </el-select>
         </el-form-item>
+        <el-form-item label="是否是互医/商城小程序" prop="isMall">
+          <el-select
+            v-model="form.isMall"
+            style="width: 220px"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in isMallOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item label="图标" prop="img">
           <image-upload v-model="form.img" :file-type='["png", "jpg", "jpeg"]' :limit="1"/>
         </el-form-item>
@@ -276,6 +296,16 @@ export default {
       list: [],
       total: 0,
       typesOptions: [],
+      isMallOptions:[
+        {
+          dictLabel: "是",
+          dictValue: 1
+        },
+        {
+          dictLabel: "否",
+          dictValue: 0
+        }
+      ],
       title: null,
       open: false,
       form: {},
@@ -419,6 +449,7 @@ export default {
     handleAdd() {
       this.reset()
       this.open = true
+        this.form.isMall = 0;
       this.title = "添加小程序配置"
     },
     handleUpdate(row) {
@@ -429,6 +460,7 @@ export default {
           ...response.data,
           type: response.data.type.toString()
         }
+        this.searchCompanies("");
         this.open = true
         this.title = "修改小程序配置"
       })

+ 3 - 5
src/views/course/courseTrafficLog/index.vue

@@ -52,6 +52,7 @@
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+        <el-button type="warning" plain icon="el-icon-download" size="mini" :loading="exportLoading" @click="handleExport" >导出</el-button>
       </el-form-item>
     </el-form>
 
@@ -211,10 +212,7 @@ export default {
       this.getList();
     },
     formatTrafficData(traffic) {
-      if (traffic < 1024) return `${traffic} B`;
-      if (traffic < 1024 ** 2) return `${(traffic / 1024).toFixed(2)} KB`;
-      if (traffic < 1024 ** 3) return `${(traffic / 1024 ** 2).toFixed(2)} MB`;
-      return `${(traffic / 1024 ** 3).toFixed(2)} GB`;
+      return `${(traffic / (1024 ** 3)).toFixed(4)} GB`;
     },
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.logId);
@@ -228,7 +226,7 @@ export default {
       }).finally(() => {
         this.exportLoading = false;
       });
-    }
+    },
   }
 };
 </script>

+ 2 - 0
src/views/course/courseUserStatistics/qw/index.vue

@@ -38,6 +38,8 @@
             <el-table-column label="进线时间" align="center" prop="createTime"/>
             <!-- 进线数 -->
             <el-table-column label="进线数" align="center" prop="line" />
+            <!-- 注册数 -->
+            <el-table-column label="注册数" align="center" prop="regNum" />
 
             <!-- 先导课上线 -->
             <el-table-column label="先导课上线" align="center" prop="firstOnline">

+ 2 - 1
src/views/course/courseUserStatistics/qw/my.vue

@@ -37,7 +37,8 @@
             <el-table-column label="进线时间" align="center" prop="createTime"/>
             <!-- 进线数 -->
             <el-table-column label="进线数" align="center" prop="line" />
-
+            <!-- 注册数 -->
+            <el-table-column label="注册数" align="center" prop="regNum" />
             <!-- 先导课上线 -->
             <el-table-column label="先导课上线" align="center" prop="firstOnline">
                 <template slot-scope="scope">

+ 2 - 1
src/views/course/courseUserStatistics/qw/myStatistics.vue

@@ -27,7 +27,8 @@
             <el-table-column label="进线时间" align="center" prop="createTime"/>
             <!-- 进线数 -->
             <el-table-column label="进线数" align="center" prop="line" />
-
+            <!-- 注册数 -->
+            <el-table-column label="注册数" align="center" prop="regNum" />
             <!-- 先导课上线 -->
             <el-table-column label="先导上线" align="center" prop="firstOnline">
                 <template slot-scope="scope">

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

@@ -37,7 +37,8 @@
             <el-table-column label="进线时间" align="center" prop="createTime"/>
             <!-- 进线数 -->
             <el-table-column label="进线数" align="center" prop="line" />
-
+            <!-- 注册数 -->
+            <el-table-column label="注册数" align="center" prop="regNum" />
             <!-- 先导课上线 -->
             <el-table-column label="先导上线" align="center" prop="firstOnline">
                 <template slot-scope="scope">
@@ -461,7 +462,7 @@
 </template>
 
 <script>
-import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,statisticsList,qwWatchLogStatisticsList,qwWatchLogAllStatisticsList } from "@/api/course/qw/courseWatchLog";
+import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,statisticsList,qwWatchLogStatisticsList,qwWatchLogAllStatisticsList } from "@/api/course/courseWatchLog";
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getCompanyList} from "@/api/company/company";
 export default {

+ 1 - 84
src/views/course/courseUserStatistics/statistics.vue

@@ -61,10 +61,7 @@
       </el-form-item>
     </el-form>
 
-    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary
-              :summary-method="getSummaries"
-              max-height="500"
-              highlight-current-row>
+    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary height="600">
       <el-table-column type="selection" width="55" align="center" />
 <!--        <el-table-column label="会员名称" align="center" prop="fsUserName" />-->
       <el-table-column label="销售名称" align="center" prop="qwUserName" />
@@ -580,74 +577,6 @@ export default {
     })
   },
   methods: {
-    // 合计
-    getSummaries(param) {
-      const { columns, data } = param;
-      const sums = [];
-
-      columns.forEach((column, index) => {
-        if (index === 0) {
-          sums[index] = '合计';
-          return;
-        }
-
-        // 获取列的真实属性名
-        const prop = column.property;
-
-        // 定义需要合计的字段
-        const summaryFields = [
-          'line', 'firstOnline', 'firstOver',
-          'd1Online', 'd1Over', 'd2Online', 'd2Over',
-          'd3Online', 'd3Over', 'd4Online', 'd4Over',
-          'd5Online', 'd5Over', 'd6Online', 'd6Over',
-          'd7Online', 'd7Over', 'd8Online', 'd8Over',
-          'd9Online', 'd9Over', 'd10Online', 'd10Over',
-          'd11Online', 'd11Over', 'd12Online', 'd12Over',
-          'd13Online', 'd13Over', 'd14Online', 'd14Over',
-          'd15Online', 'd15Over', 'd16Online', 'd16Over',
-          'd17Online', 'd17Over', 'd18Online', 'd18Over',
-          'd19Online', 'd19Over', 'd20Online', 'd20Over',
-          'd21Online', 'd21Over', 'd22Online', 'd22Over',
-          'd23Online', 'd23Over', 'd24Online', 'd24Over',
-          'd25Online', 'd25Over', 'd26Online', 'd26Over',
-          'd27Online', 'd27Over', 'd28Online', 'd28Over',
-          'd29Online', 'd29Over', 'd30Online', 'd30Over'
-        ];
-
-        if (prop && summaryFields.includes(prop)) {
-          const values = data.map(item => {
-            const value = Number(item[prop]);
-            return isNaN(value) ? 0 : value;
-          });
-          const sum = values.reduce((prev, curr) => prev + curr, 0);
-
-          // 如果是line字段,直接显示合计值
-          if (prop === 'line') {
-            sums[index] = sum;
-          } else if (prop.endsWith('Online') || prop.endsWith('Over')) {
-            // 对于上线和完课字段,显示合计值和百分比
-            const lineValues = data.map(item => {
-              const value = Number(item.line);
-              return isNaN(value) ? 0 : value;
-            });
-            const totalLine = lineValues.reduce((prev, curr) => prev + curr, 0);
-
-            if (totalLine > 0) {
-              const percentage = ((sum / totalLine) * 100).toFixed(2);
-              sums[index] = `${sum} (${percentage}%)`;
-            } else {
-              sums[index] = `${sum} (0.00%)`;
-            }
-          } else {
-            sums[index] = sum;
-          }
-        } else {
-          sums[index] = '';
-        }
-      });
-
-      return sums;
-    },
     handleSeller(){
       if(this.queryParams.companyId != null) {
         getUserList(this.queryParams.companyId).then(res=>{
@@ -691,7 +620,6 @@ export default {
       qwWatchLogAllStatisticsList(this.queryParams).then(response => {
         this.courseWatchLogList = response.rows;
         this.total = response.total;
-        console.log('数据列表:', this.courseWatchLogList);
       }).finally(()=>{
         this.loading = false;
       })
@@ -822,14 +750,3 @@ export default {
   }
 };
 </script>
-
-<style scoped>
-::v-deep .el-table__footer td {
-  font-size: 12px;
-  color: #606266;
-}
-
-::v-deep .el-table__footer td .cell {
-  font-weight: 500;
-}
-</style>

+ 7 - 7
src/views/course/courseWatchComment/index.vue

@@ -91,13 +91,13 @@
       <el-table-column label="评论内容" align="center" prop="content" />
       <el-table-column label="所属课程" align="center" prop="courseName" />
       <el-table-column label="所属小节" align="center" prop="title" />
-      <el-table-column label="弹幕状态" align="center" prop="status">
-        <template slot-scope="scope">
-          <el-tag :type="getStatusTagType(scope.row.status)">
-            {{ formatBarrageStatus(scope.row.status) }}
-          </el-tag>
-        </template>
-      </el-table-column>
+<!--      <el-table-column label="弹幕状态" align="center" prop="status">-->
+<!--        <template slot-scope="scope">-->
+<!--          <el-tag :type="getStatusTagType(scope.row.status)">-->
+<!--            {{ formatBarrageStatus(scope.row.status) }}-->
+<!--          </el-tag>-->
+<!--        </template>-->
+<!--      </el-table-column>-->
       <el-table-column label="评论时间" align="center" prop="createTime" width="160px"/>
       <!--      <el-table-column label="是否是撤回的消息,1-是,0-否" align="center" prop="isRevoke" />-->
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">

+ 165 - 20
src/views/course/courseWatchLog/index.vue

@@ -1,6 +1,16 @@
 <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 v-model="queryParams.companyId" clearable placeholder="请选择公司名" size="small">
+          <el-option
+            v-for="item in companyList"
+            :key="item.companyId"
+            :label="item.companyName"
+            :value="item.companyId"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item label="课程" prop="courseId">
         <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" @change="courseChange(queryParams.courseId)">
           <el-option
@@ -34,9 +44,23 @@
           @change="handleScheduleTimeChange">
         </el-date-picker>
       </el-form-item>
+<!--      <el-form-item label="创建时间" prop="createTime">-->
+<!--        <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"-->
+<!--                        type="daterange"-->
+<!--                        :required="true"-->
+<!--                        range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="createChange"></el-date-picker>-->
+<!--      </el-form-item>-->
       <el-form-item label="创建时间" prop="createTime">
-        <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange"
-                        range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="createChange"></el-date-picker>
+        <el-date-picker
+          v-model="createTime"
+          type="datetimerange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          @change="createChange"
+          :default-time="['00:00:00', '23:59:59']"
+        />
       </el-form-item>
       <el-form-item label="最新更新时间" prop="updateTime">
         <el-date-picker v-model="updateTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange"
@@ -138,7 +162,7 @@
 
 <script>
 import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog } from "@/api/course/courseWatchLog";
-import {allList}from "@/api/company/company";
+import { allList, getCompanyList } from '@/api/company/company'
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getUserList} from "@/api/company/companyUser";
 import {getFsUserList} from "@/api/users/user";
@@ -153,6 +177,7 @@ export default {
       courseLists:[],
       videoList:[],
       logTypeOptions:[],
+      companyList: [],
       queryUserLoading: false,
       // 遮罩层
       loading: true,
@@ -212,7 +237,11 @@ export default {
     courseList().then(response => {
       this.courseLists = response.list;
     });
-    this.getList();
+
+    getCompanyList().then(response => {
+      this.companyList = response.data;
+    });
+
     this.getDicts("sys_course_watch_log_type").then(response => {
       this.logTypeOptions = response.data;
     });
@@ -222,6 +251,14 @@ export default {
       this.userSourceTypeOptions = response.data;
     })
 
+    // 设置默认当天时间 xgb 防止频繁查询大量数据
+    this.setToday();
+
+    this.getList();
+
+    this.loading = false;
+
+
   },
   computed: {
     sourceTypeModel: {
@@ -234,6 +271,42 @@ export default {
     }
   },
   methods: {
+
+    setToday(){
+      const today = new Date();
+      const todayStart = new Date(today);
+      todayStart.setHours(0, 0, 0, 0);
+      const todayEnd = new Date(today);
+      todayEnd.setHours(23, 59, 59, 999);
+
+      this.createTime = [this.formatDate(todayStart), this.formatDate(todayEnd)];
+      this.queryParams.sTime = this.formatDate(todayStart);
+      this.queryParams.eTime = this.formatDate(todayEnd);
+    },
+    formatDate(date) {
+      if (!date) return ''
+
+      // 确保 date 是 Date 对象
+      let dateObj = date
+      if (typeof date === 'string') {
+        dateObj = new Date(date)
+      }
+
+      // 如果转换失败,返回空字符串
+      if (!(dateObj instanceof Date) || isNaN(dateObj.getTime())) {
+        return ''
+      }
+
+      // 使用更安全的格式化方法
+      const year = dateObj.getFullYear()
+      const month = String(dateObj.getMonth() + 1).padStart(2, '0')
+      const day = String(dateObj.getDate()).padStart(2, '0')
+      const hours = String(dateObj.getHours()).padStart(2, '0')
+      const minutes = String(dateObj.getMinutes()).padStart(2, '0')
+      const seconds = String(dateObj.getSeconds()).padStart(2, '0')
+
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+    },
     handleClear(){
       this.queryUserLoading = false;
       this.fsUserList = [];
@@ -272,21 +345,58 @@ export default {
         this.videoList=response.list
       });
     },
-    createChange() {
-      if (this.createTime != null) {
-        this.queryParams.sTime = this.createTime[0];
-        this.queryParams.eTime = this.createTime[1];
+    checkDateRangeLimit(dateRange) {
+      if (dateRange && dateRange.length >= 2) {
+        const startDate = new Date(dateRange[0]);
+        const endDate = new Date(dateRange[1]);
+
+        // 设置时间为当天开始,避免时间部分影响计算
+        startDate.setHours(0, 0, 0, 0);
+        endDate.setHours(0, 0, 0, 0);
+
+        const timeDiff = Math.abs(endDate - startDate);
+        const diffDays = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
+
+        if (diffDays > 31) { // maxDays-1 因为包含起始日
+          this.$message.warning('时间区间不能超过一个月');
+          return false;
+        }
+      }
+      return true;
+    },
+    createChange(createTime) {
+      if (createTime && createTime.length >= 2) {
+        if(!this.checkDateRangeLimit(createTime)){
+          this.createTime = null;
+          this.queryParams.sTime=null;
+          this.queryParams.eTime=null;
+          return;
+        }
+
+        // this.createTimeText = this.formatDateRange(createTime);
+        this.queryParams.sTime = this.formatDate(createTime[0]) || null;
+        this.queryParams.eTime = this.formatDate(createTime[1]) || null;
       } else {
+        this.createTimeText = '';
         this.queryParams.sTime = null;
         this.queryParams.eTime = null;
       }
     },
 
-    updateChange(){
-      if (this.updateTime != null) {
-        this.queryParams.upSTime = this.updateTime[0];
-        this.queryParams.upETime = this.updateTime[1];
+    updateChange(updateTime){
+      if (updateTime && updateTime.length >= 2) {
+        if(!this.checkDateRangeLimit(updateTime)){
+          this.updateTime = null;
+          this.queryParams.upSTime=null;
+          this.queryParams.upETime=null;
+          return;
+        }
+
+        // this.updateTime = this.formatDateRange(updateTime);
+        this.queryParams.upSTime = updateTime[0] || null;
+        this.queryParams.upETime = updateTime[1] || null;
       } else {
+        this.updateTime = [];
         this.queryParams.upSTime = null;
         this.queryParams.upETime = null;
       }
@@ -302,6 +412,14 @@ export default {
     },
     /** 查询短链课程看课记录列表 */
     getList() {
+
+      // xgb 看课数据量太大必须限制时间if (this.isEmptyArray(this.createTime) &&
+      if (this.isEmptyArray(this.createTime) &&
+        this.isEmptyArray(this.updateTime) &&
+        this.isEmptyArray(this.scheduleTime)) {
+        this.$message.warning('请选择创建时间或营期时间或最新更新时间');
+        return;
+      }
       this.loading = true;
       if(this.queryParams.logType == "10"){
         this.queryParams.logType = null;
@@ -311,7 +429,10 @@ export default {
         this.courseWatchLogList = response.rows;
         this.total = response.total;
         this.loading = false;
-      });
+      }).catch(() => {
+          this.loading = false;
+        }
+      );
     },
     // 取消按钮
     cancel() {
@@ -348,17 +469,21 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
-      this.createTime = null;
+      // this.createTime = null;
       this.scheduleTime = null;
-      this.queryParams.sTime = null;
-      this.queryParams.eTime = null;
+      // this.queryParams.sTime = null;
+      // this.queryParams.eTime = null;
       this.queryParams.upSTime = null;
       this.queryParams.upETime = null;
       this.queryParams.scheduleStartTime = null;
       this.queryParams.scheduleEndTime = null;
       this.scheduleTime=null;
       this.updateTime=null;
+      // 重置时间当天
+      this.setToday();
+
       this.handleQuery();
+
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
@@ -416,8 +541,19 @@ export default {
           this.msgSuccess("删除成功");
         }).catch(() => {});
     },
+    // 添加辅助方法
+    isEmptyArray(arr) {
+      return !arr || arr.length === 0;
+    },
     /** 导出按钮操作 */
     handleExport() {
+      // xgb 看课数据量太大必须限制时间
+      if (this.isEmptyArray(this.createTime) &&
+        this.isEmptyArray(this.updateTime) &&
+        this.isEmptyArray(this.scheduleTime)) {
+        this.$message.warning('请选择创建时间或营期时间或最新更新时间');
+        return;
+      }
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
           confirmButtonText: "确定",
@@ -431,11 +567,20 @@ export default {
           this.exportLoading = false;
         }).catch(() => {});
     },
-    handleScheduleTimeChange(val) {
-      if (val) {
-        this.queryParams.scheduleStartTime = val[0];
-        this.queryParams.scheduleEndTime = val[1];
+    handleScheduleTimeChange(scheduleTime) {
+      if (scheduleTime && scheduleTime.length >= 2) {
+        if(!this.checkDateRangeLimit(scheduleTime)){
+          this.scheduleTime = null;
+          this.queryParams.scheduleStartTime=null;
+          this.queryParams.scheduleStartTime=null;
+          return;
+        }
+
+        // this.scheduleTime = this.formatDateRange(scheduleTime);
+        this.queryParams.scheduleStartTime = scheduleTime[0] || null;
+        this.queryParams.scheduleEndTime = scheduleTime[1] || null;
       } else {
+        this.scheduleTime = [];
         this.queryParams.scheduleStartTime = null;
         this.queryParams.scheduleEndTime = null;
       }

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

@@ -60,8 +60,11 @@
       <el-table-column label="看课中" align="center" prop="type1" />
       <el-table-column label="已完课" align="center" prop="type2" />
       <el-table-column label="看课中断" align="center" prop="type4" />
-
-
+      <el-table-column label="注册用户待看课数" align="center" prop="isUserWaitNumber" />
+      <el-table-column label="未注册用户待看课数" align="center" prop="noUserWaitNumber" />
+      <el-table-column label="上线率" align="center" prop="onLineRate" />
+      <el-table-column label="完课率" align="center" prop="finishedRate" />
+      <el-table-column label="消耗红包金额" align="center" prop="redAmount" />
     </el-table>
 
     <pagination

+ 299 - 0
src/views/course/courseWatchLog/qw/statisticsCompany.vue

@@ -0,0 +1,299 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="公司名" prop="companyId">
+        <el-select filterable style="width: 220px" 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 label="课程" prop="courseId">
+        <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" @change="courseChange(queryParams.courseId)">
+          <el-option
+            v-for="dict in courseLists"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="小节" prop="videoId">
+        <el-select filterable  v-model="queryParams.videoId" placeholder="请选择小节"  clearable size="small">
+          <el-option
+            v-for="dict in videoList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" 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>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table border v-loading="loading" :data="courseWatchLogList" show-summary>
+      <el-table-column label="公司名称" align="center" prop="companyName" />
+      <el-table-column label="发课时间" align="center" prop="createTime"/>
+      <el-table-column label="待看课" align="center" prop="type3" />
+      <el-table-column label="看课中" align="center" prop="type1" />
+      <el-table-column label="已完课" align="center" prop="type2" />
+      <el-table-column label="看课中断" align="center" prop="type4" />
+    </el-table>
+  </div>
+</template>
+
+<script>
+import {
+  listCourseWatchLog,
+  getCourseWatchLog,
+  delCourseWatchLog,
+  addCourseWatchLog,
+  updateCourseWatchLog,
+  exportCourseWatchLog,
+  statisticsList,
+  statisticsListByCompany
+} from '@/api/course/qw/courseWatchLog'
+import { courseList,videoList } from '@/api/course/courseRedPacketLog'
+import {getCompanyList} from "@/api/company/company";
+export default {
+  name: "CourseWatchLog",
+  data() {
+    return {
+      companys:[],
+      activeName:"00",
+      createTime:null,
+      courseLists:[],
+      videoList:[],
+      logTypeOptions:[],
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 短链课程看课记录表格数据
+      courseWatchLogList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        nickName: null,
+        videoId: null,
+        logType: null,
+        qwExternalContactId: null,
+        duration: null,
+        qwUserId: null,
+        companyUserId: null,
+        companyId: null,
+        courseId: null,
+        sTime:null,
+        eTime:null,
+        scheduleStartTime: null,
+        scheduleEndTime: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      scheduleTime: null,
+    };
+  },
+  created() {
+    getCompanyList().then(response => {
+      this.companys = response.data;
+      if(this.companys!=null&&this.companys.length>0){
+        this.companyId=this.companys[0].companyId;
+        this.getTreeselect();
+      }
+    });
+    courseList().then(response => {
+      this.courseLists = response.list;
+    });
+    this.getList();
+    this.getDicts("sys_course_watch_log_type").then(response => {
+      this.logTypeOptions = response.data;
+    });
+  },
+  methods: {
+    courseChange(row){
+      this.queryParams.videoId=null;
+      if(row === ''){
+        this.videoList=[];
+        return
+      }
+      videoList(row).then(response => {
+        this.videoList=response.list
+      });
+    },
+    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;
+      }
+    },
+    handleClickX(tab,event){
+      this.activeName=tab.name;
+      if(tab.name=="00"){
+        this.queryParams.logType=null;
+      }else{
+        this.queryParams.logType=tab.name;
+      }
+      this.getList()
+    },
+    /** 查询短链课程看课记录列表 */
+    getList() {
+      this.loading = true;
+      statisticsListByCompany(this.queryParams).then(response => {
+        this.courseWatchLogList = response.rows;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        logId: null,
+        userId: null,
+        videoId: null,
+        logType: null,
+        createTime: null,
+        updateTime: null,
+        qwExternalContactId: null,
+        duration: null,
+        qwUserId: null,
+        companyUserId: null,
+        companyId: null,
+        courseId: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.createTime = null;
+      this.scheduleTime = null;
+      this.queryParams.sTime = null;
+      this.queryParams.eTime = null;
+      this.queryParams.scheduleStartTime = null;
+      this.queryParams.scheduleEndTime = null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.logId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加短链课程看课记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const logId = row.logId || this.ids
+      getCourseWatchLog(logId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改短链课程看课记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.logId != null) {
+            updateCourseWatchLog(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCourseWatchLog(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const logIds = row.logId || this.ids;
+      this.$confirm('是否确认删除短链课程看课记录编号为"' + logIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delCourseWatchLog(logIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportCourseWatchLog(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    handleScheduleTimeChange(val) {
+      if (val) {
+        this.queryParams.scheduleStartTime = val[0];
+        this.queryParams.scheduleEndTime = val[1];
+      } else {
+        this.queryParams.scheduleStartTime = null;
+        this.queryParams.scheduleEndTime = null;
+      }
+    },
+  }
+};
+</script>

+ 65 - 20
src/views/course/courseWatchLog/statistics.vue

@@ -75,7 +75,14 @@
       </el-form-item>
     </el-form>
 
-    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary>
+    <el-table
+      border
+      v-loading="loading"
+      :data="courseWatchLogList"
+      @selection-change="handleSelectionChange"
+      show-summary
+      :summary-method="getSummaries"
+    >
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="用户" align="center" prop="userName" />
       <el-table-column label="对应销售" align="center" prop="companyUserName" />
@@ -185,6 +192,44 @@ export default {
 
   },
   methods: {
+    /** 自定义合计方法 */
+    getSummaries(param) {
+      const { columns, data } = param;
+      const sums = [];
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '合计';
+          return;
+        }
+
+        // 排除不需要合计的列(小节名称和其他文本列)
+        const excludeColumns = ['userName', 'companyUserName', 'createTime', 'projectName', 'courseName', 'videoName'];
+        const prop = column.property;
+
+        if (excludeColumns.includes(prop)) {
+          sums[index] = '--';
+          return;
+        }
+
+        // 对数值列进行合计
+        const values = data.map(item => Number(item[prop]));
+        if (!values.every(value => isNaN(value))) {
+          sums[index] = values.reduce((prev, curr) => {
+            const value = Number(curr);
+            if (!isNaN(value)) {
+              return prev + curr;
+            } else {
+              return prev;
+            }
+          }, 0);
+        } else {
+          sums[index] = '--';
+        }
+      });
+
+      return sums;
+    },
+
     handleSeller(){
       console.log(this.queryParams.companyId)
       if(this.queryParams.companyId != null) {
@@ -351,30 +396,30 @@ export default {
     handleDelete(row) {
       const logIds = row.logId || this.ids;
       this.$confirm('是否确认删除短链课程看课记录编号为"' + logIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delCourseWatchLog(logIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delCourseWatchLog(logIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportCourseWatchLog(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportCourseWatchLog(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     },
     handleScheduleTimeChange(val) {
       if (val) {

+ 3 - 3
src/views/course/courseWatchLog/watchLogStatistics.vue

@@ -61,7 +61,7 @@
 import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,watchLogStatistics,watchLogStatisticsExport } from "@/api/course/courseWatchLog";
 import {allList}from "@/api/company/company";
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
-import {getUserList} from "@/api/company/companyUser";
+// import {getUserList} from "@/api/company/companyUser";
 export default {
   name: "CourseWatchLog",
   data() {
@@ -131,11 +131,11 @@ export default {
     this.getDicts("sys_course_watch_log_type").then(response => {
       this.logTypeOptions = response.data;
     });
-    getUserList().then(res=>{
+/*    getUserList().then(res=>{
       if(res.code === 200) {
         this.companyUserList = res.data
       }
-    })
+    })*/
   },
   methods: {
     courseChange(row){

+ 253 - 0
src/views/course/statistics/index.vue

@@ -0,0 +1,253 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+
+      <el-form-item label="项目" prop="projectId">
+        <el-select filterable v-model="queryParams.projectId" placeholder="请选择项目" clearable size="small">
+          <el-option
+            v-for="dict in projectLists"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="parseInt(dict.dictValue)"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="所属公司" prop="companyName">
+        <el-select
+          v-model="queryParams.companyId"
+          placeholder="请选择所属公司"
+          clearable
+          filterable
+          size="small"
+        >
+          <el-option
+            v-for="item in companyQueryOptions"
+            :key="item.companyId"
+            :label="item.companyName"
+            :value="item.companyId">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="统计日期" prop="createDate">
+        <el-date-picker
+          v-model="dateRange"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+          :picker-options="pickerOptions"
+          @change="handleDateChange"
+          clearable
+          size="small">
+        </el-date-picker>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['course:statistics:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="statisticsList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="统计日期" align="center" prop="createDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="公司名称" align="center" prop="companyName" />
+      <el-table-column label="会员数量" align="center" prop="userCount" />
+      <el-table-column label="会员黑名单数量" align="center" prop="userBlacklistCount" />
+      <el-table-column label="观看次数" align="center" prop="watchCount" />
+      <el-table-column label="完播次数" align="center" prop="completeWatchCount" />
+      <el-table-column label="完播率" align="center" prop="completeRate" />
+      <el-table-column label="答题人次" align="center" prop="answerCount" />
+      <el-table-column label="正确人次" align="center" prop="correctCount" />
+      <el-table-column label="正确率" align="center" prop="correctRate" />
+      <el-table-column label="领取次数" align="center" prop="receiveCount" />
+      <el-table-column label="领取金额" align="center" prop="receiveAmount" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listStatistics, getStatistics, exportStatistics } from "@/api/course/statistics";
+import {getCompanyList, getCompanyUserList} from "@/api/company/companyUser";
+
+export default {
+  name: "Statistics",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 会员每日看课统计表格数据
+      statisticsList: [],
+
+      // 日期范围选择器值
+      dateRange: [],
+
+      // 日期选择器配置
+      pickerOptions: {
+        onPick: ({ maxDate, minDate }) => {
+          this.pickerMinDate = minDate.getTime();
+          if (maxDate) {
+            this.pickerMinDate = '';
+          }
+        },
+        disabledDate: (time) => {
+          if (this.pickerMinDate !== '') {
+            const day30 = 30 * 24 * 3600 * 1000;
+            const maxTime = this.pickerMinDate + day30;
+            const minTime = this.pickerMinDate - day30;
+            return time.getTime() > maxTime || time.getTime() < minTime;
+          }
+          return false;
+        }
+      },
+
+      //所属公司
+      companyQueryOptions: [],
+      //项目
+      projectLists: [],
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        projectId: null,
+        watchCourseCount: null,
+        completeWatchCount: null,
+        watchCount: null,
+        completeRate: null,
+        answerCount: null,
+        correctCount: null,
+        correctRate: null,
+        receiveCount: null,
+        receiveAmount: null,
+        userCount: null,
+        userBlacklistCount: null,
+        companyId: null,
+        companyName: null,
+        createDate: null,
+        beginTime: null,
+        endTime: null
+      },
+      // 表单参数
+      form: {},
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_course_project").then(response => {
+      this.projectLists = response.data;
+    })
+    getCompanyList().then(response => {
+      if (response.code === 200) {
+        this.companyQueryOptions = response.data;
+      }});
+  },
+  methods: {
+    /** 查询会员每日看课统计列表 */
+    getList() {
+      this.loading = true;
+
+      listStatistics(this.queryParams).then(response => {
+        this.statisticsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      }).catch((error) => {
+        this.loading = false;
+      });
+    },
+
+    /** 处理日期范围变化 */
+    handleDateChange(value) {
+      this.dateRange = value;
+      if (value && value.length === 2) {
+        this.queryParams.beginTime = value[0];
+        this.queryParams.endTime = value[1];
+      } else {
+        this.queryParams.beginTime = null;
+        this.queryParams.endTime = null;
+      }
+    },
+
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    /** 重置按钮操作 */
+    resetQuery() {
+      // 重置日期范围
+      this.dateRange = [];
+      // 手动重置 companyId
+      this.queryParams.companyId = null;
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = {...this.queryParams};
+      // 确保不传递dateRange参数
+      delete queryParams.dateRange;
+
+      this.$confirm('是否确认导出所有会员每日看课统计数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportStatistics(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 266 - 11
src/views/course/userCourse/index.vue

@@ -108,11 +108,11 @@
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange">
+    <el-table height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange" style="width: 100%" :fit="true">
       <el-table-column type="selection" width="55" align="center"/>
-      <el-table-column label="课程ID" align="center" prop="courseId"/>
-      <el-table-column label="所属项目" align="center" prop="projectName"/>
-      <el-table-column label="封面图片" align="center" prop="imgUrl" width="120">
+      <el-table-column label="课程ID" align="center" prop="courseId" width="55"/>
+      <el-table-column label="所属项目" align="center" prop="projectName" width="120"/>
+      <el-table-column label="封面图片" align="center" prop="imgUrl" width="170">
         <template slot-scope="scope">
           <el-popover
             placement="right"
@@ -124,10 +124,10 @@
           </el-popover>
         </template>
       </el-table-column>
-      <el-table-column label="课堂名称" align="center" show-overflow-tooltip prop="courseName"/>
-      <el-table-column label="排序" align="center" prop="sort"/>
-      <el-table-column label="分类名称" align="center" prop="cateName"/>
-      <el-table-column label="子分类名称" align="center" prop="subCateName"/>
+      <el-table-column label="课堂名称" align="center" show-overflow-tooltip prop="courseName" min-width="100"/>
+      <el-table-column label="排序" align="center" prop="sort" width="80"/>
+      <el-table-column label="分类名称" align="center" prop="cateName" width="120"/>
+      <el-table-column label="子分类名称" align="center" prop="subCateName" width="120"/>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
@@ -145,6 +145,14 @@
             v-hasPermi="['course:userCourse:edit']"
           >修改
           </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdateRedPage(scope.row)"
+            v-hasPermi="['course:userCourse:editRedPage']"
+          >统一修改红包金额
+          </el-button>
           <el-button
             size="mini"
             type="text"
@@ -161,6 +169,14 @@
             v-hasPermi="['course:userCourse:remove']"
           >删除
           </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-if="scope.row.isPrivate === 1"
+            v-has-permi="['course:userCourse:editConfig']"
+            @click="configCourse(scope.row)"
+          >过程页配置
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -253,6 +269,83 @@
         <el-button @click="cancel">取 消</el-button>
       </div>
     </el-dialog>
+
+
+    <el-dialog title="修改课程红包金额" :visible.sync="openRedPage.open" width="1000px" append-to-body>
+      <el-form ref="openRedPage" :model="openRedPage" :rules="rulesRedPage" label-width="110px">
+        <el-form-item label="红包金额" prop="redPacketMoney">
+          <el-input-number v-model="openRedPage.redPacketMoney" :min="0.1" :max="200" :step="0.1"></el-input-number>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFormRedPage">确 定</el-button>
+        <el-button @click="cancelRedPage">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 过程页配置 -->
+    <el-dialog
+      :visible.sync="configDialog.dialogVisible"
+      title="过程页配置"
+      append-to-body
+      width="1200px"
+    >
+      <el-form :model="configDialog.form" :rules="configDialog.rules" ref="configForm" label-width="110px">
+        <el-form-item label="过程页图片" prop="coverImg">
+          <ImageUpload v-model="configDialog.form.coverImg" :height="150" :limit="1" :width="150" type="image"/>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 不配置将使用课程默认图片</span>
+        </el-form-item>
+        <el-form-item label="首播电视台" prop="tvEnable">
+          <el-switch v-model="configDialog.form.tvEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="tv" v-if="configDialog.form.tvEnable">
+          <el-input v-model="configDialog.form.tv" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个首播电视台,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="网络播放平台" prop="networkEnable">
+          <el-switch v-model="configDialog.form.networkEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="network" v-if="configDialog.form.networkEnable">
+          <el-input v-model="configDialog.form.network" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个网络播放平台,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="制作单位" prop="unitEnable">
+          <el-switch v-model="configDialog.form.unitEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="unit" v-if="configDialog.form.unitEnable">
+          <el-input v-model="configDialog.form.unit" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个制作单位,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="专家顾问团队" prop="teamEnable">
+          <el-switch v-model="configDialog.form.teamEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="team" v-if="configDialog.form.teamEnable">
+          <el-input v-model="configDialog.form.team" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个专家顾问,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="支持单位" prop="supportEnable">
+          <el-switch v-model="configDialog.form.supportEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="support" v-if="configDialog.form.supportEnable">
+          <el-input v-model="configDialog.form.support" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个支持单位,请用英文逗号隔开</span>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary"
+                   :loading="configDialog.updating"
+                   :disabled="configDialog.updating"
+                   @click="submitConfigForm">确 定</el-button>
+        <el-button @click="cancelConfig">取 消</el-button>
+      </div>
+    </el-dialog>
+
     <el-drawer
       :with-header="false"
       size="75%"
@@ -273,9 +366,11 @@ import {
   updateIsShow,
   copyUserCourse,
   putOn,
-  pullOff
-} from "@/api/course/userCourse";
+  pullOff, updateUserCourseRedPage,
+  editConfig
+} from '@/api/course/userCourse'
 
+import {getSelectableRange} from "@/api/qw/sopTemp";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import Editor from '@/components/Editor/wang';
@@ -284,10 +379,12 @@ import {listBySearch} from "@/api/course/userTalent";
 import userCourseCatalogDetails from '../../components/course/userCourseCatalogDetails.vue';
 import {getAllCourseCategoryList, getCatePidList, getCateListByPid} from "@/api/course/userCourseCategory";
 import {allList} from "@/api/company/company";
+import VideoUpload from '@/components/VideoUpload/index.vue'
 
 export default {
   name: "UserCourse",
   components: {
+    VideoUpload,
     Treeselect,
     Editor, ImageUpload, userCourseCatalogDetails
   },
@@ -336,6 +433,12 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
+      openRedPage:{
+        open:false,
+        courseId:null,
+        courseName:null,
+        redPacketMoney:0.1,
+      },
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -408,6 +511,47 @@ export default {
         integral: [
           {required: true, message: "小节兑换积分不能为空", trigger: "blur"}
         ],
+      },
+
+      rulesRedPage:{
+        redPacketMoney: [
+          {required: true, message: "红包金额不能为空", trigger: "blur"}
+        ],
+      },
+      configDialog: {
+        dialogVisible: false,
+        updating: false,
+        form: {
+          id: null,
+          coverImg: null,
+          tvEnable: 0,
+          tv: null,
+          networkEnable: 0,
+          network: null,
+          unitEnable: 0,
+          unit: null,
+          teamEnable: 0,
+          team: null,
+          supportEnable: 0,
+          support: null
+        },
+        rules: {
+          tv: [
+            { required: true, message: '首播电视台不能为空', trigger: 'blur' }
+          ],
+          network: [
+            { required: true, message: '网络播放平台不能为空', trigger: 'blur' }
+          ],
+          unit: [
+            { required: true, message: '制作单位不能为空', trigger: 'blur' }
+          ],
+          team: [
+            { required: true, message: '专家顾问团队不能为空', trigger: 'blur' }
+          ],
+          support: [
+            { required: true, message: '支持单位不能为空', trigger: 'blur' }
+          ],
+        }
       }
     };
   },
@@ -418,6 +562,9 @@ export default {
     });
 
 
+    getSelectableRange().then(e => {
+      this.startTimeRange = e.data;
+    })
     // this.getTreeselect();
     this.getDicts("sys_spec_show").then(response => {
       this.specShowOptions = response.data;
@@ -626,6 +773,13 @@ export default {
         this.title = "修改课程";
       });
     },
+
+    handleUpdateRedPage(row){
+      this.openRedPage.open=true;
+      this.openRedPage.courseId=row.courseId;
+      this.openRedPage.courseName=row.courseName;
+
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {
@@ -650,6 +804,32 @@ export default {
         }
       });
     },
+
+    submitFormRedPage(){
+
+      const courseId = this.openRedPage.courseId;
+      const redPacketMoney = this.openRedPage.redPacketMoney;
+      this.$confirm('是否确认将课程id 为"' + courseId + '"的红包批量修改为:【'+redPacketMoney+'】?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+
+        return updateUserCourseRedPage({courseId:courseId,redPacketMoney:redPacketMoney});
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("修改成功");
+        this.openRedPage.open=false;
+      }).finally(() => {
+        this.getList();
+        this.openRedPage.open=false;
+      });
+
+    },
+    cancelRedPage(){
+      this.openRedPage.open=false;
+    },
+
     /** 复制按钮操作 */
     handleCopy(row) {
       const courseId = row.courseId;
@@ -729,7 +909,82 @@ export default {
         this.msgSuccess("下架成功");
       }).catch(function () {
       });
-    }
+    },
+    configCourse(row) {
+      if (row.configJson) {
+        this.configDialog.form = {
+          tvEnable: 0,
+          networkEnable: 0,
+          unitEnable: 0,
+          teamEnable: 0,
+          supportEnable: 0,
+          ...JSON.parse(row.configJson)
+        }
+      }
+      this.configDialog.form.id = row.courseId
+      this.configDialog.dialogVisible = true;
+      this.configDialog.updating = false
+    },
+    submitConfigForm() {
+      this.$refs['configForm'].validate(valid => {
+        if (!valid) {
+          this.msgError('请完善配置内容')
+          return
+        }
+
+        if (this.configDialog.updating) {
+          return
+        }
+        this.configDialog.updating = true
+
+        const content = {
+          coverImg: this.configDialog.form.coverImg,
+          tvEnable: this.configDialog.form.tvEnable,
+          tv: this.configDialog.form.tv?.replace(",",","),
+          networkEnable: this.configDialog.form.networkEnable,
+          network: this.configDialog.form.network?.replace(",",","),
+          unitEnable: this.configDialog.form.unitEnable,
+          unit: this.configDialog.form.unit?.replace(",",","),
+          teamEnable: this.configDialog.form.teamEnable,
+          team: this.configDialog.form.team?.replace(",",","),
+          supportEnable: this.configDialog.form.supportEnable,
+          support: this.configDialog.form.support?.replace(",",","),
+        }
+
+        const params = {
+          id: this.configDialog.form.id,
+          configJson: JSON.stringify(content)
+        }
+
+        editConfig(params).then(() => {
+          this.msgSuccess('修改成功')
+          this.configDialog.dialogVisible = false;
+          this.getList()
+        }).finally(() => {
+          setTimeout(() => {
+            this.configDialog.updating = false
+          }, 500)
+        })
+      })
+    },
+    cancelConfig() {
+      this.configDialog.form = {
+        id: null,
+        coverImg: null,
+        tvEnable: 0,
+        tv: null,
+        networkEnable: 0,
+        network: null,
+        unitEnable: 0,
+        unit: null,
+        teamEnable: 0,
+        team: null,
+        supportEnable: 0,
+        support: null
+      }
+      this.resetForm('configForm')
+      this.configDialog.dialogVisible = false;
+    },
   }
 };
 </script>

+ 10 - 10
src/views/course/userCourse/public.vue

@@ -130,9 +130,9 @@
     </el-tabs>
     <el-table height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center"/>
-      <el-table-column label="课程ID" align="center" prop="courseId"/>
-      <el-table-column label="所属项目" align="center" prop="projectName"/>
-      <el-table-column label="封面图片" align="center" prop="imgUrl" width="120">
+      <el-table-column label="课程ID" align="center" prop="courseId" width="60"/>
+      <el-table-column label="所属项目" align="center" prop="projectName" width="120"/>
+      <el-table-column label="封面图片" align="center" prop="imgUrl" width="170">
         <template slot-scope="scope">
           <el-popover
             placement="right"
@@ -156,13 +156,13 @@
           </el-popover>
         </template>
       </el-table-column>
-      <el-table-column label="课堂名称" align="center" show-overflow-tooltip prop="courseName"/>
-      <el-table-column label="排序" align="center" prop="sort"/>
-      <el-table-column label="分类名称" align="center" prop="cateName"/>
-      <el-table-column label="子分类名称" align="center" prop="subCateName"/>
-      <el-table-column label="原价" align="center" prop="price"/>
-      <el-table-column label="售价" align="center" prop="sellPrice"/>
-      <el-table-column label="单节积分" align="center" prop="integral"/>
+      <el-table-column label="课堂名称" align="center" show-overflow-tooltip prop="courseName" min-width="90"/>
+      <el-table-column label="排序" align="center" prop="sort" width="70"/>
+      <el-table-column label="分类名称" align="center" prop="cateName" width="115"/>
+      <el-table-column label="子分类名称" align="center" prop="subCateName" width="115"/>
+      <el-table-column label="原价" align="center" prop="price" width="115"/>
+      <el-table-column label="售价" align="center" prop="sellPrice" width="115"/>
+      <el-table-column label="单节积分" align="center" prop="integral" width="115"/>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button

+ 3 - 0
src/views/course/userCourseComplaintRecord/index.vue

@@ -327,6 +327,9 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.dateRange = [];
+      this.queryParams.startCreateTime = null;
+      this.queryParams.endCreateTime = null;
       this.handleQuery();
     },
     // 多选框选中数据

+ 1 - 1
src/views/course/userCoursePeriod/statistics.vue

@@ -166,7 +166,7 @@ export default {
       // 查询参数
       queryParams: {
         pageNum: 1,
-        pageSize: 10,
+        pageSize: 100,
         videoIdList: [],
         // videoId: '',
         periodId: ''

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

@@ -658,8 +658,9 @@ export default {
         isAudit:1
       },
       this.auditDialog.open=true;
-      this.auditForm.videoIds = row.videoId || this.ids;
+      this.auditForm.videoIds = row.videoId ? [row.videoId] : this.ids;
     },
+
     handleClickX(){
       this.getList()
     },

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

@@ -57,6 +57,16 @@
         />
       </el-form-item>
 
+      <el-form-item label="经销商" prop="companyBelongOwner">
+        <el-input
+          v-model="queryParams.companyBelongOwner"
+          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>
@@ -80,6 +90,7 @@
 
     <el-table border v-loading="loading" :data="userWatchCourseStatisticsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="经销商归属" align="center" prop="companyBelongOwner" />
       <el-table-column label="营期名称" align="center" prop="periodName" />
       <el-table-column label="营期线" align="center" prop="periodStartingTime" />
       <el-table-column label="播出时间" align="center" prop="courseStartDateTime" />
@@ -248,7 +259,8 @@ export default {
         answerRightNum: null,
         answerRightRate: null,
         redPacketNum: null,
-        redPacketAmount: null
+        redPacketAmount: null,
+        companyBelongOwner: null
       },
       // 表单参数
       form: {},

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

@@ -56,6 +56,16 @@
         />
       </el-form-item>
 
+      <el-form-item label="经销商" prop="companyBelongOwner">
+        <el-input
+          v-model="queryParams.companyBelongOwner"
+          placeholder="请输入经销商归属"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
 <!--      <el-form-item label="所属销售" prop="companyUserName">-->
 <!--        <el-input-->
 <!--          v-model="queryParams.companyUserName"-->
@@ -88,6 +98,7 @@
 
     <el-table border v-loading="loading" :data="userWatchCourseStatisticsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="经销商归属" align="center" prop="companyBelongOwner" />
       <el-table-column label="营期名称" align="center" prop="periodName" />
       <el-table-column label="营期线" align="center" prop="periodStartingTime" />
       <el-table-column label="播出时间" align="center" prop="courseStartDateTime" />
@@ -103,6 +114,7 @@
       <el-table-column label="完播率" align="center" prop="completeWatchRatePercent" />
       <el-table-column label="红包领取个数" align="center" prop="redPacketNum" />
       <el-table-column label="红包领取总额" align="center" prop="redPacketAmount" />
+
     </el-table>
 
     <pagination
@@ -253,7 +265,8 @@ export default {
         answerRightNum: null,
         answerRightRate: null,
         redPacketNum: null,
-        redPacketAmount: null
+        redPacketAmount: null,
+        companyBelongOwner: null
       },
       // 表单参数
       form: {},

+ 14 - 1
src/views/course/userWatchStatistics/index.vue

@@ -30,6 +30,16 @@
         />
       </el-form-item>
 
+      <el-form-item label="经销商" prop="companyBelongOwner">
+        <el-input
+          v-model="queryParams.companyBelongOwner"
+          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>
@@ -54,6 +64,7 @@
 
     <el-table border v-loading="loading" :data="userWatchStatisticsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="经销商归属" align="center" prop="companyBelongOwner" />
       <el-table-column label="营期名称" align="center" prop="periodName" />
       <el-table-column label="营期线" align="center" prop="periodStartingTime" width="180">
         <template slot-scope="scope">
@@ -68,6 +79,7 @@
       <el-table-column label="完播人数" align="center" prop="completeWatchNum" />
       <el-table-column label="完播率" align="center" prop="completeWatchRatePercent" />
 
+
     </el-table>
 
     <pagination
@@ -158,7 +170,8 @@ export default {
         userNum: null,
         watchNum: null,
         completeWatchNum: null,
-        completeWatchRate: null
+        completeWatchRate: null,
+        companyBelongOwner: null
       },
       // 表单参数
       form: {},

+ 38 - 118
src/views/course/videoResource/index.vue

@@ -332,7 +332,7 @@
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button @click="cancel">取消</el-button>
-        <el-button type="primary" @click="submitForm" :disabled="isUploading">
+        <el-button type="primary" @click="submitForm" :loading="add" :disabled="isUploading || add">
           {{ isUploading ? '上传中...' : '保存' }}
         </el-button>
       </div>
@@ -406,6 +406,11 @@
             {{ getTypeName(scope.row.typeId) }}
           </template>
         </el-table-column>
+        <el-table-column label="子分类" align="center" min-width="100">
+          <template slot-scope="scope">
+            {{ getTypeName(scope.row.typeSubId) }}
+          </template>
+        </el-table-column>
         <el-table-column label="关联项目" align="center" min-width="100">
           <template slot-scope="scope">
           <a
@@ -522,7 +527,7 @@
 
       <div class="dialog-footer">
         <el-button @click="cancelBatch">取 消</el-button>
-        <el-button type="primary" @click="submitBatchAdd">保 存</el-button>
+        <el-button type="primary" :loading="add" :disabled="add || isUploading" @click="submitBatchAdd">保 存</el-button>
       </div>
       <!-- 批量上传视频弹窗 -->
       <el-dialog
@@ -979,10 +984,12 @@ export default {
     },
     // 取消按钮
     cancel() {
-      this.$refs.videoUpload.clearFiles()
       this.open = false;
       this.reset();
+      this.resetForm("form");
+      this.batchUpdateVisible = false;
       this.changeCateType(this.queryParams.typeId)
+      this.$refs.videoUpload.clearFiles()
     },
     // 表单重置
     reset() {
@@ -1094,9 +1101,10 @@ export default {
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.add){
-            this.$message.warning("文件上传中,请稍后再试")
+            this.$message.warning("请勿重复提交")
             return
           }
+          this.add = true
 
           const params = Object.assign({}, this.form);
           params.projectIds = this.form.projectIds.join(',');
@@ -1107,7 +1115,7 @@ export default {
                 this.open = false;
                 this.getList();
               }
-            });
+            })
           } else {
             addVideoResource(params).then(response => {
               if (response.code === 200) {
@@ -1115,7 +1123,7 @@ export default {
                 this.open = false;
                 this.getList();
               }
-            });
+            })
           }
         }
       });
@@ -1273,7 +1281,7 @@ export default {
             this.uploadCancellationTokens.set(form.tempId, tokens);
           }
         });
-        
+
         let line_1 = `${process.env.VUE_APP_VIDEO_LINE_1}${data.urlPath}`;
         form.fileKey = data.urlPath.substring(1);
         form.videoUrl = line_1;
@@ -1310,7 +1318,7 @@ export default {
             this.uploadCancellationTokens.set(form.tempId, tokens);
           }
         });
-        
+
         form.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
 
         // 更新线路2状态为成功
@@ -1355,7 +1363,7 @@ export default {
       const file = options.file;
       this.getMediaDuration(file);
       this.currentUploadProgress = { total: 0, line1: 0, line2: 0, line1Status: 'pending', line2Status: 'pending' };
-      
+
       try {
         await this.getFirstThumbnail(file, this.form);
         const [line1Result, line2Result] = await Promise.allSettled([
@@ -1414,6 +1422,7 @@ export default {
     /** 批量新增 */
     handleBatchAdd() {
       this.batchAddVisible = true;
+      this.add =false
       this.videoList = []; // 清空之前的视频列表
     },
     /** 批量修改 */
@@ -1422,8 +1431,7 @@ export default {
         this.$message.warning("请至少选择一条数据");
         return;
       }
-      this.batchUpdateForm.typeId = null;
-      this.batchUpdateForm.typeSubId = null;
+      this.resetForm("form");
       this.batchUpdateForm.ids = this.ids; // 将选中的ID传递给批量修改表单
       this.batchUpdateVisible = true;
     },
@@ -1486,12 +1494,24 @@ export default {
     },
     /** 提交批量添加 */
     submitBatchAdd() {
+      if (this.videoList.length === 0) {
+        this.$message.warning("请选择视频");
+        return;
+      }
+
       // 检查是否所有选中的视频都已上传完成
       const incompleteVideos = this.videoList.filter(item => (item.progress || 0) < 100);
       if (incompleteVideos.length > 0) {
         this.$message.warning('有未完成上传的视频,请先完成上传');
         return;
       }
+
+      if (this.add){
+        this.$message.warning("请勿重复提交")
+        return
+      }
+      this.add = true
+
       // 调用批量添加API
       const videoList = JSON.parse(JSON.stringify(this.videoList));
       videoList.forEach(item => {
@@ -1503,7 +1523,7 @@ export default {
           this.batchAddVisible = false;
           this.getList();
         }
-      });
+      })
     },
     /** 获取分类名称 */
     getTypeName(typeId) {
@@ -1564,7 +1584,7 @@ export default {
             console.error('Error cancelling COS upload:', error);
           }
         }
-        
+
         // Cancel OBS upload if exists
         if (cancellationTokens.obs) {
           try {
@@ -1574,7 +1594,7 @@ export default {
             console.error('Error cancelling OBS upload:', error);
           }
         }
-        
+
         // Remove cancellation tokens
         this.uploadCancellationTokens.delete(row.tempId);
       }
@@ -1716,6 +1736,7 @@ export default {
         return;
       }
 
+      this.isUploading = true;
       this.isProcessingBatch = true;
 
       while (this.uploadQueue.length > 0) {
@@ -1750,6 +1771,7 @@ export default {
       }
 
       this.isProcessingBatch = false;
+      this.isUploading = false;
       this.$message.success('所有视频上传队列处理完成!');
     },
 
@@ -2042,108 +2064,6 @@ export default {
       });
     },
 
-    /** 删除视频 */
-    handleDeleteVideo(row) {
-      if (row.uploadStatus === 'uploading') {
-        this.$confirm('该视频正在上传中,确认要取消上传并删除吗?', '取消上传', {
-          confirmButtonText: '确定取消',
-          cancelButtonText: '继续上传',
-          type: 'warning'
-        }).then(() => {
-          // Cancel the upload and remove from list
-          this.cancelVideoUpload(row);
-        }).catch(() => {
-          // User chose to continue uploading
-          this.$message.info('继续上传该视频');
-        });
-      } else {
-        // Original confirmation for non-uploading videos
-        this.$confirm('确认要从列表中删除该视频吗?', '提示', {
-          confirmButtonText: '确定',
-          cancelButtonText: '取消',
-          type: 'warning'
-        }).then(() => {
-          this.removeVideoFromList(row);
-        }).catch(() => {
-          // 取消删除
-        });
-      }
-    },
-
-    cancelVideoUpload(row) {
-      const cancellationTokens = this.uploadCancellationTokens.get(row.tempId);
-      if (cancellationTokens) {
-        // Cancel COS upload if exists
-        if (cancellationTokens.cos) {
-          try {
-            cancellationTokens.cos();
-            console.log('COS upload cancelled for video:', row.tempId);
-          } catch (error) {
-            console.error('Error cancelling COS upload:', error);
-          }
-        }
-        
-        // Cancel OBS upload if exists
-        if (cancellationTokens.obs) {
-          try {
-            cancellationTokens.obs();
-            console.log('OBS upload cancelled for video:', row.tempId);
-          } catch (error) {
-            console.error('Error cancelling OBS upload:', error);
-          }
-        }
-        
-        // Remove cancellation tokens
-        this.uploadCancellationTokens.delete(row.tempId);
-      }
-
-      const videoIndex = this.videoList.findIndex(item => item.tempId === row.tempId);
-      if (videoIndex !== -1) {
-        this.videoList[videoIndex].uploadStatus = 'cancelled';
-        this.videoList.splice(videoIndex, 1);
-      }
-
-      const queueIndex = this.uploadQueue.findIndex(item => item.tempId === row.tempId);
-      if (queueIndex !== -1) {
-        this.uploadQueue.splice(queueIndex, 1);
-        this.updateQueuePositions();
-      }
-
-      this.$message.success('已取消视频上传并从列表中移除');
-    },
-
-    removeVideoFromList(row) {
-      const videoIndex = this.videoList.findIndex(item => item.tempId === row.tempId);
-      if (videoIndex !== -1) {
-        this.videoList.splice(videoIndex, 1);
-      }
-
-      // Remove from upload queue if it's still queued
-      const queueIndex = this.uploadQueue.findIndex(item => item.tempId === row.tempId);
-      if (queueIndex !== -1) {
-        this.uploadQueue.splice(queueIndex, 1);
-        this.updateQueuePositions();
-        this.$message.success('已从上传队列中移除该视频');
-      } else {
-        this.$message.success('已从列表中移除该视频');
-      }
-    },
-
-    getUploadStatusText(status, queuePosition) {
-      switch (status) {
-        case 'success':
-          return '上传成功';
-        case 'failed':
-          return '上传失败';
-        case 'uploading':
-          return '上传中';
-        case 'queued':
-          return `队列中 (第${queuePosition}位)`;
-        default:
-          return '待上传';
-      }
-    },
-
     getQueueStatusColor(status) {
       switch (status) {
         case 'success':
@@ -2176,7 +2096,7 @@ export default {
           tokens.cos = uploadInfo.cancel;
           this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
         });
-        
+
         let line_1 = `${process.env.VUE_APP_VIDEO_LINE_1}${data.urlPath}`;
         tempVideo.fileKey = data.urlPath.substring(1);
         tempVideo.videoUrl = line_1;
@@ -2202,7 +2122,7 @@ export default {
           tokens.obs = uploadInfo.cancel;
           this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
         });
-        
+
         tempVideo.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
         return { success: true, url: tempVideo.line2 };
       } catch (error) {

+ 17 - 13
src/views/crm/components/assignCompany.vue

@@ -45,7 +45,7 @@
       </el-form>
       <div slot="footer" class="footer">
         <el-button type="primary" @click="submitAssignForm">确 定</el-button>
-        <el-button @click="assign.open=false">取 消</el-button>
+        <el-button @click="handleCancel">取 消</el-button>
       </div>
 
      <el-dialog :title="companySelect.title" :visible.sync="companySelect.open" width="1000px" append-to-body>
@@ -78,22 +78,24 @@
                 },
                 // 表单校验
                 assignRules: {
-                    
+
                 },
                 companys:[],
-                 
+
             };
         },
         created() {
-          
+
         },
         methods: {
-            init(customerIds){
-                this.customerIds =  customerIds;
-                this.assignCount=0;
-                this.noAssignCount=this.customerIds.length;
-                this.companys=[];
-            },
+          handleCancel() {
+            this.companys = [];
+            this.noAssignCount = 0;
+            this.assignCount = 0;
+            this.customerIds = [];
+            //关闭弹窗
+            // this.$emit('close');
+          },
             changeVal(row) {
                 this.$forceUpdate();//解决点击计数器失效问题
                 this.computeCount();
@@ -102,7 +104,7 @@
                          row.count=0;
                          this.computeCount();
                     });
-                   
+
                 }
             },
             handleRemoveCompany(index){
@@ -199,7 +201,9 @@
                 });
             },
             closeAction(){
-                //this.$refs.companySelects.companys=[];
+              if (this.$refs.companySelects) {
+                this.$refs.companySelects.clearSelection();
+              }
             }
         }
     };
@@ -210,7 +214,7 @@
     height: 100%;
     background-color: #fff;
     padding: 20px;
-        
+
 }
 .footer{
     display: flex;

+ 22 - 60
src/views/crm/customer/index.vue

@@ -21,25 +21,13 @@
         />
       </el-form-item>
       <el-form-item label="客户名称" prop="customerName">
-        <el-select
+        <el-input
           v-model="queryParams.customerName"
-          filterable
-          remote
+          placeholder="请输入客户名称"
           clearable
           size="small"
-          placeholder="请输入客户名称"
-          :remote-method="remoteCustomerNameQuery"
-          :loading="customerNameLoading"
-          @change="handleQuery"
-          @clear="handleClearCustomerName"
-        >
-          <el-option
-            v-for="item in customerNameOptions"
-            :key="item"
-            :label="item"
-            :value="item"
-          />
-        </el-select>
+          @keyup.enter.native="handleQuery"
+        />
       </el-form-item>
       <el-form-item label="手机" prop="mobile">
         <el-input
@@ -75,7 +63,7 @@
           v-model="dateRange"
           type="daterange"
           value-format="yyyy-MM-dd"
-          start-placeholder="开始日期" end-placeholder="结束日期"
+          start-placeholder="开始日期" end-placeholder="结束日期" @change="handleScheduleTimeChange"
            >
         </el-date-picker>
       </el-form-item>
@@ -335,7 +323,7 @@
 </template>
 
 <script>
-import { getCustName,listCustomer,getCustomer,addCustomer,updateCustomer,delCustomer,exportCustomer  } from "@/api/crm/customer";
+import { listCustomer,getCustomer,addCustomer,updateCustomer,delCustomer,exportCustomer  } from "@/api/crm/customer";
 import { getCompanyList } from "@/api/company/company";
 import customerDetails from '../components/customerDetails.vue';
 import editCustomerSource from '../components/editCustomerSource.vue';
@@ -350,8 +338,6 @@ export default {
         title:"修改客户来源",
         open:false,
       },
-      customerNameOptions: [], // 客户名称
-      customerNameLoading: false,
       tagId:null,
       tagsOptions:[],
       ctsTypeArr:[],
@@ -419,7 +405,9 @@ export default {
         companyId: null,
         isLine: null,
         source: null,
-        tags: null
+        tags: null,
+        beginTime: null,
+        endTime: null,
       },
       // 表单参数
       form: {},
@@ -463,6 +451,15 @@ export default {
     this.getList();
   },
   methods: {
+    handleScheduleTimeChange(val) {
+      if (val) {
+        this.queryParams.beginTime = val[0];
+        this.queryParams.endTime = val[1];
+      } else {
+        this.queryParams.beginTime = null;
+        this.queryParams.endTime = null;
+      }
+    },
     handleEditSource(){
       this.source.open=true;
       var that=this;
@@ -512,25 +509,6 @@ export default {
           this.citys=res.data;
         })
     },
-    handleClose(tag) {
-        this.tags.splice(this.tags.indexOf(tag), 1);
-        this.form.tags=this.tags.toString();
-    },
-    showInput() {
-      this.inputVisible = true;
-      this.$nextTick(_ => {
-        this.$refs.saveTagInput.$refs.input.focus();
-      });
-    },
-    handleInputConfirm() {
-      let inputValue = this.inputValue;
-      if (inputValue) {
-        this.tags.push(inputValue);
-      }
-      this.inputVisible = false;
-      this.inputValue = '';
-      this.form.tags=this.tags.toString();
-    },
     handleShow(row){
       var that=this;
       that.show.open=true;
@@ -616,7 +594,11 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.queryParams.beginTime = null;
+      this.queryParams.endTime = null;
+      this.dateRange = null;
       this.resetForm("queryForm");
+      //this.$forceUpdate(); // 强制更新视图
       this.handleQuery();
     },
     // 多选框选中数据
@@ -703,26 +685,6 @@ export default {
           this.msgSuccess("删除成功");
         }).catch(function() {});
     },
-    // 远程搜索客户名称
-    remoteCustomerNameQuery(query) {
-      if (query !== '') {
-        this.customerNameLoading = true;
-        // 防抖处理,避免频繁请求
-        clearTimeout(this.customerNameTimer);
-        this.customerNameTimer = setTimeout(() => {
-          getCustName({ customerName: query })
-            .then(response => {
-              this.customerNameOptions = response
-              this.customerNameLoading = false;
-            })
-            .catch(() => {
-              this.customerNameLoading = false;
-            });
-        }, 300);
-      } else {
-        this.customerNameOptions = [];
-      }
-    },
     /** 导出按钮操作 */
     handleExport() {
       //const queryParams = this.queryParams;

+ 21 - 41
src/views/crm/customer/line.vue

@@ -11,25 +11,13 @@
         />
       </el-form-item>
       <el-form-item label="客户名称" prop="customerName">
-        <el-select
+        <el-input
           v-model="queryParams.customerName"
-          filterable
-          remote
+          placeholder="请输入客户名称"
           clearable
           size="small"
-          placeholder="请输入客户名称"
-          :remote-method="remoteCustomerNameQuery"
-          :loading="customerNameLoading"
-          @change="handleQuery"
-          @clear="handleClearCustomerName"
-        >
-          <el-option
-            v-for="item in customerNameOptions"
-            :key="item"
-            :label="item"
-            :value="item"
-          />
-        </el-select>
+          @keyup.enter.native="handleQuery"
+        />
       </el-form-item>
       <el-form-item label="手机" prop="mobile">
         <el-input
@@ -55,7 +43,7 @@
           v-model="dateRange"
           type="daterange"
           value-format="yyyy-MM-dd"
-          start-placeholder="开始日期" end-placeholder="结束日期"
+          start-placeholder="开始日期" end-placeholder="结束日期"  @change="handleScheduleTimeChange"
            >
         </el-date-picker>
       </el-form-item>
@@ -327,7 +315,7 @@
 </template>
 
 <script>
-import { getCustName,assignCustomer,importLineTemplate,listLineCustomer, getLineCustomer, delLineCustomer, addLineCustomer, updateLineCustomer, exportLineCustomer } from "@/api/crm/customer";
+import { assignCustomer,importLineTemplate,listLineCustomer, getLineCustomer, delLineCustomer, addLineCustomer, updateLineCustomer, exportLineCustomer } from "@/api/crm/customer";
 import {getCitys} from "@/api/store/city";
 import { getToken } from "@/utils/auth";
 import { isAdmin } from "@/api/system/user";
@@ -340,8 +328,6 @@ export default {
   components: { customerAssignList,assignCompany },
   data() {
     return {
-      customerNameOptions: [], // 客户名称
-      customerNameLoading: false,
       assignList:{
         title:"分配历史记录",
         open:false,
@@ -440,7 +426,9 @@ export default {
         companyId: null,
         isLine: null,
         source: null,
-        tags: null
+        tags: null,
+        beginTime: null,
+        endTime: null,
       },
       // 表单参数
       form: {
@@ -479,6 +467,15 @@ export default {
     this.getList();
   },
   methods: {
+    handleScheduleTimeChange(val) {
+      if (val) {
+        this.queryParams.beginTime = val[0];
+        this.queryParams.endTime = val[1];
+      } else {
+        this.queryParams.beginTime = null;
+        this.queryParams.endTime = null;
+      }
+    },
     handleAssignList(){
       this.assignList.open=true;
       var that=this;
@@ -597,6 +594,9 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.queryParams.beginTime = null;
+      this.queryParams.endTime = null;
+      this.dateRange = null;
       this.resetForm("queryForm");
       this.handleQuery();
     },
@@ -683,26 +683,6 @@ export default {
         this.title = "修改线索客户";
       });
     },
-    // 远程搜索客户名称
-    remoteCustomerNameQuery(query) {
-      if (query !== '') {
-        this.customerNameLoading = true;
-        // 防抖处理,避免频繁请求
-        clearTimeout(this.customerNameTimer);
-        this.customerNameTimer = setTimeout(() => {
-          getCustName({ customerName: query })
-            .then(response => {
-              this.customerNameOptions = response
-              this.customerNameLoading = false;
-            })
-            .catch(() => {
-              this.customerNameLoading = false;
-            });
-        }, 300);
-      } else {
-        this.customerNameOptions = [];
-      }
-    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {

+ 2056 - 0
src/views/crm/externalContact/index.vue

@@ -0,0 +1,2056 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="企微公司" prop="corpId">
+            <el-select v-model="queryParams.corpId" placeholder="企微公司"  size="small" @change="updateCorpId()">
+              <el-option
+                v-for="dict in myQwCompanyList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+      </el-form-item>
+      <el-form-item label="客户名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入客户名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="活码id" prop="wayId">
+        <el-input
+          v-model="queryParams.wayId"
+          placeholder="请输入活码id"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="销售企微昵称" prop="qwUserName">
+        <el-input
+          v-model="queryParams.qwUserName"
+          placeholder="请输入销售企微昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+          @input="searchQwUser"
+          @focus="showQwUserDropdown = true"
+          @blur="hideDropdownWithDelay"
+          @clear="onQwUserNameClear"
+        />
+        <!-- 下拉建议 -->
+        <div v-if="showQwUserDropdown && qwUserSuggestions.length > 0" class="suggestion-box"  @scroll="handleScroll">
+          <div
+            v-for="item in qwUserSuggestions"
+            :key="item.dictValue"
+            class="suggestion-item"
+            @click="selectQwUser(item.dictValue,item.dictLabel)"
+          >
+            {{ item.dictLabel }}
+          </div>
+        </div>
+      </el-form-item>
+      <el-form-item label="用户类别" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择用户类别" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="所属销售" prop="companyUser">
+        <el-input
+          v-model="queryParams.companyUser"
+          placeholder="请输入昵称或者手机号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="性别" prop="gender">
+        <el-select v-model="queryParams.gender" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in genderOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="客户等级" prop="level">
+        <el-select v-model="queryParams.level" placeholder="客户等级" clearable size="small">
+          <el-option
+            v-for="dict in ratingType"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="等级升降" prop="levelType">
+        <el-select v-model="queryParams.levelType" placeholder="等级升降" clearable size="small">
+          <el-option
+            v-for="dict in ratingUpFall"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+
+      <el-form-item label="电话号码" prop="remarkMobiles">
+        <el-input
+          v-model="queryParams.remarkMobiles"
+          placeholder="请输入备注电话号码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="来源" prop="addWay">
+
+        <el-select v-model="queryParams.addWay" placeholder="来源" clearable size="small">
+          <el-option
+            v-for="dict in addWayOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+
+        <el-select v-model="queryParams.status" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="转接状态" prop="addWay">
+
+        <el-select v-model="queryParams.transferStatus" placeholder="转接状态" clearable size="small">
+          <el-option
+            v-for="dict in transferStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否绑定会员" prop="isBindMini">
+        <el-select v-model="queryParams.isBindMini" placeholder="是否绑定会员" clearable size="small" @change="handleQuery" >
+          <el-option
+            v-for="dict in isBindMiniOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标签" prop="tagIds">
+<!--        <el-select v-model="selectTags" remote multiple placeholder="请选择" filterable  style="width: 100%;">-->
+<!--          <el-option-->
+<!--            v-for="dict in tagList"-->
+<!--            :label="dict.name"-->
+<!--            :value="dict.tagId">-->
+<!--          </el-option>-->
+<!--        </el-select>-->
+
+        <div @click="hangleChangeTags()" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 250px">
+          <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
+            <el-tag type="success"
+                    closable
+                    :disable-transitions="false"
+                    v-for="list in this.selectTags"
+                    :key="list.tagId"
+                    @close="handleCloseTags(list)"
+                    style="margin: 3px;"
+            >{{list.name}}
+            </el-tag>
+          </div>
+        </div>
+
+
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+       <el-form-item label="添加时间" prop="createTime">
+          <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
+      </el-form-item>
+
+
+
+
+      <el-form-item label="流失时间" prop="lossTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.lossTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择流失时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="删除时间" prop="delTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.delTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择删除时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+<!--      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:externalContact:add']"
+        >同步</el-button>
+      </el-col> -->
+<!--      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotes"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotesFilter"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注(筛选条件)
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['qw:externalContact:edit']"
+        >修改备注</el-button>
+      </el-col>-->
+
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:externalContact:export']"
+        >导出</el-button>
+      </el-col>
+<!--      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="addUserTag"
+          v-hasPermi="['qw:externalContact:addTag']"
+        >批量添加标签</el-button>
+      </el-col>-->
+<!--      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="delUserTag"
+          v-hasPermi="['qw:externalContact:delTag']"
+        >批量移除标签</el-button>
+      </el-col>
+	  <el-col :span="1.5">
+	    <el-button
+	      type="primary"
+	      plain
+	      size="mini"
+	      @click="updateTalk"
+        v-hasPermi="['qw:externalContactInfo:updateTalk']"
+	    >批量更改交流状态</el-button>
+	  </el-col>-->
+<!--       <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          size="mini"-->
+<!--          @click="setUserCourseSop"-->
+<!--          v-hasPermi="['qw:externalContact:setCourseSop']"-->
+<!--        >批量设置课程SOP</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+<!--    <el-tabs type="card" v-model="isBindActiveName" @tab-click="handleClickX">-->
+<!--      <el-tab-pane label="全部" name="all"></el-tab-pane>-->
+<!--      <el-tab-pane label="已绑定CRM" name="isBind"></el-tab-pane>-->
+<!--      <el-tab-pane label="未绑定CRM" name="noBind"></el-tab-pane>-->
+<!--    </el-tabs>-->
+
+    <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="企微客户ID" align="center" prop="id" />
+      <el-table-column label="企微客户头像" align="center" prop="avatar" width="100px">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.avatar" width="60px">
+            <img :src="scope.row.avatar" style="max-width: 200px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="企微客户名称"  prop="name" width="110px"/>
+      <el-table-column label="客户称呼"  prop="stageStatus" width="110px"/>
+      <el-table-column label="销售企微昵称" align="center" prop="qwUserName" width="120px"/>
+      <el-table-column label="企微部门" align="center" prop="departmentName" width="120px"/>
+      <el-table-column label="用户类别" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="性别" align="center" prop="gender">
+        <template slot-scope="scope">
+          <dict-tag :options="genderOptions" :value="scope.row.gender"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="描述信息" align="center" prop="description" />
+      <el-table-column label="标签" align="center" prop="tagIdsName" width="300px">
+<!--        <template slot-scope="scope">-->
+<!--          <div v-for="name in scope.row.tagIdsName"  style="display: inline;">-->
+<!--          <el-tag type="success">{{ name }}</el-tag>-->
+<!--          </div>-->
+<!--        </template>-->
+        <template slot-scope="scope">
+          <div class="tag-container">
+            <div class="tag-list">
+              <el-tag
+                v-for="name in scope.row.tagIdsName"
+                :key="name"
+                type="success"
+                size="small"
+              >
+                {{ name }}
+              </el-tag>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否回复" align="center" prop="isReply" width="120px" >
+        <template slot-scope="scope">
+          <span v-if="scope.row.isReply === 1"><el-tag type="success">已回复</el-tag></span>
+          <span v-else-if="scope.row.isReply === 0"><el-tag type="info">未回复</el-tag></span>
+          <span v-else>{{ scope.row.isReply }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="客户等级" align="center" prop="level" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingType" :value="scope.row.level"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="state参数" align="center" prop="state" width="100px" />
+
+      <el-table-column label="等级状态" align="center" prop="levelType" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingUpFall" :value="scope.row.levelType"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="添加时间" align="center" prop="createTime" width="100px" />
+      <el-table-column label="流失时间" align="center" prop="lossTime" width="100px" />
+      <el-table-column label="删除时间" align="center" prop="delTime" width="100px" />
+      <el-table-column label="注册时间" align="center" prop="registerTime" width="100px" />
+      <el-table-column label="备注电话号码" align="center" prop="remarkMobiles" width="150px">
+        <template slot-scope="scope">
+          <div v-for="i in JSON.parse(scope.row.remarkMobiles)" :key="i">{{i}}</div>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注企业名称" align="center" prop="remarkCorpName" />
+      <el-table-column label="来源" align="center" prop="addWay" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="addWayOptions" :value="scope.row.addWay"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="转接状态" align="center" prop="transferStatus" width="100px" >
+        <template slot-scope="scope">
+          <dict-tag :options="transferStatusOptions" :value="scope.row.transferStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="企业id" align="center" prop="corpId" />
+      <el-table-column label="是否绑定会员" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.fsUserId" >已绑定</el-tag>
+          <el-tag v-else type="info"> 未绑定</el-tag>
+        </template>
+      </el-table-column>
+<!--      <el-table-column label="修改" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            v-if="scope.row.status==0||scope.row.status==2"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:externalContact:edit']"
+          >修改备注</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user-solid"
+            @click="handleAppellation(scope.row)"
+          >修改客户称呼</el-button>
+        </template>
+      </el-table-column>-->
+<!--      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+&lt;!&ndash;          <el-button&ndash;&gt;
+&lt;!&ndash;            size="mini"&ndash;&gt;
+&lt;!&ndash;            type="text"&ndash;&gt;
+&lt;!&ndash;            icon="el-icon-edit-outline"&ndash;&gt;
+&lt;!&ndash;            @click="handleUpdateCustomer(scope.row)"&ndash;&gt;
+&lt;!&ndash;            >&ndash;&gt;
+&lt;!&ndash;            <span v-if="scope.row.customerId">换绑CRM</span>&ndash;&gt;
+&lt;!&ndash;            <span v-else>绑定CRM</span>&ndash;&gt;
+&lt;!&ndash;          </el-button>&ndash;&gt;
+
+&lt;!&ndash;          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit-outline"
+            @click="handleUpdateUser(scope.row)"
+            >
+            <span v-if="scope.row.fsUserId">换绑会员</span>
+            <span v-else>绑定会员</span>
+          </el-button>
+
+          <el-button
+            v-if="scope.row.fsUserId"
+            size="mini"
+            type="text"
+            icon="el-icon-thumb"
+            @click="handleUnBindUserId(scope.row)"
+            v-hasPermi="['qw:externalContact:unBindUserId']"
+          >
+            <span>解除会员绑定</span>
+          </el-button>&ndash;&gt;
+
+
+&lt;!&ndash;          <el-button v-if="scope.row.customerId"&ndash;&gt;
+&lt;!&ndash;            size="mini"&ndash;&gt;
+&lt;!&ndash;            type="text"&ndash;&gt;
+&lt;!&ndash;            icon="el-icon-paperclip"&ndash;&gt;
+&lt;!&ndash;            @click="handleShow(scope.row)"&ndash;&gt;
+&lt;!&ndash;          >CRM客户详情</el-button>&ndash;&gt;
+          <el-button
+             size="mini"
+             type="text"
+             @click="handledetails(scope.row)"
+             >AI获取用户信息
+          </el-button>
+          <el-button
+             size="mini"
+             type="text"
+             @click="handleMemberdetails(scope.row)"
+             v-if="scope.row.fsUserId"
+             >
+             <span>会员详细</span>
+          </el-button>
+        </template>
+      </el-table-column>-->
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-drawer size="75%" :title="show.title" :visible.sync="show.open">
+      <customer-details  ref="customerDetails" @refreshList="refreshList"/>
+    </el-drawer>
+
+    <el-drawer
+        :with-header="false"
+        size="75%"
+          :title="show.title" :visible.sync="show.open">
+      <userDetails  ref="userDetails" />
+    </el-drawer>
+
+
+    <!--  搜索标签   -->
+    <el-dialog :title="changeTagDialog.title" :visible.sync="changeTagDialog.open" style="width:100%;height: 100%" append-to-body>
+
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(queryTagParams.name)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <div v-for="item in tagGroupList" :key="item.id"  >
+        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+          <span class="name-background">{{ item.name }}</span>
+        </div>
+        <!-- 添加外层滚动容器 -->
+        <div class="scroll-wrapper">
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </div>
+
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagSubmitForm()">确 定</el-button>
+        <el-button @click="tagCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量添加标签" :visible.sync="tagOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <!-- 添加外层滚动容器 -->
+          <div class="scroll-wrapper">
+            <div class="tag-container">
+              <a
+                v-for="tagItem in item.tag"
+                class="tag-box"
+                @click="tagSelection(tagItem)"
+                :class="{ 'tag-selected': tagItem.isSelected }"
+              >
+                {{ tagItem.name }}
+              </a>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addTagSubmitForm()">确 定</el-button>
+        <el-button @click="addTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog title="批量添加客户备注" :visible.sync="notesOpen.open" width="800px" append-to-body>
+      <el-card>
+        <el-row>
+          <el-col>
+            <el-radio-group v-model="notesOpen.nameType" style="margin-bottom: 2%">
+              <el-radio :label="1">
+                客户名称添加在【新备注】【前】
+              </el-radio>
+              <el-radio :label="2">
+                客户名称添加在【新备注】【后】
+              </el-radio>
+              <el-radio :label="3">
+                不添加客户名称
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-radio-group v-model="notesOpen.type">
+              <el-radio
+                :label="1"
+              >添加【新备注】在最【前】面
+              </el-radio>
+              <el-radio
+                :label="2"
+              >添加【新备注】在最【后】面
+              </el-radio>
+              <el-radio
+                :label="3"
+              >替换所有备注
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-input v-model="notesOpen.notes" placeholder="请输入客户备注(最多20个字,含已有的)" clearable size="small"
+                      maxlength="20" show-word-limit style="width: 500px;margin-top: 3%"/>
+            <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
+              <i class="el-icon-info"></i>
+              由于企业微信官方限制,备注最多20个字,且自动会去除末尾超出的字
+            </div>
+          </el-col>
+        </el-row>
+      </el-card>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="notesSubmitForm()">确 定</el-button>
+        <el-button @click="notesCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量移除标签" :visible.sync="tagDelOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <!-- 添加外层滚动容器 -->
+          <div class="scroll-wrapper">
+            <div class="tag-container">
+              <a
+                v-for="tagItem in item.tag"
+                class="tag-box"
+                @click="tagSelection(tagItem)"
+                :class="{ 'tag-selected': tagItem.isSelected }"
+              >
+                {{ tagItem.name }}
+              </a>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagDelSubmitForm()">确 定</el-button>
+        <el-button @click="DelTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 添加或修改企业微信客户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="描述信息" prop="description">
+          <el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入描述信息" />
+        </el-form-item>
+
+        <el-form-item label="备注电话号码" prop="remarkMobiles">
+
+          <el-tag
+            :key="tag"
+            v-for="tag in remarkMobiles"
+            closable
+            :disable-transitions="false"
+            @close="handleClose(tag)">
+            {{tag}}
+          </el-tag>
+          <el-input
+            style="width:110px"
+            class="input-new-tag"
+            v-if="inputVisible"
+            v-model="inputValue"
+            ref="saveTagInput"
+            size="small"
+            @keyup.enter.native="handleInputConfirm"
+            @blur="handleInputConfirm"
+          >
+          </el-input>
+          <el-button v-else class="button-new-tag" size="small" style="width: 110px" @click="showInput">新增电话</el-button>
+
+        </el-form-item>
+
+
+        <el-form-item label="备注企业名称" prop="remarkCorpName">
+          <el-input v-model="form.remarkCorpName" placeholder="请输入备注企业名称" />
+        </el-form-item>
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="callOpen.title" :visible.sync="callOpen.open" width="500px" append-to-body>
+      <el-form ref="callOpenFrom" :model="callOpenFrom" :rules="callOpenRule" label-width="110px">
+        <el-form-item label="客户称呼" prop="stageStatus">
+          <el-input v-model="callOpenFrom.stageStatus" placeholder="请输入客户称呼" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer" >
+        <el-button type="primary" @click="submitCallOpenFrom">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 绑定客户   -->
+    <el-dialog :title="bindCustomer.title" :visible.sync="bindCustomer.open"  width="1200px" append-to-body>
+      <mycustomer ref="mycustomer"  @bindCustomerId="bindCustomerId"></mycustomer>
+    </el-dialog>
+
+<!--    设置一个课程sop-->
+    <el-dialog :title="setSop.title" :visible.sync="setSop.open"  width="1200px" append-to-body>
+      <SopDialog ref="SopDialog"  @bindCourseSop="bindCourseSop"></SopDialog>
+    </el-dialog>
+
+    <el-dialog :title="user.title" :visible.sync="user.open" width="800px" append-to-body>
+      <selectUser ref="selectUser" @bindMiniCustomerId="bindMiniCustomerId"></selectUser>
+    </el-dialog>
+
+	<el-dialog :title="info.title" :visible.sync="info.open"   width="1100px" append-to-body>
+	  <info  ref="Details" />
+	</el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  bindUserId,
+  addTag,
+  delTag,
+  batchUpdateExternalContactNotes,
+  listExternalContact,
+  getExternalContact,
+  delExternalContact,
+  addExternalContact,
+  updateExternalContact,
+  exportExternalContact,
+  editbindCustomer,
+  setCustomerCourseSop,
+  getCustomerCourseSop,
+  setCustomerCourseSopList,
+  unBindUserId, updateExternalContactCall
+} from '@/api/qw/externalContact'
+/*import {getMyQwUserList, getMyQwCompanyList, updateUser,getQwUserListLikeName} from "@/api/qw/user";*/
+import {getMyQwUserList, getMyQwCompanyList, updateUser} from "@/api/qw/user";
+import {listTag, getTag, searchTags,} from "@/api/qw/tag";
+import { allListTagGroup} from "@/api/qw/tagGroup";
+/*import mycustomer from '@/views/qw/externalContact/mycustomer'
+import customerDetails from '@/views/qw/externalContact/customerDetails'
+import SopDialog from '@/views/course/sop/SopDialog.vue'
+import  selectUser  from "@/views/qw/externalContact/selectUser.vue";
+import info from "@/views/qw/externalContact/info.vue";
+import { editTalk } from "@/api/qw/externalContactInfo";*/
+import PaginationMore from "../../../components/PaginationMore/index.vue";
+/*import userDetails from '@/views/store/components/userDetails.vue';*/
+export default {
+  name: "ExternalContact",
+  /*components:{PaginationMore, mycustomer,customerDetails,SopDialog,selectUser,info,userDetails},*/
+  components:{PaginationMore},
+  data() {
+    return {
+      notesOpen: {
+        type: 1,
+        nameType: 3,
+        addType: 0,
+        filter: false,
+        open: false,
+        notes: null,
+      },
+      user:{
+        open:false,
+        title:"修改客户"
+      },
+      userForm:{
+        id:null,
+        fsUserId:null,
+      },
+      info:{
+        title:"用户信息",
+        open:false,
+      },
+      // ...其他已有数据
+      qwUserSuggestions: [],       // 已展示的数据
+      showQwUserDropdown: false,   // 控制下拉框显示
+      qwUserLoading: false,        // 加载状态
+      qwUserNoMore: false,         // 是否还有更多数据
+      qwUserPageNum: 1,            // 当前页码
+      qwUserPageSize: 10,          // 每页数量
+      qwUserTotal: 0,               // 总数
+      isBindMiniOptions:[
+        {dictLabel:"已绑定",dictValue:'isBindMini'},
+        {dictLabel:"未绑定",dictValue:'noBindMini'},
+      ],
+      //标签弹窗选择
+      tagChange:{
+        open:false,
+        index:null,
+      },
+	  sTime:null,
+	  eTime:null,
+	  createTime:null,
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      tagOpen:false,
+      tagDelOpen:false,
+      // 选中数组
+      ids: [],
+      isBindActiveName:"all",
+      remarkMobiles: [],
+      inputVisible: false,
+      inputValue: '',
+      // 非单个禁用
+      single: true,
+      tagGroupList: [],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业微信客户表格数据
+      externalContactList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 用户类别字典
+      typeOptions: [],
+      ratingType: [],
+      ratingUpFall: [],
+      // 性别字典
+      genderOptions: [],
+
+      addTagForm:{
+        userIds:[],
+        tagIds:[]
+      },
+
+      myQwCompanyList:[],
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+
+      //存储选择的客户
+      chooseCustomerSOP:null,
+
+      setSop:{
+        title:"选择课节SOP",
+        open:false,
+        //区分单选1还是多选2
+        type:null,
+      },
+      //合成的客户-课节SOP参数
+      customerCourseForm:{},
+
+      //查询是否已经设置过客户-某个课节的SOP
+      customerCourseFormLogs:{},
+      //绑定客户
+      bindCustomer:{
+        title:null,
+        open:false,
+      },
+      callOpen:{
+        open:false,
+        title: '修改客户称呼',
+      },
+      callOpenFrom:{
+        id:null,
+        stageStatus:null,
+      },
+      callOpenRule:{
+        stageStatus:[{required:true,message:"员工称呼不能为空",trigger:"blur"}]
+      },
+      //绑定的参数表
+      qwFormCustomer:{
+        externalContactId:null,
+        customerId:null,
+      },
+      // 来源字典
+      addWayOptions: [],
+
+      //标签
+      changeTagDialog:{
+        title:"",
+        open:false,
+      },
+
+      queryTagParams:{
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+        corpId:null,
+      },
+
+      tagTotal:0,
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        qwUserName:null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        qwUserId:null,
+        gender: null,
+        description: null,
+        tagIds: null,
+        remark:null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        status:null,
+        transferStatus:null,
+        isBind:null,
+        isBindMini:null,
+        lossTime:null,
+        sTime:null,
+        eTime:null,
+        createTime:null,
+        level:null,
+        wayId:null,
+        levelType:null,
+        companyUser:null
+      },
+      selectTags:[],
+      // 表单参数
+      form: {},
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+
+    this.getDicts("sys_qw_externalContact_type").then(response => {
+      this.typeOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_type").then(response => {
+      this.ratingType = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_upFall").then(response => {
+      this.ratingUpFall = response.data;
+    });
+
+
+    getMyQwCompanyList().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              // this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              //
+              // var listTagFrom={corpId:this.queryParams.corpId}
+              // listTag(listTagFrom).then(response => {
+              //   this.tagList = response.rows;
+              // });
+              this.getList();
+
+            }
+    });
+
+
+    this.getDicts("sys_sex").then(response => {
+      this.genderOptions = response.data;
+    });
+    this.getDicts("sys_qw_externalContact_addWay").then(response => {
+      this.addWayOptions = response.data;
+    });
+
+
+
+    this.getDicts("sys_qw_external_contact_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_qw_transfer_status").then(response => {
+      this.transferStatusOptions = response.data;
+    });
+
+  },
+  methods: {
+    handleMemberdetails(row){
+            this.show.open=true;
+            setTimeout(() => {
+                 this.$refs.userDetails.getDetails(row.fsUserId);
+            }, 1);
+    },
+    onQwUserNameClear() {
+      this.queryParams.qwUserId = null;  // 同时清空 qwUserId
+    },
+    // 搜索企微用户
+    searchQwUser(query) {
+      if (!query.trim()) {
+        this.qwUserSuggestions = [];
+        this.showQwUserDropdown = false;
+        this.qwUserNoMore = false;
+        this.qwUserPageNum = 1;
+        return;
+      }
+
+      this.queryParams.qwUserName = query;
+      this.qwUserPageNum = 1;
+      this.qwUserNoMore = false;
+      this.qwUserSuggestions = [];
+      this.fetchQwUsers(query);
+    },
+
+    fetchQwUsers(query) {
+      const params = {
+        qwUserName: query,
+        pageNum: this.qwUserPageNum,
+        pageSize: this.qwUserPageSize
+      };
+
+      this.qwUserLoading = true;
+
+      getQwUserListLikeName(params).then(res => {
+        const list = res.data.list || [];
+        const total = res.data.total || 0;
+
+        this.qwUserSuggestions = [...this.qwUserSuggestions, ...list];
+        this.qwUserTotal = total;
+
+        // 判断是否还有更多数据
+        if (this.qwUserSuggestions.length >= total) {
+          this.qwUserNoMore = true;
+        }
+
+        this.showQwUserDropdown = true;
+      }).finally(() => {
+        this.qwUserLoading = false;
+      });
+    },
+
+    // 选择企微用户
+    selectQwUser(key,value) {
+      this.queryParams.qwUserName = value;
+      this.queryParams.qwUserId = key;
+      this.showQwUserDropdown = false;
+      this.handleQuery(); // 可选:自动触发查询
+    },
+
+    // 延迟隐藏下拉框,防止点击失效
+    hideDropdownWithDelay() {
+      setTimeout(() => {
+        this.showQwUserDropdown = false;
+      }, 200);
+    },
+    handleScroll(e) {
+      const container = e.target;
+      const scrollTop = container.scrollTop;
+      const scrollHeight = container.scrollHeight;
+      const clientHeight = container.clientHeight;
+
+      // 距离底部小于 20px 触发加载
+      if (scrollHeight - scrollTop - clientHeight < 20 && !this.qwUserLoading && !this.qwUserNoMore) {
+        this.qwUserPageNum += 1;
+        this.fetchQwUsers(this.queryParams.qwUserName);
+      }
+    },
+
+
+	  change(){
+			if(this.createTime!=null){
+			  this.queryParams.sTime=this.createTime[0];
+			  this.queryParams.eTime=this.createTime[1];
+			}else{
+			  this.queryParams.sTime=null;
+			  this.queryParams.eTime=null;
+			}
+
+		  },
+    updateCorpId(){
+      var listTagFrom={corpId:this.queryParams.corpId}
+        listTag(listTagFrom).then(response => {
+          this.tagList = response.rows;
+        });
+        this.getList();
+     },
+    /** 查询企业微信客户列表 */
+    getList() {
+      this.loading = true;
+      const { qwUserName, ...queryParams } = this.queryParams;
+      listExternalContact(queryParams).then(response => {
+        this.externalContactList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    bindMiniCustomerId(row){
+      console.log(row)
+      this.userForm.fsUserId=row;
+      bindUserId(this.userForm).then(res=>{
+         if (res.code==200){
+           this.$message.success('绑定成功')
+         }else {
+           this.$message.error('绑定失败:',res.msg)
+         }
+         this.getList()
+         this.user.open=false;
+      })
+    },
+    /** 查看客户详情 */
+    handleShow(row){
+      this.show.open=true;
+      var that=this;
+      const tab = "visit";
+      setTimeout(() => {
+        that.$refs.customerDetails.getDetails(row.customerId);
+        that.$refs.customerDetails.handleClick(tab);
+
+      }, 200);
+    },
+
+	handledetails(row){
+		this.info.open=true;
+		setTimeout(() => {
+			 this.$refs.Details.getDetails(row.id);
+		}, 1);
+	},
+
+	closeInfo(){
+		this.info.open=false
+	},
+    handleClickX(tab, event) {
+
+      this.queryParams.isBind=tab.name;
+      this.handleQuery();
+    },
+
+    handleClose(tag) {
+      this.remarkMobiles.splice(this.remarkMobiles.indexOf(tag), 1);
+    },
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick(_ => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.remarkMobiles.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = '';
+    },
+
+    addUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要添加标签的客户');
+      }
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+
+      this.tagOpen = true;
+
+    },
+
+
+    getPageListTagGroup(){
+      this.queryTagParams.corpId=this.queryParams.corpId
+      allListTagGroup(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+    },
+
+    delUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要移除标签的客户');
+      }
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+      this.tagDelOpen = true;
+
+    },
+
+
+    //搜索的标签
+    hangleChangeTags(){
+
+      this.changeTagDialog.title="搜索的标签"
+      this.changeTagDialog.open=true;
+
+      // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
+      const selectedTagIds = new Set(
+        (this.selectTags || []).map(tagItem => tagItem?.tagId)
+      );
+
+      this.queryTagParams.name=null;
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
+          }
+        }
+      }, 200);
+
+
+    },
+
+    //删除一些选择的标签
+    handleCloseTags(list){
+      const ls = this.selectTags.findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.selectTags.splice(ls, 1);
+        this.selectTags = [...this.selectTags];
+      }
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+    },
+
+    //重新获取页面数据
+    refreshList(){
+      this.getList();
+    },
+
+    //批量设置课程sop
+    setUserCourseSop(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要设置课程SOP的客户');
+      }
+
+      this.$confirm('批量设置客户课节SOP可能会存在重复,确定要批量设置吗?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+          this.setSop.open = true;
+          this.setSop.type = 2;
+        })
+        .catch(() => {
+          // 可以处理用户点击“取消”的逻辑
+        });
+
+    },
+    tagSelection(row){
+
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    addTagCancel() {
+
+      this.tagOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+
+    DelTagCancel() {
+      this.tagDelOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+    addTagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+
+      this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      addTag(this.addTagForm).then(response => {
+       this.msgSuccess(response.msg);
+       this.tagOpen = false;
+        loadingRock.close();
+       this.addTagForm={
+         userIds:[],
+         tagIds:[]
+       };
+       this.getList()
+     }).finally(res=>{
+        loadingRock.close();
+      });
+
+    },
+    tagDelSubmitForm(){
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+       this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      delTag(this.addTagForm).then(response => {
+       this.msgSuccess(response.msg);
+       this.tagDelOpen = false;
+        loadingRock.close();
+       this.addTagForm={
+         userIds:[],
+         tagIds:[]
+       };
+       this.getList()
+     }).finally(res=>{
+        loadingRock.close();
+      });
+    },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        externalUserId: null,
+        name: null,
+        companyUserId:null,
+        customerId:null,
+        avatar: null,
+        type: null,
+        gender: null,
+        remark: null,
+        description: null,
+        tagIds: null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        transferStatus:null,
+        status:null,
+        sTime:null,
+        eTime:null,
+        createTime:null,
+        transferTime:null,
+        transferNum:null,
+        lossTime:null,
+        delTime:null,
+        state:null,
+        wayId:null,
+        stageStatus:null,
+        customerName:null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    handleSearchTags(name){
+
+      if (!name){
+        return this.$message.error("请输入要搜索的标签")
+      }
+
+      this.queryTagParams.name=name;
+      this.queryTagParams.corpId=this.queryParams.corpId;
+
+      searchTags(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.total = response.total;
+      });
+
+    },
+
+    cancelSearchTags(){
+      this.resetSearchQueryTag()
+
+      this.getPageListTagGroup();
+    },
+    //确定选择标签
+    tagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if (this.tagGroupList[i].tag[x].isSelected === true) {
+
+            if (!this.selectTags) {
+              this.selectTags = [];
+            }
+
+            // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+            let tagExists = this.selectTags.some(
+              tag => tag.id === this.tagGroupList[i].tag[x].id
+            );
+
+            // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+            if (!tagExists) {
+              this.selectTags.push(this.tagGroupList[i].tag[x]);
+            }
+          }
+        }
+      }
+      if (!this.selectTags || this.selectTags.length === 0) {
+        return this.$message('请选择标签');
+      }
+
+      this.changeTagDialog.open = false;
+    },
+
+    //取消选择标签
+    tagCancel(){
+      this.changeTagDialog.open = false;
+    },
+
+
+    resetSearchQueryTag(){
+
+      this.queryTagParams= {
+        pageNum: 1,
+        pageSize: 10,
+        total:0,
+        name:null,
+      };
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue;
+      this.selectTags=[];
+	   this.createTime=null;
+	  this.queryParams.sTime=null;
+	  this.queryParams.eTime=null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.loading=true;
+      this.form.corpId=this.queryParams.corpId
+     addExternalContact(this.form).then(response => {
+       this.msgSuccess("同步成功");
+       this.getList();
+     }).finally(()=>{
+       this.loading=false;
+     });
+
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getExternalContact(id).then(response => {
+        this.form = response.data;
+        if(this.form.remarkMobiles!=null){
+          this.remarkMobiles=JSON.parse(this.form.remarkMobiles)
+        }else{
+          this.remarkMobiles=[]
+        }
+
+        this.open = true;
+        this.title = "修改企业微信客户";
+      });
+    },
+
+    handleAppellation(val){
+      this.callOpen.open=true;
+      this.callOpenFrom.stageStatus=val.stageStatus;
+      this.callOpenFrom.id=val.id;
+    },
+
+    /** 绑定客户操作 */
+    handleUpdateCustomer(row){
+       this.bindCustomer.title="绑定客户"
+        this.bindCustomer.open=true;
+        this.form.id=row.id
+        this.form.externalUserId=row.externalUserId
+        this.form.name=row.name
+    },
+
+    handleUpdateUser(row){
+        this.user.title="绑定客户"
+        this.user.open=true;
+        this.userForm.id=row.id;
+    },
+
+    handleUnBindUserId(val){
+
+      this.$confirm(
+        '确认解绑客户:<span style="color: green;">' + val.name + '' +
+        '</span> 的小程序用户?<br><span style="color: red;">【ps:可能会导致客户无法看课】</span>',
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        return unBindUserId(val.id);
+      }).then(response => {
+        this.getList();
+        this.msgSuccess("解绑成功");
+      }).finally(res=>{
+        this.getList();
+      })
+    },
+
+    bindCustomerId(row){
+
+      console.log("row",row)
+      // this.qwFormCustomer.customerId=row;
+      this.form.customerId=row;
+      this.form.corpId=this.queryParams.corpId;
+      this.msgWarning("绑定中.....同步信息中.....");
+
+      editbindCustomer(this.form).then(res=>{
+        //清空表单
+        this.reset();
+        this.bindCustomer.open = false;
+        this.msgSuccess("绑定成功");
+        this.getList();
+
+      })
+
+    },
+    //设置一个SOP
+    setCourseSOP(row) {
+
+      // 检查 row.miniUserId 是否为 null
+      if (row.miniUserId === null || row.miniUserId === undefined) {
+        return this.$confirm('当前客户【CRM客户详情】中 未绑定小程序客户,请先绑定', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).catch(error => {
+          this.msgWarning("操作取消:", error);
+        });
+      } else {
+        this.chooseCustomerSOP = row;
+        this.setSop.open = true;
+        this.setSop.type=1;
+      }
+    },
+
+    //选择课程SOP
+    // 用于设置 customerCourseForm 和 customerCourseFormLogs 的共同属性
+    setCommonProperties(form, row) {
+      form.qwUserid = this.chooseCustomerSOP.userId;
+      form.companyUserId = this.chooseCustomerSOP.companyUserId;
+      form.externalUserId = this.chooseCustomerSOP.externalUserId;
+      form.customerId = this.chooseCustomerSOP.customerId;
+      form.miniUserId = this.chooseCustomerSOP.miniUserId;
+      form.businessId = row.businessId;
+    },
+
+    bindCourseSop(row,days) {
+
+      if (this.setSop.type==2){
+        this.setSop.open = false;
+        this.loading=true;
+        this.msgWarning("设定中.....同步信息中.....");
+
+        setCustomerCourseSopList({ids:this.ids,fsCourseSopId:row.id,days:days}).then(res=>{
+
+          let msg=" 批量设置成功数【" + res.successNum + "】,<br>"
+
+          if (res.failCRM.length>0){
+            msg+="失败的客户【" + res.failCRM + "】,原因是未绑定CRM客户。<br>"
+          }
+          if (res.failMiNi.length>0){
+            msg+="失败的客户【" + res.failMiNi + "】,原因是CRM中未绑定小程序客户。<br>"
+          }
+          if (res.failCompany.length>0){
+            msg+="失败的客户【" + res.failCompany + "】,原因是客户没有所属成员。<br>"
+          }
+
+
+          return this.$confirm(msg, "提示", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+            dangerouslyUseHTMLString: true // 允许使用HTML标签
+          }).catch(error => {
+            this.msgSuccess("操作完成~");
+          });
+
+        }).finally(()=>{
+          this.loading = false;
+          this.getList();
+        })
+      }else if (this.setSop.type==1){
+
+      // 设置 customerCourseFormLogs 的属性
+      this.setCommonProperties(this.customerCourseFormLogs, row);
+
+      // 设置 customerCourseForm 的属性
+      this.setCommonProperties(this.customerCourseForm, row);
+      this.customerCourseForm.sopId = row.id;
+      this.customerCourseForm.sopType = row.sopType;
+      this.customerCourseForm.setting = row.setting;
+      this.customerCourseForm.days = days;
+
+      // 执行异步操作
+      getCustomerCourseSop(this.customerCourseFormLogs)
+        .then(res => {
+          if (res) {
+            return this.$confirm('当前客户已设置过相同课程课节SOP,确定还要再次设置吗?', "警告", {
+              confirmButtonText: "确定",
+              cancelButtonText: "取消",
+              type: "warning"
+            });
+          } else {
+            return Promise.resolve(); // 如果没有设置过,直接执行后续操作
+          }
+        })
+        .then(() => {
+          this.loading = true;
+          this.setSop.open = false;
+          this.msgSuccess("设定中.....同步信息中.....");
+
+          return setCustomerCourseSop(this.customerCourseForm);
+        })
+        .then(() => {
+          this.msgSuccess("设定成功");
+        })
+        .catch(error => {
+          this.msgWarning("操作取消:", error);
+        })
+        .finally(() => {
+          this.loading = false;
+          this.getList();
+        });
+      }
+    },
+    submitCallOpenFrom(){
+
+      this.$refs["callOpenFrom"].validate(valid => {
+        if (valid) {
+
+          if (this.callOpenFrom.id != null && this.callOpenFrom.stageStatus != null) {
+            updateExternalContactCall(this.callOpenFrom).then(res=>{
+              this.$message.success('修改成功');
+              this.callOpen.open=false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            this.form.remarkMobiles=JSON.stringify(this.remarkMobiles)
+            updateExternalContact(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addExternalContact(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企业微信客户编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delExternalContact(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+
+	updateTalk(row){
+		const ids = row.id || this.ids;
+		this.$confirm('是否确认批量更改用户信息为非首次交流', "警告", {
+		    confirmButtonText: "确定",
+		    cancelButtonText: "取消",
+		    type: "warning"
+		  }).then(function() {
+		    return editTalk(ids);
+		  }).then(() => {
+		    this.getList();
+		    this.msgSuccess("成功");
+		  }).catch(() => {});
+	},
+    /** 导出按钮操作 */
+    handleExport() {
+      const { qwUserName, ...queryParams } = this.queryParams;
+      this.$confirm('是否确认导出所有企业微信客户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportExternalContact(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    handleBatchUpdateNotesFilter() {
+      this.notesOpen.open = true;
+      this.notesOpen.filter = true;
+    },
+    handleBatchUpdateNotes() {
+
+      if (this.ids == null || this.ids == "") {
+        return this.$message('请选择需要添加备注的客户');
+      }
+
+      this.notesOpen.open = true;
+      this.notesOpen.filter = false;
+
+    },
+    notesSubmitForm() {
+
+      if (this.notesOpen.notes == null || this.notesOpen.notes == "") {
+        return this.$message.error("请输入备注内容");
+      }
+
+      // let loadingRock = this.$loading({
+      //   lock: true,
+      //   text: '正在执行中请稍后~~请不要刷新页面!!',
+      //   spinner: 'el-icon-loading',
+      //   background: 'rgba(0, 0, 0, 0.7)'
+      // });
+
+      let obj = JSON.parse(JSON.stringify(this.queryParams))
+      console.log(obj);
+      if(obj.tagIds !== null && obj.tagIds !== undefined && obj.tagIds !== ''){
+        obj.tagIds = obj.tagIds.split(",");
+      }
+      batchUpdateExternalContactNotes({
+        addType: 0,
+        userIds: this.ids,
+        notes: this.notesOpen.notes,
+        type: this.notesOpen.type,
+        nameType: this.notesOpen.nameType,
+        filter: this.notesOpen.filter,
+        param: obj
+      }).then(res => {
+
+        this.resultMessage = res.msg;
+        this.$message.success("正在执行中...");
+        // this.resultDialogVisible = true; // 显示弹窗
+        // this.resultTitle = '批量修改备注结果';
+
+      }).finally(res => {
+        this.getList();
+        // loadingRock.close();
+        this.notesCancel();
+      })
+
+    },
+  }
+};
+
+</script>
+<style scoped>
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+.tag-box {
+  padding: 8px 12px;
+  border: 1px solid #989797;
+  border-radius: 4px;
+  cursor: pointer;
+  display: inline-block;
+}
+
+.tag-selected {
+  background-color: #00bc98;
+  color: #fff;
+  border-color: #00bc98;
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+
+
+.button-new-tag {
+      margin-left: 10px;
+      height: 32px;
+      line-height: 30px;
+      padding-top: 0;
+      padding-bottom: 0;
+    }
+    .input-new-tag {
+      width: 90px;
+      margin-left: 10px;
+      vertical-align: bottom;
+    }
+
+
+.suggestion-box {
+  position: absolute;
+  z-index: 999;
+  background: #fff;
+  border: 1px solid #ddd;
+  max-height: 200px;
+  overflow-y: auto;
+  width: 100%;
+}
+
+.suggestion-item {
+  padding: 10px;
+  cursor: pointer;
+}
+.suggestion-item:hover {
+  background-color: #f5f7fa;
+}
+/* 新增的滚动容器样式(不影响原有样式) */
+.scroll-wrapper {
+  max-height: 130px; /* 大约三行的高度 */
+  overflow-y: auto;  /* 垂直滚动 */
+  padding-right: 5px; /* 为滚动条留出空间 */
+}
+
+/* 美化滚动条(可选) */
+.scroll-wrapper::-webkit-scrollbar {
+  width: 6px;
+}
+.scroll-wrapper::-webkit-scrollbar-thumb {
+  background: rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+}
+
+.tag-container {
+  max-height: 200px;
+  overflow-y: auto;
+  padding: 1px;
+  border: 1px solid #ebeef5;
+  border-radius: 1px;
+  background-color: #fafafa;
+}
+.tag-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.scroll-hint {
+  text-align: center;
+  color: #909399;
+  font-size: 12px;
+  padding: 1px 0;
+}
+.container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 10px;
+}
+.title {
+  text-align: center;
+  color: #303133;
+  margin-bottom: 30px;
+}
+.demo-table {
+  width: 100%;
+  margin-bottom: 30px;
+}
+.instructions {
+  background-color: #f5f7fa;
+  padding: 15px;
+  border-radius: 1px;
+  margin-bottom: 20px;
+}
+</style>

+ 1 - 0
src/views/fastGpt/fastGptExtUserTag/index.vue

@@ -279,6 +279,7 @@ export default {
 
       searchTags(this.queryTagParams).then(response => {
         this.tagGroupList = response.rows;
+        this.total = response.total;
       });
 
 

+ 259 - 0
src/views/fastGpt/fastGptPushTokenTotal/index.vue

@@ -0,0 +1,259 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="公司名称" prop="companyId" >
+        <el-select v-model="queryParams.companyId" placeholder="请选择所属公司" filterable size="small">
+          <el-option v-for="(option, index) in companyList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
+        </el-select>
+      </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="changeTime"></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="fastGptPushTokenTotalList" :row-class-name="() => 'fixed-bottom-row'"
+              @selection-change="handleSelectionChange" :max-height="600">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="公司名称" align="center" prop="companyName" />
+      <el-table-column label="token消耗" align="center" prop="count" />
+      <el-table-column label="时间" align="center" prop="statTime" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listFastgptEventLogTotal, exportFastgptEventLogTotal, getFastGptRoleAppKeyList} from "@/api/fastGpt/fastgptEventLogTotal";
+import { getFastGptPushTokenTotal} from "@/api/fastGpt/fastgptPushTokenTotal";
+import SelectTree from "@/components/TreeSelect/index.vue";
+import {getDeptData} from "@/api/system/employeeStats";
+import TreeSelect from '@riophae/vue-treeselect'
+import '@riophae/vue-treeselect/dist/vue-treeselect.css'
+import {allList} from "@/api/company/company";
+
+
+
+export default {
+  name: "FastgptEventLogTotal",
+  components: {SelectTree,TreeSelect},
+  data() {
+    return {
+      createTime:null,
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      selectedCompanyList: [],
+      companyList:[],
+      deptList: [],
+      companyUserList: [],
+      selectedAppKey: null,
+      selectedAppKeyLabel: '',
+      appKeyOptions: [],
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // token统计表格数据
+      fastGptPushTokenTotalList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      typeCountMap: null,
+      // 日志类型字典
+      typeOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        roleId: null,
+        count: null,
+        type: null,
+        companyId: null,
+        companyUserId: null,
+        qwUserId: null,
+        typeCountMap: null,
+        beginTime:null,
+        endTime:null,
+        appKey:null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getAllCompany();
+
+  },
+
+  methods: {
+    getAllCompany() {
+      allList().then(response => {
+        this.companyList = response.rows;
+        this.companyList.push({dictLabel: "无",
+          dictValue: "0"})
+      });
+    },
+    /** 查询ai事件埋点统计列表 */
+    getList() {
+      this.loading = true;
+
+      getFastGptPushTokenTotal(this.queryParams).then(response => {
+        console.log(response)
+        this.fastGptPushTokenTotalList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    normalizer(node) {
+      return {
+        id: node.id,
+        label: node.label,
+        children: node.children,
+        disabled: node.disabled
+      }
+    },
+    handleAppKeyChange(value) {
+      const node = this.findNodeById(this.appKeyOptions, value);
+      if (!node) {
+        this.selectedAppKeyLabel = '';
+        return;
+      }
+
+      // 如果是子节点,则找父节点 label
+      if (node.parentLabel) {
+        this.queryParams.appKey = node.parentLabel;
+        this.selectedAppKeyLabel = node.parentLabel;
+        this.selectedAppKey = this.selectedAppKeyLabel;
+      } else {
+        this.queryParams.appKey = node.label;
+        this.selectedAppKeyLabel = node.label;
+        this.selectedAppKey = this.selectedAppKeyLabel;
+      }
+    },
+    findNodeById(nodes, id) {
+      for (const node of nodes) {
+        if (node.id === id) return node;
+        if (node.children) {
+          const found = this.findNodeById(node.children, id);
+          if (found) return found;
+        }
+      }
+      return null;
+    },
+    changeTime(){
+      console.log(this.createTime);
+      if(this.createTime!=null){
+        this.queryParams.beginTime=this.createTime[0];
+        this.queryParams.endTime=this.createTime[1];
+      }else{
+        this.queryParams.beginTime=null;
+        this.queryParams.endTime=null;
+      }
+      console.log(this.queryParams.beginTime);
+      console.log(this.queryParams.endTime);
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        roleId: null,
+        count: null,
+        type: null,
+        companyId: null,
+        companyUserId: null,
+        qwUserId: null,
+        statTime: null
+      };
+      this.resetForm("form");
+    },
+    getPercentageColor(percentage) {
+      // HSL模式从黄色(60度)渐变到红色(0度)
+      const percent = Math.min(100, Math.max(0, parseFloat(percentage)));
+
+      // 调整色相范围:从深黄色(40°)渐变到红色(0°)
+      const hue = 40 - 40 * (percent / 100); // 初始 hue=40(深黄),终点 hue=0(红)
+
+      // 提高饱和度(100%),亮度保持 50%(鲜艳但不刺眼)
+      return `hsl(${hue}, 100%, 50%)`;
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      console.log(this.selectedAppKey)
+      if(this.selectedAppKey === null || typeof this.selectedAppKey === 'undefined'){
+        this.queryParams.appKey = null;
+      }
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.selectedAppKey = null;
+      this.selectedAppKeyLabel = '';
+      this.selectedCompanyList = [];
+      this.queryParams.appKey = null;
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
+      this.$confirm('是否确认导出所有ai事件埋点统计数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportFastgptEventLogTotal(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 20 - 4
src/views/fastGpt/fastgptEventLogTotal/index.vue

@@ -64,7 +64,7 @@
       <el-table-column label="角色名称" align="center" prop="roleName" />
       <el-table-column label="时间" align="center" prop="statTime" />
       <el-table-column
-        v-for="dict in typeOptions"
+        v-for="dict in sortedTypeOptions"
         :key="dict.dictValue"
         :label="dict.dictLabel"
         align="center">
@@ -72,9 +72,9 @@
           <span>{{ scope.row.typeCountMap ? scope.row.typeCountMap[dict.dictValue] : '' }}</span>
           <span v-if="dict.dictValue !== '11'"
                 :style="{ fontSize: '12px', marginLeft: '5px',
-                color: getPercentageColor((scope.row.typeCountMap[dict.dictValue] / scope.row.typeCountMap[2]) * 100) }">
-            ({{ ((scope.row.typeCountMap[dict.dictValue] / scope.row.typeCountMap[2]) * 100).toFixed(2) }}%)
-          </span>
+          color: getPercentageColor((scope.row.typeCountMap[dict.dictValue] / scope.row.typeCountMap[2]) * 100) }">
+      ({{ ((scope.row.typeCountMap[dict.dictValue] / scope.row.typeCountMap[2]) * 100).toFixed(2) }}%)
+    </span>
         </template>
       </el-table-column>
     </el-table>
@@ -179,6 +179,22 @@ export default {
     });
 
   },
+  // 在 data() 中添加一个新的计算属性或方法来处理排序后的 typeOptions
+  computed: {
+    sortedTypeOptions() {
+      if (!this.typeOptions || this.typeOptions.length === 0) return [];
+
+      // 将 dictValue 为 '11' 的选项过滤出来并放到最后
+      const normalOptions = this.typeOptions.filter(option => option.dictValue !== '11');
+      const lastOption = this.typeOptions.find(option => option.dictValue === '11');
+
+      if (lastOption) {
+        return [...normalOptions, lastOption];
+      }
+      return normalOptions;
+    }
+  },
+
   methods: {
     /** 查询ai事件埋点统计列表 */
     getList() {

+ 22 - 2
src/views/his/adv/index.vue

@@ -158,7 +158,7 @@
     />
 
     <!-- 添加或修改广告对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="90px">
         <el-form-item label="标题名称" prop="advTitle">
           <el-input v-model="form.advTitle" placeholder="请输入广告标题" />
@@ -202,6 +202,16 @@
        <el-form-item label="文章内容" v-show="form.showType==3">
          <editor ref="myeditor" @on-text-change="updateText" />
        </el-form-item>
+        <el-form-item label="活动" prop="activeId" v-show="form.showType === '5'">
+          <el-select v-model="form.activeId"  placeholder="请选择活动" >
+            <el-option
+              v-for="item in activeOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            ></el-option>
+          </el-select>
+        </el-form-item>
         <el-form-item label="状态">
           <el-radio-group v-model="form.status">
              <el-radio :label="item.dictValue" v-for="item in statusOptions" >{{item.dictLabel}}</el-radio>
@@ -220,6 +230,7 @@
 <script>
 import { listAdv, getAdv, delAdv, addAdv, updateAdv, exportAdv } from "@/api/his/adv";
 import Editor from '@/components/Editor/wang';
+import { getPromotionalActiveOption } from '@/api/his/promotionalActive'
 export default {
   name: "Adv",
   components: { Editor },
@@ -230,6 +241,7 @@ export default {
       showOptions: [],
       devOptions: [],
       statusOptions: [],
+      activeOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -296,8 +308,15 @@ export default {
     this.getDicts("sys_adv_type").then(response => {
       this.devOptions = response.data;
     });
+    this.getActiveOption()
   },
   methods: {
+    getActiveOption() {
+      getPromotionalActiveOption().then(response => {
+        console.log(response)
+        this.activeOptions = response.list;
+      });
+    },
     updateText(text){
         this.form.content=text
       },
@@ -345,7 +364,8 @@ export default {
         status: "0",
         sort: null,
         advType: null,
-        showType: null
+        showType: null,
+        activeId: null
       };
       this.resetForm("form");
     },

+ 3 - 0
src/views/his/aiDoctorChatSession/index.vue

@@ -275,6 +275,9 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.dateRange = [];
+      this.queryParams.beginTime=null;
+      this.queryParams.endTime=null;
       this.resetForm("queryForm");
       this.handleQuery();
     },

+ 525 - 0
src/views/his/answer/index.vue

@@ -0,0 +1,525 @@
+<template>
+  <div class="app-container">
+    <!-- <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form> -->
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
+          v-hasPermi="['his:answer:add']">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
+          v-hasPermi="['his:answer:edit']">修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
+          v-hasPermi="['his:answer:remove']">删除</el-button>
+      </el-col>
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['his:answer:export']"
+        >导出</el-button>
+      </el-col> -->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="answerList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="问答名称" align="center" prop="questionName" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+            v-hasPermi="['his:answer:edit']">修改</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+            v-hasPermi="['his:answer:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
+      @pagination="getList" />
+
+    <!-- 添加或修改问答对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+        <el-form-item label="问答名称" prop="questionName">
+          <el-input v-model="form.questionName" placeholder="请输入内容" />
+        </el-form-item>
+        <div v-if="form.answers && form.answers.length == 0" class="empty-state">
+          <div class="empty-state-icon">
+            <i class="el-icon-document"></i>
+          </div>
+          <p>暂无问题,请点击下方按钮添加</p>
+        </div>
+
+        <div v-for="(answer, index) in form.answers" :key="index" class="answer-section">
+          <div class="answer-section-header">
+            <span class="answer-section-title">
+              <span class="answer-section-number">{{ index + 1 }}</span>
+              问题 {{ index + 1 }}
+            </span>
+            <div>
+              <el-button 
+                v-if="index !== 0" 
+                type="danger" 
+                size="mini" 
+                icon="el-icon-delete"
+                @click="delItem(answer, index)">
+                删除问题
+              </el-button>
+            </div>
+          </div>
+          
+          <el-row :gutter="15">
+            <el-col :span="16">
+              <el-form-item label="问题标题" :prop="`answers[${index}].title`" :rules="rules.title">
+                <el-input v-model="answer.title" placeholder="请输入问题标题"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          
+          <el-form-item label="选项配置">
+            <div v-for="(option, optionIndex) in answer.options" :key="optionIndex" class="option-item">
+              <div class="option-input">
+                <el-input 
+                  v-model="answer.options[optionIndex].name" 
+                  :placeholder="`选项 ${optionIndex + 1}`">
+                </el-input>
+              </div>
+              <div class="option-actions">
+                <el-button 
+                  v-if="optionIndex + 1 === answer.options.length"
+                  type="primary" 
+                  size="mini" 
+                  icon="el-icon-plus"
+                  circle
+                  @click="addOption(index, optionIndex)">
+                </el-button>
+                <el-button 
+                  v-if="optionIndex !== 0"
+                  type="danger" 
+                  size="mini" 
+                  icon="el-icon-minus"
+                  circle
+                  @click="delOption(answer.options, optionIndex)">
+                </el-button>
+              </div>
+            </div>
+            <div class="option-tip">
+              <span>提示:至少保留一个选项,点击 + 按钮添加更多选项</span>
+            </div>
+          </el-form-item>
+        </div>
+        
+        <div class="add-section-btn">
+          <el-button 
+            type="primary" 
+            icon="el-icon-plus"
+            @click="addItem(form.answers.length)">
+            添加问题
+          </el-button>
+        </div>
+        
+        <!-- <div v-for="(i, index) in form.answers" :key="index">
+          <el-row>
+            <el-col :span="8">
+              <el-form-item label="标题" prop="title">
+                <el-input v-model="i.title"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-button style="margin: 5px;" v-if="index + 1 == form.answers.length"
+                @click="addItem(form.answers.length)" type="primary" size="mini">+</el-button>
+              <el-button style="margin: 5px;" v-if="index !== 0" type="danger" size="mini"
+                @click="delItem(i, index)">-</el-button>
+            </el-col>
+
+          </el-row>
+        </div> -->
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listAnswer, getAnswer, delAnswer, addAnswer, updateAnswer, exportAnswer } from "@/api/his/answer";
+
+export default {
+  name: "Answer",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 问答表格数据
+      answerList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        jsonInfo: null,
+      },
+      form: {
+            questionName: '',
+            answers: [
+              {
+                title: '',
+                options: [{name:'',value:0}]
+              }
+            ]
+          },
+          rules: {
+            questionName: [
+              { required: true, message: '请输入问答名称', trigger: 'blur' }
+            ],
+            title: [
+              { required: true, message: '请输入问题标题', trigger: 'blur' }
+            ]
+          }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    addItem(length) {
+          this.form.answers.push({
+            title: '',
+            options: [{name:'',value:0}]
+          })
+        },
+        delItem(item, index) {
+          if (this.form.answers.length > 1) {
+            this.$confirm('确定要删除这个问题吗?', '提示', {
+              confirmButtonText: '确定',
+              cancelButtonText: '取消',
+              type: 'warning'
+            }).then(() => {
+              this.form.answers.splice(index, 1)
+              this.$message({
+                type: 'success',
+                message: '删除成功!'
+              });
+            }).catch(() => {
+              this.$message({
+                type: 'info',
+                message: '已取消删除'
+              });          
+            });
+          } else {
+            this.$message.warning('至少保留一个问题')
+          }
+        },
+        addOption(answerIndex, optionIndex) {
+          this.form.answers[answerIndex].options.push({name:'',value:optionIndex + 1})
+        },
+        delOption(options, index) {
+          if (options.length > 1) {
+            this.$confirm('确定要删除这个选项吗?', '提示', {
+              confirmButtonText: '确定',
+              cancelButtonText: '取消',
+              type: 'warning'
+            }).then(() => {
+              options.splice(index, 1)
+              this.$message({
+                type: 'success',
+                message: '删除成功!'
+              });
+            }).catch(() => {
+              this.$message({
+                type: 'info',
+                message: '已取消删除'
+              });          
+            });
+          } else {
+            this.$message.warning('至少保留一个选项')
+          }
+        },
+    // addItem(length) {
+    //   this.form.answers.push({
+    //     title: '',
+    //     options: [],
+    //   })
+    // },
+    // delItem(item, index) {
+    //   this.form.answers.splice(index, 1)
+    // },
+    // addItem1(length,n) {
+    //   this.form.answers[n].options.push('')
+    // },
+    // delItem2(item, index) {
+    //   this.form.answers.splice(index, 1)
+    // },
+    /** 查询问答列表 */
+    getList() {
+      this.loading = true;
+      listAnswer(this.queryParams).then(response => {
+        this.answerList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        jsonInfo: null,
+        createTime: null,
+        updateTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加问答";
+      if (this.form.answers == null) {
+        this.form = {
+          answers: [{
+            title: '',
+            options: [{name:'',value:0}]
+          }
+
+          ]
+        }
+      }
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getAnswer(id).then(response => {
+        this.form = response.data;
+        if (this.form.answers == null) {
+          this.form = {
+            answers: [{
+              title: '',
+              options: [{name:'',value:0}]
+            }
+
+            ]
+          }
+        }
+        this.form.questionName = response.data.questionName;
+        this.form.id = response.data.id;
+        this.open = true;
+        this.title = "修改问答";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.answers) {
+            this.form.jsonInfo = JSON.stringify(this.form.answers);
+          }
+          if (this.form.id != null) {
+            updateAnswer(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addAnswer(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除问答编号为"' + ids + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return delAnswer(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有问答数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportAnswer(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => { });
+    }
+  }
+};
+</script>
+<style>
+    .form-container {
+      max-width: 900px;
+      margin: 30px auto;
+      padding: 25px;
+      background: #fff;
+      border-radius: 10px;
+      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+    }
+    .form-header {
+      margin-bottom: 25px;
+      padding-bottom: 15px;
+      border-bottom: 1px solid #ebeef5;
+    }
+    .form-header h2 {
+      margin: 0;
+      color: #303133;
+      font-size: 22px;
+    }
+    .form-header p {
+      margin: 8px 0 0;
+      color: #606266;
+      font-size: 14px;
+    }
+    .answer-section {
+      margin: 25px 0;
+      padding: 20px;
+      border: 1px solid #e6e9f0;
+      border-radius: 8px;
+      background-color: #f9fafc;
+      transition: all 0.3s ease;
+    }
+    .answer-section:hover {
+      border-color: #c0c4cc;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+    }
+    .answer-section-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 20px;
+      padding-bottom: 12px;
+      border-bottom: 1px dashed #dcdfe6;
+    }
+    .answer-section-title {
+      font-weight: 600;
+      color: #303133;
+      font-size: 16px;
+    }
+    .answer-section-number {
+      display: inline-flex;
+      align-items: center;
+      justify-content: center;
+      width: 24px;
+      height: 24px;
+      background: #409EFF;
+      color: white;
+      border-radius: 50%;
+      font-size: 12px;
+      margin-right: 8px;
+    }
+    .option-item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 12px;
+    }
+    .option-input {
+      flex: 1;
+    }
+    .option-actions {
+      margin-left: 10px;
+      display: flex;
+      gap: 5px;
+    }
+    .section-actions {
+      display: flex;
+      justify-content: flex-end;
+      margin-top: 20px;
+    }
+    .add-section-btn {
+      margin-top: 15px;
+      text-align: center;
+    }
+    .el-form-item {
+      margin-bottom: 20px;
+    }
+    .el-col {
+      padding-right: 15px;
+    }
+    .el-col:last-child {
+      padding-right: 0;
+    }
+    .option-tip {
+      margin-top: 10px;
+      color: #909399;
+      font-size: 12px;
+    }
+    .empty-state {
+      text-align: center;
+      padding: 30px;
+      color: #909399;
+    }
+    .empty-state-icon {
+      font-size: 48px;
+      margin-bottom: 15px;
+      color: #c0c4cc;
+    }
+  </style>
+

+ 4 - 6
src/views/his/article/index.vue

@@ -106,16 +106,14 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="封面图片" align="center" prop="imageUrl" width="120px">
            <template slot-scope="scope">
-                  <el-popover
-                    placement="right"
-                    title=""
-                    trigger="hover">
+                  <el-popover placement="right" title="" trigger="hover">
+                    <!--配置默认图片效果好些-->
                     <img slot="reference" :src="scope.row.imageUrl" width="100px">
                     <img :src="scope.row.imageUrl" style="max-width: 150px;">
                   </el-popover>
                 </template>
       </el-table-column>
-      <el-table-column label="标题" align="center" prop="title" show-overflow-tooltip width="170px" />
+      <el-table-column label="标题2" align="center" prop="title" show-overflow-tooltip width="170px" />
       <el-table-column label="分类名称" align="center" prop="cateName" width="120px" />
       <el-table-column label="浏览数" align="center" prop="views" />
       <el-table-column label="排序" align="center" prop="sort" />
@@ -133,7 +131,7 @@
       <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
       <el-table-column label="更新时间" align="center" prop="updateTime" width="180" />
 
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="150px">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
             size="mini"

+ 414 - 133
src/views/his/company/index.vue

@@ -94,6 +94,17 @@
         >导出
         </el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="multiple"
+          @click="handleMiniProgram"
+        >批量修改小程序
+        </el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -111,6 +122,7 @@
       </el-table-column>
 
       <el-table-column label="余额" align="center" prop="money"/>
+      <el-table-column label="红包余额" align="center" prop="redPackageMoney"/>
       <el-table-column label="企业类型" align="center" prop="companyType">
         <template slot-scope="scope">
           <dict-tag :options="companyTypeOptions" :value="scope.row.companyType"/>
@@ -118,9 +130,9 @@
       </el-table-column>
       <el-table-column label="管理员账号" align="center" prop="userName"/>
       <el-table-column label="限制用户数量" align="center" prop="limitUserCount"/>
-      <el-table-column label="限制pad数量" align="center" prop="maxPadNum" :formatter="padNumFormatter"/>
-      <el-table-column label="占用pad数量" align="center" prop="usedNum"/>
-      <el-table-column label="所属部门" align="center" prop="deptId">
+      <el-table-column label="限制pad数量" align="center" prop="maxPadNum" :formatter="padNumFormatter" v-if="this.$store.state.user.medicalMallConfig.resource"/>
+      <el-table-column label="占用pad数量" align="center" prop="usedNum" v-if="this.$store.state.user.medicalMallConfig.resource"/>
+      <el-table-column label="所属部门" align="center" prop="deptId" v-if="this.$store.state.user.medicalMallConfig.resource">
         <template slot-scope="scope">
           <el-tag prop="deptId" v-for="(item, index) in deptOptions" :key="'deptId'+index"
                   v-if="scope.row.deptId===item.deptId"
@@ -134,7 +146,7 @@
       <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
       <el-table-column label="更新时间" align="center" prop="updateTime" width="180"/>
       <!--      <el-table-column label="主机重启时间" align="center" prop="restartTime" width="180" />-->
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="300px">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="220px">
         <template slot-scope="scope">
           <el-button
             size="mini"
@@ -152,14 +164,6 @@
             v-hasPermi="['his:company:pass']"
           >重置密码
           </el-button>
-          <!-- 新增绑定店铺按钮 -->
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-shop"
-            @click="handleBindShop(scope.row)"
-            v-hasPermi="['company:company:bindShop']"
-          >绑定店铺</el-button>
           <el-button
             size="mini"
             type="text"
@@ -184,7 +188,29 @@
             v-hasPermi="['his:company:deduct']"
           >扣款
           </el-button>
-
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleRedRecharge(scope.row)"
+            v-hasPermi="['his:company:redRecharge']"
+          >红包充值
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleRedDeduct(scope.row)"
+            v-hasPermi="['his:company:redDeduct']"
+          >红包扣款
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleRevenue(scope.row)"
+            v-hasPermi="['company:company:revenue']"
+          >分账配置</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -197,38 +223,6 @@
       @pagination="getList"
     />
 
-    <!-- 绑定店铺对话框 -->
-    <el-dialog :title="bindShop.title" :visible.sync="bindShop.open" width="600px" append-to-body>
-      <el-form ref="bindShopForm" :rules="bindShopRules" :model="bindShopForm" label-width="100px">
-        <el-form-item label="公司名称">
-          <el-input v-model="bindShopForm.companyName" disabled />
-        </el-form-item>
-        <el-form-item label="选择店铺" prop="shopId">
-          <el-select
-            v-model="bindShopForm.shopId"
-            placeholder="请选择店铺"
-            filterable
-            clearable
-            style="width: 100%"
-            @change="handleShopChange"
-          >
-            <el-option
-              v-for="shop in shopList"
-              :key="shop.storeId"
-              :label="shop.storeName"
-              :value="shop.storeId"
-            >
-              <span style="float: left">{{ shop.storeName }}</span>
-              <span style="float: right; color: #8492a6; font-size: 13px">{{ shop.storeId }}</span>
-            </el-option>
-          </el-select>
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitBindShopForm" :loading="bindShop.submitLoading">确 定</el-button>
-        <el-button @click="bindShop.open=false">取 消</el-button>
-      </div>
-    </el-dialog>
     <!-- 添加或修改诊所管理对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
 
@@ -252,7 +246,7 @@
           </el-select>
         </el-form-item>
         <!-- 所属部门 -->
-        <el-form-item label="所属部门" prop="deptId">
+        <el-form-item label="所属部门" prop="deptId" v-if="this.$store.state.user.medicalMallConfig.resource">
           <el-select
             v-model="form.deptId"
             placeholder="请选择"
@@ -279,7 +273,7 @@
         <el-form-item label="员工数量" prop="limitUserCount">
           <el-input-number v-model="form.limitUserCount" :min="1" :max="10000"></el-input-number>
         </el-form-item>
-        <el-form-item label="pad数量" prop="maxPadNum">
+        <el-form-item label="pad数量" prop="maxPadNum" v-if="this.$store.state.user.medicalMallConfig.resource">
           <el-input-number v-model="form.maxPadNum" :min="-1" :max="10000"></el-input-number>
           <span class="pad-tips">
             注:-1表示不做限制
@@ -459,9 +453,6 @@
             />
           </el-select>
         </el-form-item>
-        <el-form-item label="PAD分配数量" prop="maxPadNum">
-          <el-input-number v-model="form.maxPadNum" placeholder="默认-1不限制"/>
-        </el-form-item>
         <el-form-item label="备注" prop="remark">
           <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注"/>
         </el-form-item>
@@ -496,6 +487,27 @@
       </div>
     </el-dialog>
 
+    <el-dialog :title="redRecharge.title" :visible.sync="redRecharge.open" width="500px" append-to-body>
+      <el-form ref="redRechargeForm" :rules="redRechargeRules" :model="redRechargeForm" label-width="80px">
+        <el-form-item label="公司">
+          <el-input v-model="redRechargeForm.companyName" disabled/>
+        </el-form-item>
+        <el-form-item label="余额">
+          <el-input v-model="redRechargeForm.balance" disabled/>
+        </el-form-item>
+        <el-form-item label="充值金额" prop="money">
+          <el-input-number v-model="redRechargeForm.money" :min="0.01" placeholder="请输入充值金额"/>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="redRechargeForm.remark" placeholder="请输入备注"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitRedRechargeForm" :disabled="redSubmit">确 定</el-button>
+        <el-button @click="redRecharge.open=false">取 消</el-button>
+      </div>
+    </el-dialog>
+
     <el-dialog :title="deduct.title" :visible.sync="deduct.open" width="500px" append-to-body>
       <el-form ref="deductForm" :rules="deductRules" :model="deductForm" label-width="80px">
         <el-form-item label="公司">
@@ -516,6 +528,183 @@
         <el-button @click="deduct.open=false">取 消</el-button>
       </div>
     </el-dialog>
+
+    <el-dialog :title="redDeduct.title" :visible.sync="redDeduct.open" width="500px" append-to-body>
+      <el-form ref="redDeductForm" :rules="redDeductRules" :model="redDeductForm" label-width="80px">
+        <el-form-item label="公司">
+          <el-input v-model="redDeductForm.companyName" disabled/>
+        </el-form-item>
+        <el-form-item label="余额">
+          <el-input v-model="redDeductForm.balance" disabled/>
+        </el-form-item>
+        <el-form-item label="扣款金额" prop="money">
+          <el-input-number v-model="redDeductForm.money" :min="0.01" placeholder="请输入扣款金额"/>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="redDeductForm.remark" placeholder="请输入备注"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitRedDeductForm">确 定</el-button>
+        <el-button @click="redDeduct.open=false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="revenue.title" :visible.sync="revenue.open" width="800px" append-to-body>
+      <el-form ref="revenueForm"  :model="revenueForm" label-width="150px">
+        <el-form-item label="公司">
+          <el-input v-model="revenueForm.companyName" disabled/>
+        </el-form-item>
+
+        <el-form-item label="开启分账">
+          <el-switch
+            v-model="revenueForm.divFlag"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            active-value="1"
+            inactive-value="0"
+          >
+          </el-switch>
+        </el-form-item>
+
+        <el-form-item label="分账模式" v-if="revenueForm.divFlag == 1">
+          <el-radio v-model="revenueForm.delayAcctFlag" label="N">实时分账</el-radio>
+          <el-radio v-model="revenueForm.delayAcctFlag" label="Y">延时分账</el-radio>
+        </el-form-item>
+        <el-form-item label="是否使用百分比分账" v-if="revenueForm.divFlag == 1">
+          <el-switch
+            v-model="revenueForm.percentageFlag"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            active-value="Y"
+            inactive-value="N"
+          >
+          </el-switch>
+        </el-form-item>
+        <el-form-item label="是否净值分账" v-if="revenueForm.percentageFlag == 'Y'">
+          <el-switch
+            v-model="revenueForm.iscCleanSplit"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            active-value="Y"
+            inactive-value="N"
+          >
+          </el-switch>
+        </el-form-item>
+        <div v-if="revenueForm.divFlag == 1">
+            <el-form-item label="分账接收方配置">
+              <el-tooltip content="批量设置分账接收账户" placement="top">
+                <el-button type="primary" icon="el-icon-plus" @click="addAcctInfo" style="margin-bottom: 5px;">
+                  添加新接收方
+                </el-button>
+              </el-tooltip>
+
+            </el-form-item>
+
+            <div v-for="(account, index) in revenueForm.acctInfos" :key="index"
+                 style="border: 1px solid #dcdfe6; padding: 20px; margin-bottom: 20px; border-radius: 4px;"
+            >
+              <div style="display: flex; justify-content: between; align-items: center; margin-bottom: 15px;">
+                <div style="margin: 0; color: #409eff;">账户 {{ index + 1 }}</div>
+                <el-button
+                  type="danger"
+                  icon="el-icon-delete"
+                  size="mini"
+                  @click="removeAcctInfo(index)"
+                  v-if="revenueForm.acctInfos.length > 0"
+                >
+                  删除账户
+                </el-button>
+              </div>
+
+              <el-form-item label="分账接收方ID" :prop="`acctInfos.${index}.huifuId`">
+                <el-input v-model="account.huifuId"   placeholder="斗拱开户时生成;示例值:6666000123120001"></el-input>
+              </el-form-item>
+              <el-form-item label="账户号" :prop="`acctInfos.${index}.acctId`" >
+                <el-input v-model="account.acctId"  placeholder="可指定账户号,仅支持基本户、现金户,不填默认为基本户;示例值:F00598600"></el-input>
+              </el-form-item>
+
+              <el-form-item label="分账百分比%" v-if="revenueForm.percentageFlag == 'Y'" :prop="`acctInfos.${index}.percentageDiv`"  >
+                <el-input-number v-model="account.percentageDiv" :precision="2" :step="0.1" :min="0" :max="100" placeholder="示例值:23.50,表示23.50%。acct_infos中全部分账百分比之和必须为100.00%。"></el-input-number>
+              </el-form-item>
+              <el-form-item label="分账金额" v-if="revenueForm.percentageFlag == 'N'" :prop="`acctInfos.${index}.divAmt`"  >
+                <el-input-number v-model="account.divAmt" :precision="2" :step="1" :min="0.01" placeholder="单位元,需保留小数点后两位,示例值:1.00 ,最低传入0.01"></el-input-number>
+              </el-form-item>
+
+            </div>
+          </div>
+
+
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitRevenueForm">确 定</el-button>
+        <el-button @click="revenue.open=false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 批量修改小程序 -->
+    <el-dialog :title="miniProgram.title" :visible.sync="miniProgram.open" width="700px" append-to-body>
+
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="小程序点播配置" prop="courseMiniAppId">
+          <el-select
+            v-model="form.courseMiniAppId"
+            placeholder="请选择小程序"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in miniAppList"
+              :key="item.appId"
+              :label="item.appName"
+              :value="item.appId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="主要小程序" prop="miniAppMaster">
+          <el-select
+            v-model="form.miniAppMaster"
+            multiple
+            :multiple-limit="1"
+            placeholder="请选择"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in miniAppList"
+              :key="item.appId"
+              :label="item.appName"
+              :value="item.appId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="备用小程序" prop="miniAppServer">
+          <el-select
+            v-model="form.miniAppServer"
+            multiple
+            :multiple-limit="1"
+            placeholder="请选择"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in miniAppList"
+              :key="item.appId"
+              :label="item.appName"
+              :value="item.appId"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitMiniProgramForm">确 定</el-button>
+        <el-button @click="cancelMiniProgram">取 消</el-button>
+      </div>
+    </el-dialog>
+
   </div>
 </template>
 
@@ -527,12 +716,14 @@ import {
   addCompany,
   updateCompany,
   recharge,
+  redRecharge,
   deduct,
+  redDeduct,
   exportCompany,
-  resetPwd
+  resetPwd,
+  getDivConfig,
+  setDiv, exitMiniProgram
 } from '@/api/his/company'
-import {bindShopCompany} from "@/api/company/company";
-import { storeList } from '@/api/hisStore/store'
 import { getFollowDoctorList } from '@/api/his/doctor'
 import { docList } from '@/api/his/doctor'
 import { getVoiceApiList } from '@/api/company/companyVoiceApi'
@@ -546,34 +737,33 @@ export default {
   name: 'Company',
   data() {
     return {
-      shopList: [], // 清空店铺列表
-      // 绑定店铺相关
-      bindShopForm: {
-        companyId: null,
-        shopId: null,
-        companyName: null,
-      },
-      bindShopRules: {
-        shopId: [
-          { required: true, message: "店铺不能为空", trigger: "blur" }
-        ]
+      redSubmit: false,
+      //分账参数
+      revenue:{
+          open: false,
+          title: '分账配置'
       },
-      bindShop: {
-        open: false,
-        title: "绑定店铺",
-        loading: false,
-        submitLoading: false
+      revenueForm:{
+        acctInfos: []
       },
       // 表单参数
       deductForm: {
         money: 0
       },
+      // 表单参数
+      redDeductForm: {
+        money: 0
+      },
       doctorIds: [],
       doctor: [],
       recharge: {
         open: false,
         title: '后台充值'
       },
+      redRecharge: {
+        open: false,
+        title: '红包充值'
+      },
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -616,6 +806,10 @@ export default {
       rechargeForm: {
         money: 0
       },
+      // 红包充值表单参数
+      redRechargeForm: {
+        money: 0
+      },
       followDoctorList: [],
       cateList: [],
       // 表单参数
@@ -687,22 +881,41 @@ export default {
           { required: true, message: '扣款金额不能为空', trigger: 'blur' }
         ]
       },
+      // 表单校验
+      redDeductRules: {
+        money: [
+          { required: true, message: '扣款金额不能为空', trigger: 'blur' }
+        ]
+      },
       rechargeRules: {
         money: [
           { required: true, message: '扣款金额不能为空', trigger: 'blur' }
         ]
       },
+      redRechargeRules: {
+        money: [
+          { required: true, message: '扣款金额不能为空', trigger: 'blur' }
+        ]
+      },
       deduct: {
         open: false,
         title: '后台扣款'
       },
+      redDeduct: {
+        open: false,
+        title: '红包扣款'
+      },
       maAppList: [],
       miniAppList: [],
-      customAppList: []
+      customAppList: [],
+      //分账参数
+      miniProgram:{
+        open: false,
+        title: '批量修改小程序'
+      },
     }
   },
   created() {
-    this.storeList();
     this.getList()
     this.getDicts('sys_company_status').then(response => {
       this.statusOptions = response.data
@@ -734,64 +947,49 @@ export default {
     })
   },
   methods: {
-
-    /** 店铺选择变化 */
-    handleShopChange(shopId) {
-      if (shopId) {
-        // 可以在这里获取选中店铺的详细信息
-        console.log('选中的店铺ID:', shopId);
-      }
-    },
-    /** 绑定店铺按钮操作 */
-    handleBindShop(row) {
-      this.resetBindShopForm();
-      this.bindShopForm.companyId = row.companyId;
-      this.bindShopForm.companyName = row.companyName;
-      this.bindShopForm.shopId = row.storeId ? String(row.storeId) : '';
-      this.bindShop.open = true;
+    // 添加分账账户
+    addAcctInfo() {
+      console.log("-----------------",this.revenueForm)
+      this.revenueForm.acctInfos.push({
+        huifuId: '',
+        acctId: '',
+        percentageDiv: null,
+        divAmt: null
+      })
     },
-    /** 重置绑定店铺表单 */
-    resetBindShopForm() {
-      this.bindShopForm = {
-        companyId: null,
-        companyName: '',
-        shopId: null,
-        shopName: '',
-        remark: ''
-      };
-      this.resetForm("bindShopForm");
+    // 删除接收方账户
+    removeAcctInfo(index) {
+      this.$confirm('确认删除该接收方账户?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.revenueForm.acctInfos.splice(index, 1)
+        this.$message.success('删除成功')
+      }).catch(() => {
+      })
     },
-    /** 提交绑定店铺表单 */
-    submitBindShopForm() {
-      this.$refs["bindShopForm"].validate(valid => {
-        if (valid) {
-          this.bindShop.submitLoading = true;
-          console.log( this.bindShopForm.companyId)
-          console.log( this.bindShopForm.shopId)
-          // 调用绑定店铺的API
-          bindShopCompany({
-            companyId: this.bindShopForm.companyId,
-            storeId: this.bindShopForm.shopId
-          }).then(response => {
-            if (response.code === 200) {
-              this.msgSuccess("绑定店铺成功");
-              this.bindShop.open = false;
-              this.getList(); // 刷新列表
-            } else {
-              this.msgError(response.msg);
-            }
-            this.bindShop.submitLoading = false;
-          }).catch(() => {
-            this.bindShop.submitLoading = false;
-          });
+    handleRevenue(row){
+      const companyId = row.companyId
+      //查询配置
+      this.revenueForm.isAdd = 1
+      getDivConfig(companyId).then(response => {
+        if(response.data){
+          this.revenueForm = response.data
+          if(response.data.acctInfos == null){
+            this.revenueForm.acctInfos = []
+          }
+          if(response.data.divFlag){
+            this.revenueForm.divFlag = String(response.data.divFlag)
+          }
         }
-      });
-    },
-    storeList() {
-      storeList().then(response => {
-        console.log(response.data)
-        this.shopList = response.data;
-      });
+      })
+      this.revenueForm.companyId = companyId
+      this.revenueForm.companyName = row.companyName
+      if(row.divFlag){
+        this.revenueForm.divFlag == "0"
+      }
+      this.revenue.open = true
     },
     handleRecharge(row) {
       const companyId = row.companyId
@@ -801,6 +999,15 @@ export default {
       this.rechargeForm.money = null
       this.recharge.open = true
     },
+    // 红包充值
+    handleRedRecharge(row) {
+      this.redSubmit=false
+      this.redRechargeForm.companyId = row.companyId
+      this.redRechargeForm.companyName = row.companyName
+      this.redRechargeForm.balance = row.money
+      this.redRechargeForm.money = null
+      this.redRecharge.open = true
+    },
     handleDeduct(row) {
       const companyId = row.companyId
       this.deductForm.companyId = row.companyId
@@ -809,6 +1016,13 @@ export default {
       this.deductForm.money = null
       this.deduct.open = true
     },
+    handleRedDeduct(row) {
+      this.redDeductForm.companyId = row.companyId
+      this.redDeductForm.companyName = row.companyName
+      this.redDeductForm.balance = row.money
+      this.redDeductForm.money = null
+      this.redDeduct.open = true
+    },
     /** 提交按钮 */
     submitRechargeForm() {
       this.$refs['rechargeForm'].validate(valid => {
@@ -823,6 +1037,35 @@ export default {
         }
       })
     },
+    /** 红包充值提交按钮 */
+    submitRedRechargeForm() {
+      this.$refs['redRechargeForm'].validate(valid => {
+        if (valid) {
+          this.redSubmit=true
+          redRecharge(this.redRechargeForm).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess(response.msg)
+              this.redRecharge.open = false
+              this.getList()
+            }
+          })
+        }
+      })
+    },
+    submitRevenueForm(){
+      var param = this.revenueForm;
+      console.log("--------------",param)
+      if(param.companyId && param.divFlag){
+        setDiv(param).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess(response.msg)
+              this.revenue.open = false
+              this.getList()
+            }
+          })
+        console.log("--------------",param)
+      }
+    },
     /** 提交按钮 */
     submitDeductForm() {
       this.$refs['deductForm'].validate(valid => {
@@ -837,6 +1080,20 @@ export default {
         }
       })
     },
+    /** 提交按钮 */
+    submitRedDeductForm() {
+      this.$refs['redDeductForm'].validate(valid => {
+        if (valid) {
+          redDeduct(this.redDeductForm).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess(response.msg)
+              this.redDeduct.open = false
+              this.getList()
+            }
+          })
+        }
+      })
+    },
 
     getList() {
       this.loading = true
@@ -917,17 +1174,17 @@ export default {
     /** 新增按钮操作 */
     handleAdd() {
       this.reset()
-      this.getAppList()
+      this.getAppList(null)
       this.open = true
       this.doctorIds = []
       this.title = '添加公司'
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
+      const companyId = row.companyId || this.ids
       this.reset()
-      this.getAppList()
+      this.getAppList(companyId)
       this.doctorIds = []
-      const companyId = row.companyId || this.ids
       getCompany(companyId).then(response => {
         this.form = response.data
         this.form.usedNum = row.usedNum
@@ -950,12 +1207,11 @@ export default {
         }
       })
     },
-    getAppList() {
+    getAppList(companyId) {
       this.maAppList = []
       this.miniAppList = []
       this.customAppList = []
-      const key = 'courseMa.config'
-      listAll(key).then(response => {
+      listAll().then(response => {
         const { code, data } = response
         if (code === 200) {
           if (data) {
@@ -1056,7 +1312,32 @@ export default {
     padNumFormatter(row){
       // console.log(row.maxPadNum.type)
       return row.maxPadNum === -1 ? '不限' : row.maxPadNum
-    }
+    },
+    handleMiniProgram() {
+      this.getAppList(null);
+      this.miniProgram.open = true;
+      this.form = {
+        ...this.form,
+        courseMiniAppId:null,
+        miniAppMaster: null,
+        miniAppServer: null
+      };
+    },
+    // 取消按钮
+    cancelMiniProgram() {
+      this.miniProgram.open = false;
+      this.reset()
+    },
+    submitMiniProgramForm(){
+      this.form.ids = this.ids;
+      exitMiniProgram(this.form).then(response => {
+        if (response.code === 200) {
+          this.miniProgram.open = false;
+          this.msgSuccess('修改小程序成功')
+          this.getList()
+        }
+      });
+    },
   }
 }
 </script>

+ 23 - 1
src/views/his/companyDeduct/index.vue

@@ -19,6 +19,16 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="业务类型" prop="businessType">
+        <el-select v-model="queryParams.businessType" placeholder="请选择支付类型" clearable size="small">
+          <el-option
+            v-for="dict in businessTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item label="创建时间" prop="createTime">
         <el-date-picker clearable size="small"
           v-model="queryParams.createTime"
@@ -59,6 +69,11 @@
       <el-table-column label="金额" align="center" prop="money" />
       <el-table-column label="余额" align="center" prop="balance" />
       <el-table-column label="提交人" align="center" prop="createUserNickName" />
+      <el-table-column label="业务类型" align="center" prop="businessType">
+        <template slot-scope="scope">
+          <dict-tag :options="businessTypeOptions" :value="scope.row.businessType"/>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" align="center" prop="isAudit">
         <template slot-scope="scope">
           <dict-tag :options="isAuditOptions" :value="scope.row.isAudit"/>
@@ -146,6 +161,8 @@ export default {
       open: false,
       // 审核状态字典
       isAuditOptions: [],
+      // 业务类型 0-普通 1-红包充值
+      businessTypeOptions:[],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -154,6 +171,7 @@ export default {
         companyName: null,
         createTime: null,
         isAudit: 0,
+        businessType:null, // 业务类型
       },
       // 表单参数
       form: {},
@@ -166,10 +184,13 @@ export default {
     };
   },
   created() {
-    this.getList();
     this.getDicts("sys_company_isaudit").then(response => {
       this.isAuditOptions = response.data;
     });
+    this.getDicts("sys_company_deduct_business_type").then(response => {
+      this.businessTypeOptions = response.data;
+    });
+    this.getList();
   },
   methods: {
     /** 查询扣款管理列表 */
@@ -211,6 +232,7 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.queryParams.businessType=null;
       this.handleQuery();
     },
     // 多选框选中数据

+ 22 - 0
src/views/his/companyRecharge/index.vue

@@ -29,6 +29,16 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="业务类型" prop="businessType">
+        <el-select v-model="queryParams.businessType" placeholder="请选择支付类型" clearable size="small">
+          <el-option
+            v-for="dict in businessTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
           <el-option
@@ -90,6 +100,11 @@
           <dict-tag :options="payTypeOptions" :value="scope.row.payType"/>
         </template>
       </el-table-column>
+      <el-table-column label="业务类型" align="center" prop="businessType">
+        <template slot-scope="scope">
+          <dict-tag :options="businessTypeOptions" :value="scope.row.businessType"/>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" align="center" prop="isAudit">
         <template slot-scope="scope">
           <dict-tag :options="isAuditOptions" :value="scope.row.isAudit"/>
@@ -182,6 +197,8 @@ export default {
       statusOptions: [],
       // 支付类型 1微信 2支付宝 3人工转账字典
       payTypeOptions: [],
+      // 业务类型 0-普通 1-红包充值
+      businessTypeOptions:[],
       // 审核状态 0待审核 1已审核字典
       isAuditOptions: [],
       // 查询参数
@@ -193,6 +210,7 @@ export default {
         status: null,
         payType: null,
         isAudit: 0,
+        businessType:null, // 业务类型
       },
       // 表单参数
       form: {},
@@ -215,6 +233,9 @@ export default {
     this.getDicts("sys_company_isaudit").then(response => {
       this.isAuditOptions = response.data;
     });
+    this.getDicts("sys_company_pay_business_type").then(response => {
+      this.businessTypeOptions = response.data;
+    });
   },
   methods: {
     /** 查询充值管理列表 */
@@ -264,6 +285,7 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.queryParams.businessType=null;
       this.handleQuery();
     },
     // 多选框选中数据

+ 442 - 0
src/views/his/dfAccount/index.vue

@@ -0,0 +1,442 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="AppKey" prop="dfAppKey">
+        <el-input
+          v-model="queryParams.dfAppKey"
+          placeholder="请输入dfAppKey"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="Appsecret" prop="dfAppsecret">
+        <el-input
+          v-model="queryParams.dfAppsecret"
+          placeholder="请输入dfAppsecret"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="登录账号" prop="loginAccount">
+        <el-input
+          v-model="queryParams.loginAccount"
+          placeholder="请输入登录账号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+    
+      <el-form-item label="月结账号" prop="monthlyCard">
+        <el-input
+          v-model="queryParams.monthlyCard"
+          placeholder="请输入月结账号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="物流产品" prop="expressProductCode">
+        <el-select v-model="queryParams.expressProductCode" placeholder="请选择物流产品编码" clearable size="small">
+          <el-option
+            v-for="dict in expressOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="寄件人" prop="senderName">
+        <el-input
+          v-model="queryParams.senderName"
+          placeholder="请输入寄件人姓名"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      
+      
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['his:dfAccount:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['his:dfAccount:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['his:dfAccount:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['his:dfAccount:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="accountList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="key" align="center" prop="dfAppKey" />
+      <el-table-column label="secret" align="center" prop="dfAppsecret" />
+      <el-table-column label="登录账号" align="center" prop="loginAccount" />
+      <el-table-column label="回调地址" align="center" prop="callBackUrl" />
+      <el-table-column label="月结账号" align="center" prop="monthlyCard" />
+      <el-table-column label="物流产品" align="center" >
+        <template slot-scope="scope">
+          <dict-tag :options="expressOptions" :value="scope.row.expressProductCode"/>
+        </template>
+        </el-table-column>  
+      <el-table-column label="寄件人姓名" align="center" prop="senderName" />
+      <el-table-column label="寄件人手机" align="center" prop="senderPhone" />
+      <el-table-column label="寄件人省" align="center" prop="senderProvince" />
+      <el-table-column label="寄件人市" align="center" prop="senderCity" />
+      <el-table-column label="寄件人区" align="center" prop="senderDistrict" />
+      <el-table-column label="寄件人地址" align="center" prop="senderAddress" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['his:dfAccount:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:dfAccount:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改代服账户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="Key" prop="dfAppKey">
+          <el-input v-model="form.dfAppKey" placeholder="请输入dfAppKey" />
+        </el-form-item>
+        <el-form-item label="secret" prop="dfAppsecret">
+          <el-input v-model="form.dfAppsecret" placeholder="请输入dfAppsecret" />
+        </el-form-item>
+        <el-form-item label="登录账号" prop="loginAccount">
+          <el-input v-model="form.loginAccount" placeholder="请输入登录账号" />
+        </el-form-item>
+        <el-form-item label="回调地址" prop="callBackUrl">
+          <el-input v-model="form.callBackUrl" placeholder="请输入回调地址" />
+        </el-form-item>
+        <el-form-item label="月结账号" prop="monthlyCard">
+          <el-input v-model="form.monthlyCard" placeholder="请输入月结账号" />
+        </el-form-item>
+        <el-form-item label="物流产品" prop="expressProductCode">
+          <el-select v-model="form.expressProductCode" placeholder="请选择物流产品编码" clearable size="small">
+            <el-option
+              v-for="dict in expressOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="寄件姓名" prop="senderName">
+          <el-input v-model="form.senderName" placeholder="请输入寄件人姓名" />
+        </el-form-item>
+        <el-form-item label="寄件手机" prop="senderPhone">
+          <el-input v-model="form.senderPhone" placeholder="寄件人手机" />
+        </el-form-item>
+        <el-form-item label="省市区" prop="cityIds">
+          <el-cascader
+            placeholder="请选择寄件人省市区"
+            ref="citySelect"
+            v-model="form.cityIds"
+            :options="citys"
+            @change="handleCityChange()"
+          >
+          </el-cascader>
+        </el-form-item>
+        <el-form-item label="详细地址" prop="senderAddress">
+          <el-input v-model="form.senderAddress" placeholder="请输入寄件人地址" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listAccount, getAccount, delAccount, addAccount, updateAccount, exportAccount } from "@/api/his/dfAccount";
+import { getCitys } from '@/api/store/city'
+export default {
+  name: "Account",
+  data() {
+    return {
+      citys: [],
+      expressOptions:[],//物流产品编码
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 代服账户表格数据
+      accountList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        dfAppKey: null,
+        dfAppsecret: null,
+        loginAccount: null,
+        callBackUrl: null,
+        monthlyCard: null,
+        expressProductCode: null,
+        senderName: null,
+        senderPhone: null,
+        senderProvince: null,
+        senderCity: null,
+        senderDistrict: null,
+        senderAddress: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        dfAppKey: [
+          { required: true, message: "key不能为空", trigger: "blur" }
+        ],
+        dfAppsecret: [
+          { required: true, message: "secret不能为空", trigger: "blur" }
+        ],
+        loginAccount: [
+          { required: true, message: "登录账户不能为空", trigger: "blur" }
+        ],
+        callBackUrl: [
+          { required: true, message: "回调地址不能为空", trigger: "blur" }
+        ],
+        monthlyCard: [
+          { required: true, message: "月结账户不能为空", trigger: "blur" }
+        ],
+        expressProductCode: [
+          { required: true, message: "物流产品不能为空", trigger: "blur" }
+        ],
+        senderName: [
+          { required: true, message: "寄件人不能为空", trigger: "blur" }
+        ],
+        senderPhone: [
+          { required: true, message: "寄件人电话不能为空", trigger: "blur" }
+        ],
+        cityIds: [
+          { required: true, message: "省市区不能为空", trigger: "blur" }
+        ],
+        senderAddress: [
+          { required: true, message: "详细地址不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getCitys();
+    this.getDicts("df_account_express").then(response => {
+      this.expressOptions = response.data;
+    });
+    this.getList();
+  },
+  methods: {
+    handleCityChange() {
+      var nodes = this.$refs.citySelect.getCheckedNodes()
+      this.form.senderProvince = nodes[0].pathLabels[0]
+      this.form.senderCity = nodes[0].pathLabels[1]
+      this.form.senderDistrict = nodes[0].pathLabels[2]
+    },
+    getCitys() {
+      getCitys().then(res => {
+        this.loading = false
+        this.citys = res.data
+      })
+    },
+    /** 查询代服账户列表 */
+    getList() {
+      this.loading = true;
+      listAccount(this.queryParams).then(response => {
+        this.accountList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        dfAppKey: null,
+        dfAppsecret: null,
+        loginAccount: null,
+        callBackUrl: null,
+        monthlyCard: null,
+        expressProductCode: null,
+        senderName: null,
+        senderPhone: null,
+        senderProvince: null,
+        senderCity: null,
+        senderDistrict: null,
+        senderAddress: null,
+        createTime: null,
+        updateTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加代服账户";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getAccount(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改代服账户";
+        this.form.cityIds = JSON.parse(response.data.cityIds)
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.cityIds = JSON.stringify(this.form.cityIds)
+          if (this.form.id != null) {
+            updateAccount(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addAccount(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除代服账户编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delAccount(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有代服账户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportAccount(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 378 - 0
src/views/his/divItem/index.vue

@@ -0,0 +1,378 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="85px">
+      <el-form-item label="订单号" prop="orderCode">
+        <el-input
+          v-model="queryParams.orderCode"
+          placeholder="请输入订单编号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="支付订单号" prop="payCode">
+        <el-input
+          v-model="queryParams.payCode"
+          placeholder="请输入支付订单号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择" @keyup.enter.native="handleQuery" size="small">
+          <el-option
+            v-for="item in options"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="延迟分账" prop="isDelay">
+        <el-select v-model="queryParams.isDelay" placeholder="请选择" @keyup.enter.native="handleQuery" size="small">
+          <el-option
+            v-for="item in delayOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['his:divItem:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['his:divItem:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['his:divItem:remove']"
+        >删除</el-button>
+      </el-col> -->
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['his:divItem:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="divItemList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="订单编号" align="center" prop="orderCode" />
+      <el-table-column label="支付订单号" align="center" prop="payCode" />
+      <el-table-column label="支付状态" align="center" prop="isPay" >
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.isPay == 1">成功</el-tag>
+          <el-tag v-if="scope.row.isPay == 0">失败</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="延迟分账" align="center" prop="isDelay" >
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.isDelay == 1">是</el-tag>
+          <el-tag v-if="scope.row.isDelay == 0">否</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="分账明细" align="center" prop="detail" />
+      <el-table-column label="退款明细" align="center" prop="refundDetail" />
+      <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
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['his:divItem:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:divItem:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column> -->
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改分账明细对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="订单编号" prop="orderCode">
+          <el-input v-model="form.orderCode" placeholder="请输入订单编号" />
+        </el-form-item>
+        <el-form-item label="支付订单号" prop="payCode">
+          <el-input v-model="form.payCode" placeholder="请输入支付订单号" />
+        </el-form-item>
+        <el-form-item label="分账明细" prop="detail">
+          <el-input v-model="form.detail" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="是否支付成功 0否 1是" prop="isPay">
+          <el-input v-model="form.isPay" placeholder="请输入是否支付成功 0否 1是" />
+        </el-form-item>
+        <el-form-item label="是否延迟分账 0否 1是" prop="isDelay">
+          <el-input v-model="form.isDelay" placeholder="请输入是否延迟分账 0否 1是" />
+        </el-form-item>
+        <el-form-item label="是否退款 0否 1是" prop="isRefund">
+          <el-input v-model="form.isRefund" placeholder="请输入是否退款 0否 1是" />
+        </el-form-item>
+        <el-form-item label="退款明细" prop="refundDetail">
+          <el-input v-model="form.refundDetail" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listDivItem, getDivItem, delDivItem, addDivItem, updateDivItem, exportDivItem } from "@/api/his/divItem";
+
+export default {
+  name: "DivItem",
+  data() {
+    return {
+      delayOptions:[
+      {
+          value:0,
+          label:"否"
+        },
+        {
+          value:1,
+          label:"是"
+        }
+      ],
+      options:[
+        {
+          value:1,
+          label:"支付"
+        },
+        {
+          value:0,
+          label:"退款"
+        }
+      ],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 分账明细表格数据
+      divItemList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        orderCode: null,
+        payCode: null,
+        detail: null,
+        isPay: null,
+        isDelay: 0,
+        isRefund: null,
+        refundDetail: null,
+        status:1
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        orderCode: [
+          { required: true, message: "订单编号不能为空", trigger: "blur" }
+        ],
+        payCode: [
+          { required: true, message: "支付订单号不能为空", trigger: "blur" }
+        ],
+        isPay: [
+          { required: true, message: "是否支付成功 0否 1是不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询分账明细列表 */
+    getList() {
+      this.loading = true;
+      var params = this.queryParams;
+      if(params.status == 1){
+        params.isPay = null;
+        params.isRefund = 0;
+      } else{
+        params.isPay = null;
+        params.isRefund = 1;
+      }
+      listDivItem(this.queryParams).then(response => {
+        this.divItemList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        orderCode: null,
+        payCode: null,
+        detail: null,
+        isPay: null,
+        isDelay: null,
+        isRefund: null,
+        createTime: null,
+        updateTime: null,
+        refundDetail: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加分账明细";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getDivItem(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改分账明细";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateDivItem(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addDivItem(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除分账明细编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delDivItem(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有分账明细数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportDivItem(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 30 - 2
src/views/his/doctor/type1.vue

@@ -485,7 +485,7 @@
                   </el-col>
             </el-row>
             <el-row>
-                  <el-col :span="24">
+                  <el-col :span="12">
                       <el-form-item label="身份证反面" prop="idCardBackUrl">
                         <el-upload id="sf"
                          v-model="form.idCardBackUrl"
@@ -499,6 +499,20 @@
                         </el-upload>
                       </el-form-item>
                   </el-col>
+                  <el-col :span="12">
+                      <el-form-item label="医生签名" prop="signUrl">
+                        <el-upload id="sign"
+                         v-model="form.signUrl"
+                         class="avatar-uploader"
+                         :action="bauploadUrl"
+                         :show-file-list="false"
+                         :on-success="signhandleAvatarSuccess"
+                         :before-upload="beforeAvatarUpload">
+                         <img v-if="form.signUrl" :src="form.signUrl" class="avatar" width="150px">
+                         <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+                        </el-upload>
+                      </el-form-item>
+                  </el-col>
             </el-row>
 
         <el-row>
@@ -635,7 +649,7 @@
          
          <el-row>
                <el-col :span="12">
-                 <el-form-item label="登录账号" prop="account" v-if="form.doctorId==null||form.doctorId==''">
+                 <el-form-item label="登录账号" prop="account" >
                    <el-input v-model="form.account" placeholder="请输入账号名称" />
                  </el-form-item>
                </el-col>
@@ -1084,6 +1098,15 @@ export default {
                   this.msgError(res.msg);
                 }
      },
+     signhandleAvatarSuccess(res, file) {
+                if(res.code==200){
+                  this.form.signUrl=res.url;
+                  this.$forceUpdate();
+                }
+                else{
+                  this.msgError(res.msg);
+                }
+     },
 
     handleAvatarSuccess(res, file) {
             if(res.code==200){
@@ -1483,6 +1506,11 @@ export default {
       min-height: 150px;
       display: block;
     }
+    #sign .avatar{
+      min-width: 120px;
+      min-height: 80px;
+      display: block;
+    }
     .avatar {
          min-width: 150px;
          min-height: 150px;

+ 30 - 2
src/views/his/doctor/type2.vue

@@ -396,7 +396,7 @@
                 </el-col>
           </el-row>
           <el-row>
-                <el-col :span="24">
+                <el-col :span="12">
                     <el-form-item label="身份证反面" prop="idCardBackUrl">
                        <el-upload
                                   v-model="form.idCardBackUrl"
@@ -410,6 +410,20 @@
                       </el-upload>
                     </el-form-item>
                 </el-col>
+                <el-col :span="12">
+                  <el-form-item label="医生签名" prop="signUrl">
+                    <el-upload id="sign"
+                               v-model="form.signUrl"
+                               class="avatar-uploader"
+                               :action="bauploadUrl"
+                               :show-file-list="false"
+                               :on-success="signhandleAvatarSuccess"
+                               :before-upload="beforeAvatarUpload">
+                      <img v-if="form.signUrl" :src="form.signUrl" class="avatar" width="150px">
+                      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+                    </el-upload>
+                  </el-form-item>
+                </el-col>
           </el-row>
 
       <el-row>
@@ -536,6 +550,7 @@ export default {
       certificateBack:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       practise:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       practiseBack:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      bauploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       orOptions: [],
       isauditOptions: [],
       positionOptions: [],
@@ -778,7 +793,15 @@ export default {
                   this.msgError(res.msg);
                 }
      },
-
+    signhandleAvatarSuccess(res, file) {
+      if(res.code==200){
+        this.form.signUrl=res.url;
+        this.$forceUpdate();
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
     handleAvatarSuccess(res, file) {
             if(res.code==200){
               this.form.certificateImages=res.url;
@@ -1124,4 +1147,9 @@ export default {
        line-height: 150px;
        text-align: center;
     }
+  #sign .avatar{
+    min-width: 120px;
+    min-height: 80px;
+    display: block;
+  }
 </style>

+ 7 - 10
src/views/his/hospital/index.vue

@@ -152,15 +152,12 @@
 
       <el-table-column label="医院照片" align="center" >
         <template slot-scope="scope">
-                <el-popover
-                  placement="right"
-                  title=""
-                  trigger="hover">
-                  <img slot="reference" :src="scope.row.imgUrl" width="60px">
-                  <img :src="scope.row.imgUrl" style="max-width: 250px;">
-                </el-popover>
-              </template>
-</el-table-column>
+          <el-popover placement="right" title="" trigger="hover">
+            <img slot="reference" :src="scope.row.imgUrl" width="60px">
+            <img :src="scope.row.imgUrl" style="max-width: 250px;">
+          </el-popover>
+        </template>
+      </el-table-column>
 
       <el-table-column label="省市区" align="center" prop="cityIds" width="150px">
                 <template slot-scope="scope">
@@ -188,7 +185,7 @@
       </el-table-column>
        <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="联系电话" align="center" prop="phone"  width="150px"/>
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150px" fixed="right">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
             size="mini"

+ 26 - 1
src/views/his/inquiryOrder/order1.vue

@@ -47,6 +47,17 @@
              @keyup.enter.native="handleQuery"
            />
        </el-form-item>
+       
+       <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+         <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+           <el-option
+             v-for="dict in appMallOptions"
+             :key="dict.id"
+             :label="dict.name + '(' + dict.appid + ')'"
+             :value="dict.id"
+           />
+         </el-select>
+       </el-form-item>
         <el-form-item label="问诊开始时间" prop="startTime">
            <el-date-picker v-model="startTime" 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>
@@ -101,6 +112,7 @@
       <el-table-column label="问诊标题" align="center" prop="title" show-overflow-tooltip />
       <el-table-column label="病人名称" align="center" prop="patientName" />
       <el-table-column label="医生名称" align="center" prop="doctorName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="状态" align="center" prop="status" >
         <template slot-scope="scope">
           <dict-tag :options="inquiryStatusOptions" :value="scope.row.status" />
@@ -198,6 +210,7 @@ import inquiryOrderDetails from '../../components/his/inquiryOrderDetails.vue';
 import msgDetails from '../../components/his/msgDetails.vue';
 import msgServiceDetails from '../../components/his/msgServiceDetails.vue';
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "inquiryOrder",
   components: { inquiryOrderDetails,msgDetails,msgServiceDetails },
@@ -275,6 +288,7 @@ export default {
         doctorName:null,
         patientName:null,
         sendName:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -286,6 +300,7 @@ export default {
       inquiryPayOptions:[],
       inquiryOrderOptions:[],
       orOptions:[],
+      appMallOptions:[],
     };
   },
 
@@ -308,6 +323,10 @@ export default {
       this.getDicts("sys_inquiry_sub_type").then(response => {
         this.inquirySubTypeOptions = response.data;
       });
+      
+      // 获取小程序选项列表
+      this.getAppMallOptions();
+      
     this.getList();
   },
   methods: {
@@ -543,7 +562,13 @@ export default {
 			},10000);
 		  }
         }).catch(() => {});
-    }
+    },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>

+ 25 - 1
src/views/his/inquiryOrder/order2.vue

@@ -37,6 +37,17 @@
       <el-form-item label="会员电话" prop="phone">
            <el-input v-model="queryParams.phone" placeholder="请输入会员电话"  clearable  size="small" @keyup.enter.native="handleQuery"/>
        </el-form-item>
+       
+       <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+         <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+           <el-option
+             v-for="dict in appMallOptions"
+             :key="dict.id"
+             :label="dict.name + '(' + dict.appid + ')'"
+             :value="dict.id"
+           />
+         </el-select>
+       </el-form-item>
 
 
 
@@ -94,6 +105,7 @@
       <el-table-column label="咨询标题" align="center" prop="title" show-overflow-tooltip />
       <el-table-column label="病人名称" align="center" prop="patientName" />
       <el-table-column label="医生名称" align="center" prop="doctorName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="员工" align="center" prop="companyUserName" />
       <el-table-column label="公司" align="center" prop="companyName" />
       <el-table-column label="状态" align="center" prop="status" >
@@ -193,6 +205,7 @@ import {allList}from "@/api/company/company";
 import inquiryOrderDetails from '../../components/his/inquiryOrderDetails.vue';
 import msgDetails from '../../components/his/msgDetails.vue';
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "ofast",
   components: { inquiryOrderDetails,msgDetails },
@@ -268,6 +281,7 @@ export default {
         phone:null,
         inquirySubType:null,
         companyUserName:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -281,6 +295,7 @@ export default {
       inquiryOrderOptions:[],
       inquirySubTypeOptions:[],
       orOptions:[],
+      appMallOptions:[],
     };
   },
   created() {
@@ -305,6 +320,9 @@ export default {
 
     this.getList();
     this.getAllCompany();
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
   },
   methods: {
     getMsg(row){
@@ -569,7 +587,13 @@ export default {
 		   },10000);
 		 }
         }).catch(() => {});
-    }
+    },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>

+ 27 - 0
src/views/his/inquiryOrder/order3.vue

@@ -49,6 +49,17 @@
            <el-input v-model="queryParams.phone" placeholder="请输入会员电话"  clearable  size="small" @keyup.enter.native="handleQuery"/>
        </el-form-item>
 
+      <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+        <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.id"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.id"
+          />
+        </el-select>
+      </el-form-item>
+
       <el-form-item label="订单类型" prop="orderType">
          <el-select v-model="queryParams.orderType" placeholder="状态" clearable size="small">
                  <el-option
@@ -155,6 +166,7 @@
 
       </el-table-column>
       <el-table-column label="科室名称" align="center" prop="deptName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="100px">
         <template slot-scope="scope">
        <el-button
@@ -200,11 +212,13 @@ import inquiryOrderDetails from '../../components/his/inquiryOrderDetails.vue';
 import msgDetails from '../../components/his/msgDetails.vue';
 import {allList}from "@/api/company/company";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "omedicine",
   components: { inquiryOrderDetails,msgDetails },
   data() {
     return {
+      appMallOptions: [],
       companyList:[],
       msgForm:{
           pageNum: 1,
@@ -274,6 +288,7 @@ export default {
         patientName:null,
         sendName:null,
         phone:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -286,6 +301,7 @@ export default {
       inquiryOrderOptions:[],
       inquirySubTypeOptions:[],
       orOptions:[],
+      appMallOptions:[],
     };
   },
   created() {
@@ -307,6 +323,10 @@ export default {
     this.getDicts("sys_inquiry_sub_type").then(response => {
       this.inquirySubTypeOptions = response.data;
     });
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
+    
     this.getList();
     this.getAllCompany();
   },
@@ -316,6 +336,12 @@ export default {
         this.companyList = response.rows;
       });
     },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     getMsg(row){
       const orderId = row.orderId;
       const doctorName = row.doctorName;
@@ -417,6 +443,7 @@ export default {
     this.startTime=null;
     this.queryParams.sTime=null;
     this.queryParams.eTime=null;
+    this.queryParams.coursePlaySourceConfigId=null;
     this.handleQuery();
   },
   change(){

+ 77 - 30
src/views/his/inquiryOrderReport/index.vue

@@ -1,10 +1,13 @@
 <template>
   <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="所属公司" prop="companyId" >
-      <el-select v-model="queryParams.companyId" placeholder="请选择所属公司" filterable size="small">
-            <el-option v-for="(option, index) in companyList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
-       </el-select>
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="所属公司" prop="companyId">
+        <el-select v-model="queryParams.companyId" placeholder="请选择所属公司" filterable clearable size="small">
+          <el-option v-for="(option, index) in companyList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="员工" prop="companyUserNickName">
+        <el-input v-model="queryParams.companyUserNickName" placeholder="请输入员工名称" clearable size="small" @keyup.enter.native="handleQuery"/>
       </el-form-item>
       <el-form-item label="订单号" prop="orderId">
         <el-input
@@ -15,8 +18,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-
-      <el-form-item label="报告编号" prop="reportSn" >
+      <el-form-item label="报告编号" prop="reportSn">
         <el-input
           v-model="queryParams.reportSn"
           placeholder="请输入报告编号"
@@ -26,14 +28,11 @@
         />
       </el-form-item>
       <el-form-item label="子类型" prop="inquirySubType">
-         <el-select v-model="queryParams.inquirySubType" placeholder="子类型" clearable size="small">
-            <el-option v-for="dict in inquirySubTypeOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
-         </el-select>
-      </el-form-item>
-      <el-form-item label="员工" prop="companyUserNickName">
-           <el-input  v-model="queryParams.companyUserNickName"  placeholder="请输入员工名称" clearable size="small" @keyup.enter.native="handleQuery"/>
+        <el-select v-model="queryParams.inquirySubType" placeholder="子类型" clearable size="small">
+          <el-option v-for="dict in inquirySubTypeOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+        </el-select>
       </el-form-item>
-      <el-form-item label="患者名称" prop="patientName" >
+      <el-form-item label="患者名称" prop="patientName">
         <el-input
           v-model="queryParams.patientName"
           placeholder="请输入患者名称"
@@ -42,7 +41,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="手机号" prop="patientMobile" >
+      <el-form-item label="手机号" prop="patientMobile">
         <el-input
           v-model="queryParams.patientMobile"
           placeholder="请输入手机号"
@@ -51,7 +50,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="导医" prop="userName" >
+      <el-form-item label="导医" prop="userName">
         <el-input
           v-model="queryParams.userName"
           placeholder="请输入导医"
@@ -60,7 +59,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="医生名称" prop="doctorName" >
+      <el-form-item label="医生名称" prop="doctorName">
         <el-input
           v-model="queryParams.doctorName"
           placeholder="请输医生名称"
@@ -70,21 +69,34 @@
         />
       </el-form-item>
       <el-form-item label="咨询状态" prop="inquiryStatus">
-         <el-select v-model="queryParams.inquiryStatus" placeholder="状态" clearable size="small">
-                 <el-option
-                   v-for="dict in inquiryStatusOptions"
-                   :key="dict.dictValue"
-                   :label="dict.dictLabel"
-                   :value="dict.dictValue"
-                 />
-               </el-select>
+        <el-select v-model="queryParams.inquiryStatus" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in inquiryStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      
+      <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+        <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.id"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.id"
+          />
+        </el-select>
       </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 label="提交时间" prop="createTime">
+        <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
       </el-form-item>
       <el-form-item label="首次分诊时间" prop="updateTime">
-          <el-date-picker v-model="updateTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
+        <el-date-picker v-model="updateTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
       </el-form-item>
+      
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@@ -119,6 +131,7 @@
       <el-table-column label="医生名称" align="center" prop="doctorName" />
       <el-table-column label="公司" align="center" prop="companyName" />
       <el-table-column label="员工" align="center" prop="companyUserName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="咨询结果" align="center" prop="inquiryResult" />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
@@ -368,6 +381,7 @@ import {listdocuser} from "@/api/his/doctor";
 import { getIllness } from "@/api/his/illnessLibrary";
 import {allList}from "@/api/company/company";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "InquiryOrderReport",
   components: { inquiryOrderReportDetails },
@@ -432,6 +446,7 @@ export default {
       inquiryStatusOptions:[],
       inquirySubTypeOptions:[],
       companyList:[],
+      appMallOptions:[],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -448,6 +463,7 @@ export default {
         userName: null,
         inquiryStatus:null,
         doctorName:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -479,6 +495,10 @@ export default {
     getBody().then(response => {
           this.body=response;
       });
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
+    
     this.getAllCompany();
   },
   methods: {
@@ -511,6 +531,12 @@ export default {
         this.companyList = response.rows;
       });
     },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     selectOK(rows){
 
       if(this.form.inquiryResult==null){
@@ -603,9 +629,14 @@ export default {
     resetQuery() {
       this.resetForm("queryForm");
       this.createTime=null;
+      this.updateTime=null;
       this.queryParams.sTime=null;
       this.queryParams.eTime=null;
-      this.inquiryStatus=null;
+      this.queryParams.beginTime=null;
+      this.queryParams.endTime=null;
+      this.queryParams.coursePlaySourceConfigId=null;
+      // 注意:不重置status,保持当前tab状态
+      // this.queryParams.status 保持不变
       this.handleQuery();
     },
     // 多选框选中数据
@@ -888,7 +919,23 @@ export default {
           },10000);
         }
         }).catch(() => {});
-    }
+    },
+    /** tab切换操作 */
+    handleClickX(tab, event) {
+      if(tab.name=="10"){
+        this.queryParams.status=null;
+      }else{
+        this.queryParams.status=tab.name;
+      }
+      this.handleQuery();
+    },
+    /** 查看详情操作 */
+    handledetails(row){
+      this.show.open=true;
+      setTimeout(() => {
+        this.$refs.Details.getDetails(row.reportId);
+      }, 1);
+    },
   }
 };
 </script>

+ 26 - 1
src/views/his/integralOrder/index.vue

@@ -147,6 +147,13 @@
              @click="handledetails(scope.row)"
              >详情
           </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              @click="cancelOrder(scope.row.orderCode)"
+              v-if="scope.row.status === '1'"
+            >取消订单
+            </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -256,7 +263,7 @@
 </template>
 
 <script>
-import {importTemplate, listIntegralOrder,importExpressTemplate, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder } from "@/api/his/integralOrder";
+import {importTemplate, listIntegralOrder,importExpressTemplate, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder,cancelOrder } from "@/api/his/integralOrder";
 import integralOrderDetails from '../../components/his/integralOrderDetails.vue';
 import { getToken } from "@/utils/auth";
 import {getCompanyList} from "@/api/company/company";
@@ -355,6 +362,24 @@ export default {
     });
   },
   methods: {
+     //取消订单
+     cancelOrder(orderCode){
+      this.$confirm('确定取消此订单?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        console.log("orderCode",orderCode)
+        cancelOrder(orderCode).then(()=>{
+          this.$message({
+            type: 'success',
+            message: '取消成功!'
+          });
+          this.getList();
+        })
+      }).catch(() => {
+      });
+    },
     change(){
           if(this.createTime!=null){
             this.queryParams.sTime=this.createTime[0];

+ 90 - 6
src/views/his/package/index.vue

@@ -91,6 +91,16 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="所属小程序" prop="appName" >
+        <el-select v-model="queryParams.appId" placeholder="请选择" clearable>
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.appid"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.appid"
+          />
+        </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>
@@ -152,6 +162,17 @@
 
               >导入</el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          :disabled="multiple"
+          @click="bulkCopy"
+          v-hasPermi="['his:package:bulkCopy']"
+        >批量复制</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -538,6 +559,26 @@
                   />
           </el-select>
         </el-form-item>
+        <el-form-item label="所属小程序" prop="appId">
+          <el-select v-model="appId" placeholder="请选择所属小程序" clearable size="small" multiple>
+            <el-option
+              v-for="dict in appMallOptions"
+              :key="dict.appid"
+              :label="dict.name + '(' + dict.appid + ')'"
+              :value="dict.appid"
+            />
+          </el-select>
+        </el-form-item>
+        <!-- <el-form-item label="问答" prop="questionId" >
+           <el-select v-model="form.questionId" placeholder="请选择问答">
+              <el-option
+                  v-for="dict in questionOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="parseInt(dict.dictValue)"
+                />
+           </el-select>
+        </el-form-item> -->
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -608,10 +649,21 @@
 </template>
 
 <script>
-import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportPackage,importTemplate,modifyPackages } from "@/api/his/package";
+import {
+  listPackage,
+  getPackage,
+  delPackage,
+  addPackage,
+  updatePackage,
+  exportPackage,
+  importTemplate,
+  modifyPackages,
+  bulkCopy
+} from "@/api/his/package";
 import {getAllFollowTempName } from "@/api/his/followTemp";
 import {getAllCateList} from "@/api/his/packageCate";
 import {allIcd } from "@/api/his/icd";
+// import {questionOptions } from "@/api/his/answer";
 import packageDetails from '../../components/his/packageDetails.vue';
 import productAttrValueSelect from "../../components/his/productAttrValueSelect.vue";
 import { listStore } from "@/api/his/storeProduct";
@@ -620,7 +672,8 @@ import { getToken } from "@/utils/auth";
 import Material from '@/components/Material'
 import ImageUpload from '@/components/ImageUpload'
 import { Loading } from 'element-ui';
-import { getOptions } from '@/api/his/packageSolarTerm'
+import { getOptions } from '@/api/his/packageSolarTerm';
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "Package",
   components: { packageDetails,Editor,productAttrValueSelect,Material },
@@ -634,6 +687,7 @@ export default {
   },
   data() {
     return {
+      appId:[],
       open1: false,
       form1:{},
       finalQuality:1,
@@ -659,6 +713,7 @@ export default {
               url: process.env.VUE_APP_BASE_API + "/his/package/importData"
             },
       productTypeOptions: [],
+      // questionOptions: [],
       storeId:null,
       storeOPtions:[],
       usageFrequencyUnitOptions:[{
@@ -718,6 +773,7 @@ export default {
       isDelOptions: [],
       packageSubTypeOptions:[],
       solarTermOptions: [],
+      appMallOptions:[],
       photoArr:[],
       // 查询参数
       queryParams: {
@@ -807,10 +863,14 @@ export default {
       this.privateTypeOptions = response.data.privateType;
     });
     this.getTemp();
-    this.getSolarTermOptions()
+    this.getSolarTermOptions(),
+    this.getAppMallOptions();
     listStore().then(response => {
       this.storeOPtions = response.rows;
     });
+    // questionOptions().then(res => {
+    //   this.questionOptions = res.rows;
+    // })
   },
   methods: {
     getSolarTermLabel(solarTerm) {
@@ -824,6 +884,11 @@ export default {
         this.solarTermOptions = response.data;
       })
     },
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     handleUpdateMore(row){
       this.reset1();
       this.title = "批量修改套餐状态";
@@ -1105,6 +1170,7 @@ export default {
         if(this.form.followNum!=null ){
           this.form.followNum=JSON.stringify(this.form.followNum)
         }
+        this.appId=this.form.appIds ? this.form.appIds.split(',') : [];
         setTimeout(() => {
                   if(this.form.desc==null){
                     this.$refs.myeditor.setText("");
@@ -1138,14 +1204,18 @@ export default {
             this.form.productJson=JSON.stringify(this.drugList)
           }
           this.form.describeJson = JSON.stringify(this.describeJson);
-          if (this.form.packageId != null) {
-            updatePackage(this.form).then(response => {
+          const params = {
+            ...this.form,
+            appIds: this.appId.join(',') // 数组转字符串
+          };
+          if (params.packageId != null) {
+            updatePackage(params).then(response => {
               this.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
-            addPackage(this.form).then(response => {
+            addPackage(params).then(response => {
               this.msgSuccess("新增成功");
               this.open = false;
               this.getList();
@@ -1247,6 +1317,20 @@ export default {
       });
     },
     /** 删除按钮操作 */
+    bulkCopy(row) {
+      const packageIds = row.packageId || this.ids;
+      this.$confirm('是否确认复制套餐包编号为"' + packageIds + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return bulkCopy(packageIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("批量复制成功");
+      }).catch(() => {});
+    },
+    /** 删除按钮操作 */
     handleDelete(row) {
       const packageIds = row.packageId || this.ids;
       this.$confirm('是否确认删除套餐包编号为"' + packageIds + '"的数据项?', "警告", {

+ 59 - 6
src/views/his/packageOrder/index.vue

@@ -109,6 +109,17 @@
         </el-select>
       </el-form-item>
 
+      <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+        <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.id"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.id"
+          />
+        </el-select>
+      </el-form-item>
+
       <el-form-item label="开始时间" prop="startTime">
         <el-date-picker v-model="startTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="startChange"></el-date-picker>
       </el-form-item>
@@ -146,6 +157,7 @@
       <el-table-column label="订单号" align="center" prop="orderSn" width="120px"/>
       <el-table-column label="所属公司" align="center" prop="companyName" />
       <el-table-column label="员工" align="center" prop="companyUserName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="套餐名称" align="center" prop="packageName" />
       <el-table-column label="套餐别名" align="center" prop="packageSecondName" width="100px"/>
       <el-table-column label="天数" align="center" prop="days" />
@@ -286,6 +298,7 @@ import { treeselect } from "@/api/company/companyDept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   watch: {
     // 监听deptId
@@ -309,6 +322,8 @@ export default {
       startTime:null,
       // 导出遮罩层
       exportLoading: false,
+      // 导出任务检查计数器
+      exportCheckCount: 0,
       // 选中数组
       ids: [],
       createTime:null,
@@ -336,6 +351,7 @@ export default {
       payTypeOptions:[],
       deliveryPayStatusOptions:[],
       deliveryStatusOptions:[],
+      appMallOptions:[],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -364,6 +380,7 @@ export default {
         companyName:null,
         deptId:null,
         source:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -406,6 +423,9 @@ export default {
     this.getDicts("sys_package_sub_type").then(response => {
       this.packageSubTypeOptions = response.data;
     });
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
   },
   methods: {
     /** 查询套餐订单列表 */
@@ -569,27 +589,54 @@ export default {
         this.exportLoading = true;
         return exportPackageOrder(queryParams);
       }).then(response => {
-       
-          if(response.code==200){
+        if(response.code==200){
           that.msgSuccess(response.msg);
           that.taskId=response.data;
+          that.exportCheckCount = 0; // 添加检查计数器
           that.time=setInterval(function(){
-            //查订单
+            that.exportCheckCount++;
+            //查任务状态
             getTask(that.taskId).then(res => {
+              // 任务完成
               if(res.data.status==1){
                 that.exportLoading = false;
-                clearTimeout(that.time)
+                clearInterval(that.time);
                 that.time=null;
                 that.download(res.data.fileUrl);
               }
+              // 任务失败
+              else if(res.data.status==-1 || res.data.status==2){
+                that.exportLoading = false;
+                clearInterval(that.time);
+                that.time=null;
+                that.msgError('导出任务失败,请重试');
+              }
+              // 超时处理(检查超过30次,即5分钟)
+              else if(that.exportCheckCount > 30){
+                that.exportLoading = false;
+                clearInterval(that.time);
+                that.time=null;
+                that.msgError('导出任务超时,请稍后重试');
+              }
+            }).catch(err => {
+              // API调用失败
+              that.exportCheckCount++;
+              if(that.exportCheckCount > 30){
+                that.exportLoading = false;
+                clearInterval(that.time);
+                that.time=null;
+                that.msgError('导出任务查询失败,请重试');
+              }
             });
-          },10000);
+          },10000); // 10秒查询一次
         }
         else{
           that.msgError(response.msg);
           that.exportLoading = false;
         }
-      }).catch(() => {});
+      }).catch(() => {
+        that.exportLoading = false;
+      });
     },
     /** 查询部门下拉树结构 */
     getTreeselect() {
@@ -611,6 +658,12 @@ export default {
       this.queryParams.deptId=val;
       this.getList();
     },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>

+ 147 - 0
src/views/his/promotionalActive/ChooseCourseVideoComponent.vue

@@ -0,0 +1,147 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="课程" prop="courseId">
+        <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" style="width: 100%" :value-key="'dictValue'">
+          <el-option
+            v-for="dict in courseList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="parseInt(dict.dictValue)"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table border v-loading="loading" :data="list" @selection-change="handleSelectionChange" ref="videoTable" :row-key="'videoId'" :reserve-selection="true">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="课程名称" align="center" prop="courseName" />
+      <el-table-column label="小节名称" align="center" prop="courseVideoName" />
+      <el-table-column label="视频名称" align="center" prop="videoName" />
+      <el-table-column label="时长" align="center" prop="duration"/>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <div class="footer-button">
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" @click="submit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { courseList } from '@/api/course/courseRedPacketLog'
+import { getChooseCourseVideoList } from '@/api/course/userCourseVideo'
+
+export default {
+  name: "ChooseCourseVideoComponent",
+  props: {
+    videoIds: {
+      type: Array,
+      default: () => []
+    }
+  },
+  activated() {
+    // keep-alive 激活时恢复选中
+    this.$nextTick(() => {
+      this.restoreSelection()
+    })
+  },
+  watch: {
+    // videoIds 变化时重新恢复选中
+    videoIds: {
+      immediate: false,
+      handler() {
+        this.$nextTick(() => this.restoreSelection())
+      }
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      showSearch: true,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        courseId: null
+      },
+      courseList: [],
+      total: 0,
+      list: [],
+      selected: []
+    }
+  },
+  created() {
+    courseList().then(response => {
+      this.courseList = response.list;
+    });
+    this.handleQuery()
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        courseId: null
+      }
+      this.handleQuery()
+    },
+    getList() {
+      this.loading = true
+      getChooseCourseVideoList(this.queryParams).then(response => {
+        this.list = response.data.list
+        this.total = response.data.total
+        this.loading = false
+        // 列表加载后,根据传入的 videoIds 自动选中
+        this.$nextTick(() => this.restoreSelection())
+      })
+    },
+    handleSelectionChange(selection) {
+      this.selected = selection
+    },
+    cancel() {
+      this.$emit('closeChoose')
+    },
+    submit() {
+      this.$emit('selectConfirm', this.selected)
+    },
+    // 恢复勾选状态
+    restoreSelection() {
+      const tableRef = this.$refs.videoTable
+      if (!tableRef || !Array.isArray(this.list) || !Array.isArray(this.videoIds)) return
+      tableRef.clearSelection()
+      if (this.videoIds.length === 0) return
+      const idsSet = new Set(this.videoIds)
+      this.list.forEach(row => {
+        if (row && idsSet.has(row.videoId)) {
+          tableRef.toggleRowSelection(row, true)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.footer-button {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 40px;
+}
+</style>

+ 213 - 0
src/views/his/promotionalActive/ChooseDoctorComponent.vue

@@ -0,0 +1,213 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="医生姓名" prop="doctorName">
+        <el-input
+          v-model="queryParams.doctorName"
+          placeholder="请输入医生姓名"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="所属医院" prop="hospitalId" >
+        <el-select v-model="queryParams.hospitalId" placeholder="请选择所属医院" clearable filterable size="small">
+          <el-option v-for="(option, index) in hospitalList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="科室" prop="deptId">
+        <el-select v-model="queryParams.deptId" placeholder="请选择所属科室" clearable size="small">
+          <el-option
+            v-for="dict in depList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="职称" prop="position">
+        <el-select v-model="queryParams.position" placeholder="职称" clearable size="small">
+          <el-option
+            v-for="dict in positionOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="手机号" prop="mobile">
+        <el-input
+          v-model="queryParams.mobile"
+          placeholder="请输入手机号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table border v-loading="loading" :data="list" @selection-change="handleSelectionChange" ref="doctorTable" :row-key="'doctorId'" :reserve-selection="true">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="医生名称" align="center" prop="doctorName"/>
+      <el-table-column label="所属医院" align="center" prop="hospitalName"/>
+      <el-table-column label="科室" align="center" prop="deptName"/>
+      <el-table-column label="职称" align="center" prop="position"/>
+      <el-table-column label="手机号" align="center" prop="mobile"/>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <div class="footer-button">
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" @click="submit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import{listDepartment} from "@/api/his/disease";
+import{listAllHospital} from "@/api/his/hospital";
+import { getChooseDoctorList } from '@/api/his/doctor'
+
+export default {
+  name: "ChooseDoctorComponent",
+  props: {
+    doctorIds: {
+      type: Array,
+      default: () => []
+    }
+  },
+  activated() {
+    // keep-alive 激活时恢复选中
+    this.$nextTick(() => {
+      this.restoreSelection()
+    })
+  },
+  watch: {
+    // doctorIds 变化时重新恢复选中
+    doctorIds: {
+      immediate: false,
+      handler() {
+        this.$nextTick(() => this.restoreSelection())
+      }
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        doctorName: null,
+        hospitalId: null,
+        deptId: null,
+        position: null,
+        mobile: null
+      },
+      //医院列表
+      hospitalList:[],
+      //科室列表
+      depList:[],
+      positionOptions: [],
+      // 总条数
+      total: 0,
+      // 课程列表
+      list: [],
+      selected: [],
+    }
+  },
+  created() {
+    this.getHospitaldeplist();
+    this.getdeplist();
+    this.getDicts("sys_doc_position").then(response => {
+      this.positionOptions = response.data;
+    });
+    this.handleQuery()
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        doctorName: null,
+        hospitalId: null,
+        deptId: null,
+        position: null,
+        mobile: null
+      }
+      this.handleQuery()
+    },
+    getList() {
+      this.loading = true
+      getChooseDoctorList(this.queryParams).then(response => {
+        this.list = response.data.list
+        this.total = response.data.total
+        this.loading = false
+        // 列表加载后,根据传入的 videoIds 自动选中
+        this.$nextTick(() => this.restoreSelection())
+      })
+    },
+    /** 查询医院列表 */
+    getHospitaldeplist() {
+      listAllHospital().then(response => {
+        this.hospitalList = response.rows;
+      });
+    },
+    /** 查询科室列表 */
+    getdeplist() {
+      listDepartment().then(response => {
+        this.depList = response.rows;
+      });
+    },
+    handleSelectionChange(selection) {
+      this.selected = selection
+    },
+    cancel() {
+      this.$emit('closeChoose')
+    },
+    submit() {
+      this.$emit('selectConfirm', this.selected)
+    },
+    // 恢复勾选状态
+    restoreSelection() {
+      const tableRef = this.$refs.doctorTable
+      if (!tableRef || !Array.isArray(this.list) || !Array.isArray(this.doctorIds)) return
+      tableRef.clearSelection()
+      if (this.doctorIds.length === 0) return
+      const idsSet = new Set(this.doctorIds)
+      this.list.forEach(row => {
+        if (row && idsSet.has(row.doctorId)) {
+          tableRef.toggleRowSelection(row, true)
+        }
+      })
+    }
+  },
+}
+</script>
+
+<style scoped>
+.footer-button {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 40px;
+}
+</style>

+ 176 - 0
src/views/his/promotionalActive/ChooseIntegralGoodsComponent.vue

@@ -0,0 +1,176 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="商品名称" prop="goodsName">
+        <el-input
+          v-model="queryParams.goodsName"
+          placeholder="请输入商品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="商品分类" prop="goodsType">
+        <el-select v-model="queryParams.goodsType" placeholder="请选择商品分类" clearable size="small">
+          <el-option
+            v-for="dict in goodsTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table border v-loading="loading" :data="list" @selection-change="handleSelectionChange" ref="integralGoodsTable" :row-key="'goodsId'" :reserve-selection="true">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="商品名称" align="center" prop="goodsName"/>
+      <el-table-column label="商品分类" align="center" prop="goodsTypeName"/>
+      <el-table-column label="封面图片" align="center" prop="goodsImg" width="120">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.goodsImg" width="100">
+            <img :src="scope.row.goodsImg" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="商品价格" align="center" prop="cash"/>
+      <el-table-column label="所需积分" align="center" prop="integral"/>
+      <el-table-column label="库存" align="center" prop="stock"/>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <div class="footer-button">
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" @click="submit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getChooseIntegralGoodsList } from '@/api/his/integralGoods'
+
+export default {
+  name: "ChooseIntegralGoodsComponent",
+  props: {
+    goodsIds: {
+      type: Array,
+      default: () => []
+    }
+  },
+  activated() {
+    // keep-alive 激活时恢复选中
+    this.$nextTick(() => {
+      this.restoreSelection()
+    })
+  },
+  watch: {
+    // goodsIds 变化时重新恢复选中
+    goodsIds: {
+      immediate: false,
+      handler() {
+        this.$nextTick(() => this.restoreSelection())
+      }
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        goodsName: null,
+        goodsType: null
+      },
+      // 商品分类字典
+      goodsTypeOptions: [],
+      // 总条数
+      total: 0,
+      // 数据
+      list: [],
+      selected: []
+    }
+  },
+  created() {
+    this.handleQuery();
+    this.getDicts("sys_integral_goods_type").then(response => {
+      this.goodsTypeOptions = response.data;
+    });
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        goodsName: null,
+        goodsType: null
+      };
+      this.handleQuery();
+    },
+    getList() {
+      this.loading = true
+      getChooseIntegralGoodsList(this.queryParams).then(response => {
+        this.list = response.data.list
+        this.total = response.data.total
+        this.loading = false
+        // 列表加载后,根据传入的 goodsIds 自动选中
+        this.$nextTick(() => this.restoreSelection())
+      })
+    },
+    handleSelectionChange(selection) {
+      this.selected = selection
+    },
+    cancel() {
+      this.$emit('closeChoose')
+    },
+    submit() {
+      this.$emit('selectConfirm', this.selected)
+    },
+    // 恢复勾选状态
+    restoreSelection() {
+      const tableRef = this.$refs.integralGoodsTable
+      if (!tableRef || !Array.isArray(this.list) || !Array.isArray(this.goodsIds)) return
+      tableRef.clearSelection()
+      if (this.goodsIds.length === 0) return
+      const idsSet = new Set(this.goodsIds)
+      this.list.forEach(row => {
+        if (row && idsSet.has(row.goodsId)) {
+          tableRef.toggleRowSelection(row, true)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.footer-button {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 40px;
+}
+</style>

+ 202 - 0
src/views/his/promotionalActive/ChoosePackageComponent.vue

@@ -0,0 +1,202 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
+      <el-form-item label="套餐包名称" prop="packageName">
+        <el-input
+          v-model="queryParams.packageName"
+          placeholder="请输入套餐包名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="套餐包别名" prop="secondName">
+        <el-input
+          v-model="queryParams.secondName"
+          placeholder="套餐包别名"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="套餐类型" prop="packageType">
+        <el-select v-model="queryParams.packageType" placeholder="请选择" clearable size="small">
+          <el-option
+            v-for="dict in packageTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="子类型" prop="packageSubType">
+        <el-select v-model="queryParams.packageSubType" placeholder="请选择子类型" clearable size="small">
+          <el-option
+            v-for="dict in packageSubTypeOptions"
+            :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-table border v-loading="loading" :data="list" @selection-change="handleSelectionChange" ref="packageTable" :row-key="'packageId'" :reserve-selection="true">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="封面图片" width="120" align="center">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.packageImg" width="100">
+            <img :src="scope.row.packageImg" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="套餐包名称" align="center" prop="packageName"/>
+      <el-table-column label="套餐包别名" align="center" prop="secondName"/>
+      <el-table-column label="套餐类型" align="center" prop="packageTypeName"/>
+      <el-table-column label="子类型" align="center" prop="packageSubTypeName"/>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <div class="footer-button">
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" @click="submit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getChoosePackageList } from '@/api/his/package'
+
+export default {
+  name: "ChoosePackageComponent",
+  props: {
+    packageIds: {
+      type: Array,
+      default: () => []
+    }
+  },
+  activated() {
+    // keep-alive 激活时恢复选中
+    this.$nextTick(() => {
+      this.restoreSelection()
+    })
+  },
+  watch: {
+    // packageIds 变化时重新恢复选中
+    packageIds: {
+      immediate: false,
+      handler() {
+        this.$nextTick(() => this.restoreSelection())
+      }
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 列表参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        packageName: null,
+        secondName: null,
+        packageType: null,
+        packageSubType: null,
+      },
+      // 套餐类型字典
+      packageTypeOptions: [],
+      // 子类型字典
+      packageSubTypeOptions: [],
+      // 总条数
+      total: 0,
+      // 表格数据
+      list: [],
+      selected: [],
+    }
+  },
+  created() {
+    this.getDicts("sys_package_type").then(response => {
+      this.packageTypeOptions = response.data;
+    });
+    this.getDicts("sys_package_sub_type").then(response => {
+      this.packageSubTypeOptions = response.data;
+    });
+    this.getList();
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        packageName: null,
+        secondName: null,
+        packageType: null,
+        packageSubType: null,
+      };
+      this.handleQuery();
+    },
+    getList() {
+      this.loading = true;
+      getChoosePackageList(this.queryParams).then(response => {
+        this.list = response.data.list
+        this.total = response.data.total
+        this.loading = false
+        // 列表加载后,根据传入的 packageIds 自动选中
+        this.$nextTick(() => this.restoreSelection())
+      })
+    },
+    handleSelectionChange(selection) {
+      this.selected = selection
+    },
+    cancel() {
+      this.$emit('closeChoose')
+    },
+    submit() {
+      this.$emit('selectConfirm', this.selected)
+    },
+    // 恢复勾选状态
+    restoreSelection() {
+      const tableRef = this.$refs.packageTable
+      if (!tableRef || !Array.isArray(this.list) || !Array.isArray(this.packageIds)) return
+      tableRef.clearSelection()
+      if (this.packageIds.length === 0) return
+      const idsSet = new Set(this.packageIds)
+      this.list.forEach(row => {
+        if (row && idsSet.has(row.packageId)) {
+          tableRef.toggleRowSelection(row, true)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.footer-button {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 40px;
+}
+</style>

+ 689 - 0
src/views/his/promotionalActive/index.vue

@@ -0,0 +1,689 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" @submit.native.prevent>
+      <el-form-item label="活动标题" prop="title">
+        <el-input v-model="queryParams.title"
+                  placeholder="请输入活动标题"
+                  clearable
+                  size="small"
+                  @keyup.enter.native="handleQuery" />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary"
+                   icon="el-icon-plus"
+                   size="mini"
+                   @click="handleAdd"
+                   v-has-permi="['his:promotionalActive:add']">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="success"
+                   icon="el-icon-edit"
+                   size="mini"
+                   :disabled="single"
+                   @click="handleUpdate"
+                   v-has-permi="['his:promotionalActive:edit']">修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="danger"
+                   icon="el-icon-delete"
+                   size="mini"
+                   :disabled="multiple"
+                   @click="handleDelete"
+                   v-has-permi="['his:promotionalActive:remove']">删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="活动标题" align="center" prop="title" width="200" />
+      <el-table-column label="活动主题" align="center" prop="theme" width="250" >
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.theme" style="max-height: 80px; width: auto;">
+            <img :src="scope.row.theme" style="max-width: 150px; max-height: 150px; width: auto;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="活动内容" align="center" prop="content">
+        <template slot-scope="scope">
+          <div v-if="scope.row.content">
+            <el-image
+              v-for="(img, index) in parseImages(scope.row.content)"
+              :key="index"
+              style="width: 50px; height: 50px; margin-right: 5px; margin-bottom: 5px;"
+              :src="img"
+              :preview-src-list="parseImages(scope.row.content)"
+              fit="cover">
+            </el-image>
+          </div>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="100" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
+        <template slot-scope="scope">
+          <el-button size="mini"
+                     type="text"
+                     icon="el-icon-edit"
+                     @click="handleUpdate(scope.row)"
+                     v-has-permi="['his:promotionalActive:edit']">修改</el-button>
+          <el-button size="mini"
+                     type="text"
+                     icon="el-icon-delete"
+                     @click="handleDelete(scope.row)"
+                     v-has-permi="['his:promotionalActive:remove']">删除</el-button>
+          <el-button size="mini"
+                     type="text"
+                     icon="el-icon-view"
+                     v-has-permi="['his:promotionalActive:view']"
+                     @click="handleView(scope.row)">查看</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改活动对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
+      <el-form v-loading="formLoading" :model="form" ref="form" :rules="rules" label-width="110px">
+        <el-form-item label="活动标题" prop="title">
+          <el-input v-model="form.title" placeholder="请输入活动标题" clearable size="small" />
+        </el-form-item>
+        <el-form-item label="活动主题" prop="theme">
+          <ImageUpload v-model="form.theme" type="image" :limit="1" :width="150" :height="150"/>
+        </el-form-item>
+        <el-form-item label="活动内容" prop="content">
+          <ImageUpload v-model="form.content" type="image" :limit="3" :width="150" :height="150"/>
+        </el-form-item>
+        <el-form-item label="视频区" prop="videoList">
+          <el-button size="small" type="primary" @click="chooseCourseVideo">选取课程小节</el-button>
+          <el-table border width="100%" style="margin-top:5px;" :data="form.videoList">
+            <el-table-column label="所属课程" align="center" prop="courseName" />
+            <el-table-column label="小节名称" align="center" prop="courseVideoName"/>
+            <el-table-column label="视频文件名称" align="center" prop="videoName"/>
+            <el-table-column label="时长" align="center" prop="duration"/>
+            <el-table-column label="操作" align="center">
+              <template slot-scope="scope">
+                <el-button size="mini"
+                           type="text"
+                           icon="el-icon-delete"
+                           @click="handleCourseVideoDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+        <el-form-item label="问诊区" prop="doctorList">
+          <el-button size="small" type="primary" @click="chooseDoctor">选取问诊医生</el-button>
+          <el-table border width="100%" style="margin-top:5px;" :data="form.doctorList">
+            <el-table-column label="医生姓名" align="center" prop="doctorName" />
+            <el-table-column label="所属医院" align="center" prop="hospitalName"/>
+            <el-table-column label="所属科室" align="center" prop="deptName"/>
+            <el-table-column label="职称" align="center" prop="position"/>
+            <el-table-column label="操作" align="center">
+              <template slot-scope="scope">
+                <el-button size="mini"
+                           type="text"
+                           icon="el-icon-delete"
+                           @click="handleDoctorDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+        <el-form-item label="积分商品" prop="goodsList">
+          <el-button size="small" type="primary" @click="chooseGoods">选取商品</el-button>
+          <el-table border width="100%" style="margin-top:5px;" :data="form.goodsList">
+            <el-table-column label="商品名称" align="center" prop="goodsName" />
+            <el-table-column label="封面图片" align="center" prop="goodsImg">
+              <template slot-scope="scope">
+                <el-popover
+                  placement="right"
+                  title=""
+                  trigger="hover"
+                >
+                  <img slot="reference" :src="scope.row.goodsImg" width="100">
+                  <img :src="scope.row.goodsImg" style="max-width: 150px;">
+                </el-popover>
+              </template>
+            </el-table-column>
+            <el-table-column label="商品分类" align="center" prop="goodsTypeName"/>
+            <el-table-column label="商品价格" align="center" prop="cash"/>
+            <el-table-column label="所需积分" align="center" prop="integral"/>
+            <el-table-column label="库存" align="center" prop="stock"/>
+            <el-table-column label="操作" align="center">
+              <template slot-scope="scope">
+                <el-button size="mini"
+                           type="text"
+                           icon="el-icon-delete"
+                           @click="handleGoodsDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+        <el-form-item label="疗法包" prop="packageList">
+          <el-button size="small" type="primary" @click="choosePackage">选取疗法包</el-button>
+          <el-table border width="100%" style="margin-top:5px;" :data="form.packageList">
+            <el-table-column label="封面图片" width="120" align="center">
+              <template slot-scope="scope">
+                <el-popover
+                  placement="right"
+                  title=""
+                  trigger="hover"
+                >
+                  <img slot="reference" :src="scope.row.packageImg" width="100">
+                  <img :src="scope.row.packageImg" style="max-width: 150px;">
+                </el-popover>
+              </template>
+            </el-table-column>
+            <el-table-column label="疗法名称" align="center" prop="packageName" />
+            <el-table-column label="疗法别名" align="center" prop="secondName"/>
+            <el-table-column label="类型" align="center" prop="packageTypeName"/>
+            <el-table-column label="子类型" align="center" prop="packageSubTypeName"/>
+            <el-table-column label="操作" align="center">
+              <template slot-scope="scope">
+                <el-button size="mini"
+                           type="text"
+                           icon="el-icon-delete"
+                           @click="handlePackageDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary"
+                   @click="submitForm"
+                   :loading="addOrUpdating"
+                   :disabled="addOrUpdating">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="videoDialog.title" :visible.sync="videoDialog.open" width="1200px" append-to-body>
+      <choose-course-video-component :videoIds="this.form.videoList.map(item => item.videoId)"
+                                     @closeChoose="closeChooseCourseVideo"
+                                     @selectConfirm="selectConfirmCourseVideo"/>
+    </el-dialog>
+
+    <el-dialog :title="doctorDialog.title" :visible.sync="doctorDialog.open" width="1200px" append-to-body>
+      <choose-doctor-component :doctorIds="this.form.doctorList.map(item => item.doctorId)"
+                              @closeChoose="closeChooseDoctor"
+                              @selectConfirm="selectConfirmDoctor"/>
+    </el-dialog>
+
+    <el-dialog :title="goodsDialog.title" :visible.sync="goodsDialog.open" width="1200px" append-to-body>
+      <choose-integral-goods-component :goodsIds="this.form.goodsList.map(item => item.goodsId)"
+                                      @closeChoose="closeChooseGoods"
+                                      @selectConfirm="selectConfirmGoods"/>
+    </el-dialog>
+
+    <el-dialog :title="packageDialog.title" :visible.sync="packageDialog.open" width="1200px" append-to-body>
+      <choose-package-component :packageIds="this.form.packageList.map(item => item.packageId)"
+                              @closeChoose="closeChoosePackage"
+                              @selectConfirm="selectConfirmPackage"/>
+    </el-dialog>
+
+    <el-drawer
+      :with-header="false"
+      size="75%"
+      :title="show.title"
+      :visible.sync="show.open" append-to-body>
+      <div v-if="show.data" v-loading="formLoading" class="detail-container">
+        <div class="detail-header">
+          <div class="detail-title">
+            {{ show.data.title || '查看详情' }}
+          </div>
+          <el-button type="text" icon="el-icon-close" @click="show.open=false"></el-button>
+        </div>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">基本信息</div>
+          <el-descriptions :column="1" border size="small">
+            <el-descriptions-item label="活动标题">{{ show.data.title || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="创建时间">{{ show.data.createTime || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="活动主题">
+              <div class="theme-wrapper">
+                <img v-if="show.data.theme" :src="show.data.theme" class="theme-image" />
+                <span v-else>-</span>
+              </div>
+            </el-descriptions-item>
+            <el-descriptions-item label="活动内容">
+              <div v-if="show.data.content" class="image-gallery">
+                <el-image
+                  v-for="(img, index) in parseImages(show.data.content)"
+                  :key="index"
+                  :src="img"
+                  :preview-src-list="parseImages(show.data.content)"
+                  fit="cover"
+                  class="gallery-item"
+                />
+              </div>
+              <span v-else>-</span>
+            </el-descriptions-item>
+          </el-descriptions>
+        </el-card>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">视频区</div>
+          <el-table v-if="(show.data.videoList || []).length" :data="show.data.videoList" border size="small">
+            <el-table-column label="所属课程" align="center" prop="courseName" />
+            <el-table-column label="小节名称" align="center" prop="courseVideoName"/>
+            <el-table-column label="视频文件名称" align="center" prop="videoName"/>
+            <el-table-column label="时长" align="center" prop="duration"/>
+          </el-table>
+          <span v-else>-</span>
+        </el-card>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">问诊区</div>
+          <el-table v-if="(show.data.doctorList || []).length" :data="show.data.doctorList" border size="small">
+            <el-table-column label="医生姓名" align="center" prop="doctorName" />
+            <el-table-column label="所属医院" align="center" prop="hospitalName"/>
+            <el-table-column label="所属科室" align="center" prop="deptName"/>
+            <el-table-column label="职称" align="center" prop="position"/>
+          </el-table>
+          <span v-else>-</span>
+        </el-card>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">积分商品</div>
+          <el-table v-if="(show.data.goodsList || []).length" :data="show.data.goodsList" border size="small">
+            <el-table-column label="商品名称" align="center" prop="goodsName" />
+            <el-table-column label="封面图片" align="center" prop="goodsImg">
+              <template slot-scope="scope">
+                <el-popover placement="right" title="" trigger="hover">
+                  <img slot="reference" :src="scope.row.goodsImg" class="thumb" />
+                  <img :src="scope.row.goodsImg" class="popover-img" />
+                </el-popover>
+              </template>
+            </el-table-column>
+            <el-table-column label="商品分类" align="center" prop="goodsTypeName"/>
+            <el-table-column label="商品价格" align="center" prop="cash"/>
+            <el-table-column label="所需积分" align="center" prop="integral"/>
+            <el-table-column label="库存" align="center" prop="stock"/>
+          </el-table>
+          <span v-else>-</span>
+        </el-card>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">疗法包</div>
+          <el-table v-if="(show.data.packageList || []).length" :data="show.data.packageList" border size="small">
+            <el-table-column label="封面图片" width="120" align="center">
+              <template slot-scope="scope">
+                <el-popover placement="right" title="" trigger="hover">
+                  <img slot="reference" :src="scope.row.packageImg" class="thumb" />
+                  <img :src="scope.row.packageImg" class="popover-img" />
+                </el-popover>
+              </template>
+            </el-table-column>
+            <el-table-column label="疗法名称" align="center" prop="packageName" />
+            <el-table-column label="疗法别名" align="center" prop="secondName"/>
+            <el-table-column label="类型" align="center" prop="packageTypeName"/>
+            <el-table-column label="子类型" align="center" prop="packageSubTypeName"/>
+          </el-table>
+          <span v-else>-</span>
+        </el-card>
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import ChooseCourseVideoComponent from '@/views/his/promotionalActive/ChooseCourseVideoComponent.vue'
+import ChooseDoctorComponent from '@/views/his/promotionalActive/ChooseDoctorComponent.vue'
+import ChooseIntegralGoodsComponent from '@/views/his/promotionalActive/ChooseIntegralGoodsComponent.vue'
+import ChoosePackageComponent from '@/views/his/promotionalActive/ChoosePackageComponent.vue'
+import { add, update, list, get, del } from '@/api/his/promotionalActive'
+
+export default {
+  name: 'promotionalActive',
+  components: {
+    ChooseCourseVideoComponent,
+    ChooseDoctorComponent,
+    ChooseIntegralGoodsComponent,
+    ChoosePackageComponent
+  },
+  data() {
+    return {
+      loading: false,
+      single: true,
+      multiple: true,
+      ids: [],
+      showSearch: true,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: null,
+      },
+      total: 0,
+      list: [],
+      title: '新增',
+      open: false,
+      form: {
+        id: null,
+        title: null,
+        theme: null,
+        content: null,
+        goodsList: [],
+        packageList: [],
+        doctorList: [],
+        videoList: [],
+      },
+      formLoading: false,
+      rules: {
+        title: [
+          { required: true, message: '请输入活动标题', trigger: 'blur' }
+        ],
+        theme: [
+          { required: true, message: '请上传活动主题', trigger: 'blur' }
+        ],
+        content: [
+          { required: true, message: '请上传活动内容', trigger: 'blur' }
+        ]
+      },
+      videoDialog: {
+        open: false,
+        title: '课程小节选择',
+      },
+      doctorDialog: {
+        open: false,
+        title: '问诊医生选择',
+      },
+      goodsDialog: {
+        open: false,
+        title: '积分商品选择',
+      },
+      packageDialog: {
+        open: false,
+        title: '疗法包选择',
+      },
+      addOrUpdating: false,
+      show: {
+        open: false,
+        title: '查看详情',
+      }
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 解析逗号分隔的图片URL字符串
+    parseImages(images) {
+      if (!images) return [];
+      return images.split(',').filter(img => img.trim() !== '');
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        title: null,
+      };
+      this.getList();
+    },
+    getList() {
+      this.loading = true
+      list(this.queryParams).then(response => {
+        this.list = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.addOrUpdating = false
+      this.title = '添加活动'
+    },
+    reset() {
+      this.form = {
+        id: null,
+        title: null,
+        theme: null,
+        content: null,
+        goodsList: [],
+        packageList: [],
+        doctorList: [],
+        videoList: [],
+      }
+      this.resetForm("form");
+    },
+    handleUpdate(row) {
+      const id = row.id || this.ids
+      this.reset()
+      this.formLoading = true
+      get(id).then(response => {
+        this.form = {
+          ...response.data,
+          goodsList: response.data.goodsList || [],
+          packageList: response.data.packageList || [],
+          doctorList: response.data.doctorList || [],
+          videoList: response.data.videoList || []
+        }
+        this.formLoading = false
+      })
+      this.open = true
+      this.addOrUpdating = false
+      this.title = '修改活动'
+    },
+    handleDelete(row) {
+      const ids = row.id || this.ids
+      this.$confirm('是否确认删除积分商品编号为"' + ids + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return del(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.multiple = !selection.length
+      this.single = selection.length !== 1
+    },
+    handleView(row) {
+      this.formLoading = true
+      this.show.open = true
+      get(row.id).then(response => {
+        this.show.data = {
+          ...response.data,
+          goodsList: response.data.goodsList || [],
+          packageList: response.data.packageList || [],
+          doctorList: response.data.doctorList || [],
+          videoList: response.data.videoList || []
+        }
+        this.formLoading = false
+      })
+    },
+    chooseCourseVideo() {
+      this.videoDialog.open = true
+    },
+    closeChooseCourseVideo() {
+      this.videoDialog.open = false
+    },
+    selectConfirmCourseVideo(data) {
+      this.form.videoList = []
+      data.forEach(item => {
+        this.form.videoList.push(item)
+      })
+      this.videoDialog.open = false
+    },
+    handleCourseVideoDelete(row) {
+      this.form.videoList.splice(this.form.videoList.indexOf(row), 1)
+    },
+    chooseDoctor() {
+      this.doctorDialog.open = true
+    },
+    closeChooseDoctor() {
+      this.doctorDialog.open = false
+    },
+    selectConfirmDoctor(data) {
+      this.form.doctorList = []
+      data.forEach(item => {
+        this.form.doctorList.push(item)
+      })
+      this.doctorDialog.open = false
+    },
+    handleDoctorDelete(row) {
+      this.form.doctorList.splice(this.form.doctorList.indexOf(row), 1)
+    },
+    chooseGoods() {
+      this.goodsDialog.open = true
+    },
+    closeChooseGoods() {
+      this.goodsDialog.open = false
+    },
+    selectConfirmGoods(data) {
+      this.form.goodsList = []
+      data.forEach(item => {
+        this.form.goodsList.push(item)
+      })
+      this.goodsDialog.open = false
+    },
+    handleGoodsDelete(row) {
+      this.form.goodsList.splice(this.form.goodsList.indexOf(row), 1)
+    },
+    choosePackage() {
+      this.packageDialog.open = true
+    },
+    closeChoosePackage() {
+      this.packageDialog.open = false
+    },
+    selectConfirmPackage(data) {
+      this.form.packageList = []
+      data.forEach(item => {
+        this.form.packageList.push(item)
+      })
+      this.packageDialog.open = false
+    },
+    handlePackageDelete(row) {
+      this.form.packageList.splice(this.form.packageList.indexOf(row), 1)
+    },
+    submitForm() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          const params = {
+            id: this.form.id,
+            title: this.form.title,
+            theme: this.form.theme,
+            content: this.form.content,
+            goodsIds: this.form.goodsList.map(item => item.goodsId),
+            packageIds: this.form.packageList.map(item => item.packageId),
+            doctorIds: this.form.doctorList.map(item => item.doctorId),
+            videoIds: this.form.videoList.map(item => item.videoId),
+          }
+
+          this.addOrUpdating = true
+          if (this.form.id) {
+            update(params).then(res => {
+              this.msgSuccess("修改成功");
+              this.open = false
+              this.getList()
+            })
+            return
+          }
+
+          add(params).then(res => {
+            this.msgSuccess("新增成功");
+            this.open = false
+            this.getList()
+          })
+        }
+      })
+    },
+    cancel() {
+      this.open = false
+      this.reset()
+    }
+  }
+}
+</script>
+
+<style scoped>
+.detail-container {
+  padding: 12px 16px 20px;
+}
+
+.detail-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 4px 0 8px;
+  margin-bottom: 8px;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.detail-title {
+  font-size: 16px;
+  font-weight: 600;
+}
+
+.block-card {
+  margin-bottom: 12px;
+}
+
+.card-header {
+  font-weight: 600;
+}
+
+.theme-wrapper {
+  display: flex;
+  align-items: center;
+  min-height: 120px;
+}
+
+.theme-image {
+  max-width: 100%;
+  max-height: 240px;
+  width: auto;
+  display: block;
+}
+
+.image-gallery {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.gallery-item {
+  width: 100px;
+  height: 100px;
+  margin-right: 8px;
+  margin-bottom: 8px;
+}
+
+.thumb {
+  max-height: 80px;
+  width: auto;
+}
+
+.popover-img {
+  max-width: 150px;
+  max-height: 150px;
+  width: auto;
+}
+</style>

+ 103 - 0
src/views/his/promotionalActive/stats.vue

@@ -0,0 +1,103 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="活动标题" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入活动标题"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="日期" prop="date">
+        <el-date-picker
+          v-model="queryParams.date"
+          type="datetimerange"s
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+          clearable
+          size="small"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="list" border>
+      <el-table-column label="活动标题" align="center" prop="title" />
+      <el-table-column label="首页浏览量" align="center" prop="homeViews" />
+      <el-table-column label="视频区点击量" align="center" prop="videoClick" />
+      <el-table-column label="问诊区点击量" align="center" prop="doctorClick"/>
+      <el-table-column label="产品区点击量" align="center" prop="goodsClick" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { list } from '@/api/his/promotionalActiveLog'
+
+export default {
+  name: 'promotionalActiveStats',
+  data() {
+    return {
+      showSearch: true,
+      loading: false,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        date: null,
+      },
+      total: 0,
+      list: null,
+    }
+  },
+  created() {
+    this.handleQuery()
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+      }
+      this.handleQuery()
+    },
+    getList() {
+      this.loading = true
+      const params = {
+        ...this.queryParams,
+        startTime: this.queryParams.date && this.queryParams.date[0],
+        endTime: this.queryParams.date && this.queryParams.date[1],
+      }
+      list(params).then(response => {
+        this.list = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 352 - 0
src/views/his/statistics/afterSalesOrder.vue

@@ -0,0 +1,352 @@
+<template>
+    <div class="app-container">
+        <div class="app-content">
+             <div class="title">
+               售后订单统计
+            </div>
+           <el-form class="search-form" :inline="true" >
+            <el-form-item >
+              <el-select v-model="value" placeholder="请选择日期">
+                <el-option
+                  v-for="item in options"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value">
+                </el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item >
+              <treeselect :clearable="false"  v-model="deptId"  :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
+            </el-form-item>
+            <el-form-item>
+              <el-select filterable v-model="userIds" placeholder="请选择员工" clearable size="small">
+                  <el-option
+                    v-for="item in users"
+                    :key="item.userId"
+                    :label="item.nickName"
+                    :value="item.userId">
+                  </el-option>
+                </el-select>
+            </el-form-item>
+           <el-form-item label="下单日期" prop="createTime">
+                    <el-date-picker clearable size="small" style="width: 205.4px"
+                      v-model="dateRange"
+                      type="daterange"
+                      value-format="yyyy-MM-dd"
+                      start-placeholder="开始日期" end-placeholder="结束日期"
+                      >
+                    </el-date-picker>
+            </el-form-item>
+            <el-form-item>
+                <el-button type="cyan" icon="el-icon-search"   @click="afterSalesOrder">搜索</el-button>
+            </el-form-item>
+          </el-form>
+           <div class="data-box">
+              <div class="echart-box">
+                <div id="echart-customer"></div>
+              </div>
+              <div class="table-box">
+                    <el-button class="export" size="small"  @click="handleExport" >导出</el-button>
+                    <el-table
+                    :data="list"
+                    border
+                    :summary-method="getSummaries"
+                    show-summary
+                    max-height="500"
+                    style="width: 100%;">
+                    <el-table-column
+                      prop="nickName"
+                      label="员工姓名">
+                    </el-table-column>
+                    <el-table-column
+                      prop="orderCount"
+                      label="订单数">
+                    </el-table-column>
+                    <el-table-column
+                      prop="payPrice"
+                      label="订单金额">
+                    </el-table-column>
+  
+                  </el-table>
+              </div>
+          </div>
+        </div>
+  
+      </div>
+  </template>
+  
+  <script>
+  import { afterSalesOrder,exportAfterSalesOrder } from "@/api/company/statistics";
+  import { getUserListByDeptId} from "@/api/company/companyUser";
+  import echarts from 'echarts'
+  import resize from '../../dashboard/mixins/resize'
+  import { treeselect } from "@/api/company/companyDept";
+  import Treeselect from "@riophae/vue-treeselect";
+  import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+  
+  export default {
+  name: 'Index',
+  mixins: [resize],
+  components: { Treeselect },
+  watch: {
+  // 监听deptId
+  'deptId': 'currDeptChange'
+  },
+  data() {
+  return {
+   deptOptions:[],
+   deptId:undefined,
+   userIds:undefined,
+   users:[],
+   dateRange:[],
+   chart: null,
+   options: [{
+      value: '1',
+      label: '今天'
+    }, {
+      value: '2',
+      label: '昨天'
+    }, {
+      value: '3',
+      label: '本周'
+    }, {
+      value: '4',
+      label: '上周'
+    }, {
+      value: '5',
+      label: '本月'
+    }
+    , {
+      value: '6',
+      label: '上月'
+    }
+    , {
+      value: '7',
+      label: '本季度'
+    }
+    , {
+      value: '8',
+      label: '上季度'
+    }
+    , {
+      value: '9',
+      label: '本年'
+    }
+    , {
+      value: '10',
+      label: '上年'
+    }],
+    value: '5',
+    list:[],
+    dates:[],
+    orderCount:[],
+    payPrice:[],
+  
+  }
+  },
+  created() {
+  this.getTreeselect();
+  },
+  methods: {
+    currDeptChange(val){
+    console.log(val)
+    this.deptId=val;
+    this.getUserListByDeptId();
+  },
+  /** 查询部门下拉树结构 */
+  getTreeselect() {
+  var that=this;
+  treeselect().then((response) => {
+    this.deptOptions = response.data;
+    console.log(this.deptOptions)
+    if(response.data!=null&&response.data.length>0){
+      this.deptId=response.data[0].id;
+      that.afterSalesOrder()
+    }
+  });
+  },
+  handleExport(){
+    var data;
+    if(this.userIds!=undefined){
+        data={type:this.value,userIds:this.userIds+"",deptId:this.deptId}
+    }
+    else{
+        data={type:this.value,deptId:this.deptId}
+    }
+    if(this.dateRange){
+        data.startTime = this.dateRange[0];
+        data.endTime = this.dateRange[1];
+      }
+    exportAfterSalesOrder(data).then((response) => {
+        console.log(response)
+       this.download(response.msg);
+    });
+  
+  },
+  getUserListByDeptId() {
+    this.userIds=undefined;
+    var data={deptId:this.deptId};
+    getUserListByDeptId(data).then(response => {
+      this.users = response.data;
+  
+    });
+  },
+  afterSalesOrder(){
+      var data;
+      if(this.userIds!=undefined){
+          data={type:this.value,userIds:this.userIds+"",deptId:this.deptId}
+      }
+      else{
+          data={type:this.value,deptId:this.deptId}
+      }
+      if(this.dateRange){
+        data.startTime = this.dateRange[0];
+        data.endTime = this.dateRange[1];
+      }
+      afterSalesOrder(data).then((response) => {
+       this.list=response.list;
+       this.dates=response.dates;
+       this.orderCount=response.orderCount;
+       this.payPrice=response.payPrice;
+        setTimeout(() => {
+          this.initEchart();
+        }, 500);
+    });
+  },
+  initEchart(){
+    var option = {
+      tooltip: {
+          trigger: 'axis',
+          axisPointer: {            // 坐标轴指示器,坐标轴触发有效
+              type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
+          }
+      },
+      legend: {
+          data: ['订单数', '订单金额' ]
+      },
+      grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+      },
+      xAxis: [
+          {
+              type: 'category',
+              data: this.dates
+          }
+      ],
+      yAxis: [
+          {
+              type: 'value',
+              axisLabel:{
+                formatter:'{value}'
+              }
+          }
+      ],
+      series: [
+          {
+  
+              name: '订单数',
+              type: 'line',
+              emphasis: {
+                  focus: 'series'
+              },
+              data: this.orderCount
+          },
+          {
+  
+              name: '订单金额',
+              type: 'line',
+              emphasis: {
+                  focus: 'series'
+              },
+              data: this.payPrice
+          }
+  
+      ]
+    };
+    this.chart=echarts.init(document.getElementById("echart-customer"));
+    this.chart.setOption(option,true);
+  },
+   getSummaries(param) {
+    const { columns, data } = param;
+    const sums = [];
+    columns.forEach((column, index) => {
+      if (index === 0) {
+        sums[index] = '总计';
+        return;
+      }
+      const values = data.map(item => Number(item[column.property]));
+      if (!values.every(value => isNaN(value))) {
+        const total = values.reduce((prev, curr) => {
+          const value = Number(curr);
+          return !isNaN(value) ? prev + curr : prev;
+        }, 0);
+        sums[index] = total.toFixed(2);
+      } else {
+        sums[index] = '';
+      }
+    });
+  
+    return sums;
+  }
+  }
+  }
+  </script>
+  
+  <style lang="scss" scoped>
+  .app-container{
+  border: 1px solid #e6e6e6;
+  padding: 12px;
+  
+  .app-content{
+  background-color: white;
+  .title{
+    padding: 20px 30px 0px 30px;
+    font-size: 18px;
+    font-weight: bold;
+    color: black;
+  
+  }
+  .search-form{
+    margin: 20px 30px 0px 30px;
+  }
+  .data-box{
+    padding: 30px;
+    background-color:  rgb(255, 255, 255);
+    height: 100%;
+  
+    .echart-box{
+      margin: 0 auto;
+      text-align: center;
+    }
+    .el-select{
+      margin: 5px 10px;
+    }
+    .table-box{
+      margin-top: 15px;
+      .export{
+        float: right;
+        margin: 10px 0px;
+      }
+    }
+  }
+  }
+  }
+  #echart-customer{
+  width:100%;
+  height:320px
+  }
+  .vue-treeselect{
+  width: 217px;
+  height: 36px;
+  }
+  
+  </style>
+  <style>
+  .vue-treeselect__control{
+  display: block;
+  }
+  </style>
+  

+ 178 - 0
src/views/his/statistics/appOrderCountStats.vue

@@ -0,0 +1,178 @@
+<template>
+  <div class="app-container">
+    <div class="app-content">
+      <div class="title">App商城订单统计</div>
+      <el-form class="search-form" :inline="true">
+        <el-form-item label="公司名称" prop="companyId">
+          <el-select
+            style="width: 220px"
+            filterable
+            v-model="queryParams.companyId"
+            placeholder="请选择公司名"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in companys"
+              :key="item.companyId"
+              :label="item.companyName"
+              :value="item.companyId"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="员工" prop="companyUserId">
+          <el-select
+            filterable
+            v-model="queryParams.companyUserId"
+            placeholder="请选择员工"
+            clearable
+            size="small"
+            :disabled="!queryParams.companyId"
+          >
+            <el-option
+              v-for="item in users"
+              :key="item.userId"
+              :label="item.nickName"
+              :value="item.userId"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="下单日期">
+          <el-date-picker
+            clearable
+            size="small"
+            style="width: 205.4px"
+            v-model="dateRange"
+            type="daterange"
+            value-format="yyyy-MM-dd"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" @click="search">搜索</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div class="data-box">
+        <div class="table-box">
+          <el-table :data="tableData" border max-height="500" style="width: 100%">
+            <el-table-column prop="category" label="订单类型" width="180" />
+            <el-table-column prop="orderCount" label="订单数" />
+            <el-table-column prop="orderAmount" label="订单总金额(元)" />
+            <el-table-column prop="depositAmount" label="定金金额(元)" />
+            <el-table-column prop="codAmount" label="物流代收金额(元)" />
+          </el-table>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getAppOrderCount } from "@/api/company/statistics";
+import { getUserList } from "@/api/company/companyUser"; // 使用 getUserList(companyId)
+import { getCompanyList } from "@/api/company/company";
+
+export default {
+  name: "AppOrderCountStats",
+  data() {
+    return {
+      // 仅保留必要查询参数
+      queryParams: {
+        companyId: null,
+        companyUserId: null
+      },
+      companys: [],   // 公司列表
+      users: [],      // 员工列表
+      dateRange: [],  // 日期范围
+      tableData: []   // 表格数据
+    };
+  },
+  watch: {
+    // 公司变化时,重新加载员工
+    'queryParams.companyId'(newVal) {
+      if (newVal) {
+        this.queryParams.companyUserId = null;
+        this.loadUsers();
+      } else {
+        this.users = [];
+        this.queryParams.companyUserId = null;
+      }
+    }
+  },
+  created() {
+    // 初始化公司下拉列表
+    getCompanyList().then(response => {
+      this.companys = response.data || [];
+    });
+  },
+  methods: {
+    // 根据 companyId 加载员工
+    loadUsers() {
+      const companyId = this.queryParams.companyId;
+      if (!companyId) return;
+
+      getUserList(companyId).then(res => {
+        if (res.code === 200) {
+          this.users = Array.isArray(res.data) ? res.data : [];
+        } else {
+          this.users = [];
+        }
+      }).catch(() => {
+        this.users = [];
+      });
+    },
+
+    // 搜索统计
+    search() {
+      const params = {
+        companyId: this.queryParams.companyId,
+        companyUserId: this.queryParams.companyUserId,
+        startTime: this.dateRange?.[0] || undefined,
+        endTime: this.dateRange?.[1] ? this.dateRange[1] + " 23:59:59" : undefined
+      };
+
+      getAppOrderCount(params).then(response => {
+        const vo = response.data;
+        // this.tableData = vo ? [vo] : [];
+        this.tableData = response.data || []; // 直接赋值数组
+      }).catch(() => {
+        this.tableData = [];
+      });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  border: 1px solid #e6e6e6;
+  padding: 12px;
+
+  .app-content {
+    background-color: white;
+    .title {
+      padding: 20px 30px 0px 30px;
+      font-size: 18px;
+      font-weight: bold;
+      color: black;
+    }
+    .search-form {
+      margin: 20px 30px 0px 30px;
+    }
+    .data-box {
+      padding: 30px;
+      background-color: rgb(255, 255, 255);
+      height: 100%;
+
+      .table-box {
+        margin-top: 15px;
+      }
+    }
+  }
+}
+</style>

+ 420 - 0
src/views/his/statistics/comprehensiveStatistics.vue

@@ -0,0 +1,420 @@
+<template>
+  <div class="app-container">
+    <div class="app-content">
+      <div class="title">综合统计看板</div>
+
+      <el-form class="search-form" :inline="true" label-width="90px">
+
+        <!-- 时间范围选择 -->
+        <el-form-item label="时间范围">
+          <el-date-picker
+            v-model="dateRange"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            :picker-options="pickerOptions">
+          </el-date-picker>
+        </el-form-item>
+
+        <!-- 统计维度选择 -->
+        <el-form-item label="统计维度">
+          <el-select v-model="queryParams.dimension" placeholder="请选择统计维度" @change="handleDimensionChange" clearable>
+            <el-option label="个人" :value="1"></el-option>
+            <el-option label="公司" :value="2"></el-option>
+            <el-option label="部门" :value="3"></el-option>
+          </el-select>
+        </el-form-item>
+
+        <!-- 公司选择 -->
+        <el-form-item label="选择公司" v-if="queryParams.dimension">
+          <el-select
+            v-model="queryParams.companyId"
+            placeholder="请选择公司"
+            @change="handleCompanyChange"
+            clearable
+            :disabled="!queryParams.dimension">
+            <el-option
+              v-for="company in companyList"
+              :key="company.companyId"
+              :label="company.companyName"
+              :value="company.companyId">
+            </el-option>
+          </el-select>
+        </el-form-item>
+
+        <!-- 部门选择 -->
+        <el-form-item label="选择部门" v-if="showDepartmentSelect">
+          <el-select
+            v-model="queryParams.deptId"
+            placeholder="请选择部门"
+            @change="handleDeptChange"
+            clearable
+            :disabled="!queryParams.companyId">
+            <el-option
+              v-for="dept in deptList"
+              :key="dept.deptId"
+              :label="dept.deptName"
+              :value="dept.deptId">
+            </el-option>
+          </el-select>
+        </el-form-item>
+
+        <!-- 人员选择 -->
+        <el-form-item label="选择人员" v-if="showUserSelect">
+          <el-select
+            v-model="queryParams.userId"
+            placeholder="请选择人员"
+            clearable
+            :disabled="!queryParams.deptId">
+            <el-option
+              v-for="user in userList"
+              :key="user.userId"
+              :label="user.userName"
+              :value="user.userId">
+            </el-option>
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <!-- 数据表格 -->
+    <div class="table-section">
+      <el-table :data="paginatedTableData" border style="width: 100%" height="400">
+        <el-table-column prop="companyName" label="公司名称" />
+        <el-table-column prop="deptName" label="部门名称" />
+        <el-table-column prop="userName" label="人员姓名" />
+        <el-table-column prop="lineNum" label="进线数" />
+        <el-table-column prop="activeNum" label="激活数" />
+        <el-table-column prop="completeNum" label="完课数" />
+        <el-table-column prop="answerNum" label="答题数" />
+        <el-table-column prop="redPacketNum" label="红包领取数" />
+      </el-table>
+
+      <el-pagination
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="currentPage"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="pageSize"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="tableData.length"
+        style="margin-top: 20px; text-align: right;">
+      </el-pagination>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getStatisticsData, getSearchUserInfo, getSearchCompanyInfo, getSearchDeptInfo } from "@/api/statistics/statistics";
+
+export default {
+  data() {
+    return {
+      companyList: [],
+      deptList: [],
+      userList: [],
+      rawData: [],
+      tableData: [],
+      currentPage: 1,
+      pageSize: 20,
+      dateRange: [],
+      pickerOptions: {
+        shortcuts: [{
+          text: '最近一周',
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+            picker.$emit('pick', [start, end]);
+          }
+        }, {
+          text: '最近一个月',
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+            picker.$emit('pick', [start, end]);
+          }
+        }, {
+          text: '最近三个月',
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+            picker.$emit('pick', [start, end]);
+          }
+        }]
+      },
+      queryParams: {
+        dimension: null,
+        companyId: null,
+        deptId: null,
+        userId: null
+      }
+    };
+  },
+
+  computed: {
+    paginatedTableData() {
+      const start = (this.currentPage - 1) * this.pageSize;
+      const end = start + this.pageSize;
+      return this.tableData.slice(start, end);
+    },
+
+    showDepartmentSelect() {
+      return this.queryParams.dimension &&
+        (this.queryParams.dimension === 3 || this.queryParams.dimension === 1) &&
+        this.queryParams.companyId;
+    },
+
+    showUserSelect() {
+      return this.queryParams.dimension === 1 &&
+        this.queryParams.companyId &&
+        this.queryParams.deptId;
+    }
+  },
+
+  mounted() {
+    // 设置默认时间为当天
+    const today = new Date();
+    this.dateRange = [today, today];
+    // 默认设置统计维度为公司
+    this.queryParams.dimension = 2;
+    this.loadData();
+  },
+
+  methods: {
+    loadData() {
+      // 使用 getSearchCompanyInfo 获取公司下拉数据
+      getSearchCompanyInfo().then(response => {
+        this.companyList = response.data || [];
+
+        // 默认选择第一个公司(如果存在)
+        if (this.companyList.length > 0) {
+          this.queryParams.companyId = this.companyList[0].companyId;
+          // 加载该公司的部门数据
+          return this.loadDeptData(this.queryParams.companyId);
+        }
+      }).then(() => {
+        // 在公司和部门默认选择完成后,请求统计数据
+        return this.fetchStatisticsData();
+      }).catch(error => {
+        console.error('数据加载失败:', error);
+        this.$message.error('数据加载失败');
+      });
+    },
+
+    loadDeptData(companyId) {
+      return getSearchDeptInfo({ id: companyId }).then(response => {
+        this.deptList = response.data || [];
+
+        // 默认选择第一个部门(如果存在)
+        if (this.deptList.length > 0) {
+          this.queryParams.deptId = this.deptList[0].deptId;
+        }
+      }).catch(error => {
+        console.error('部门数据加载失败:', error);
+        this.$message.error('部门数据加载失败');
+      });
+    },
+
+    fetchStatisticsData() {
+      // 构造请求参数对象
+      const params = {
+        dimension: this.queryParams.dimension,
+        startTime: this.formatDate(this.dateRange[0]),
+        endTime: this.formatDate(this.dateRange[1])
+      };
+
+      // 根据维度设置id参数
+      if (this.queryParams.dimension === 1 && this.queryParams.userId) {
+        params.id = this.queryParams.userId;
+      } else if (this.queryParams.dimension === 2 && this.queryParams.companyId) {
+        params.id = this.queryParams.companyId;
+      } else if (this.queryParams.dimension === 3 && this.queryParams.deptId) {
+        params.id = this.queryParams.deptId;
+      }
+
+      // 以POST方式发送请求体
+      return getStatisticsData(params).then(response => {
+        this.rawData = response.data || [];
+        this.tableData = [...this.rawData];
+        this.currentPage = 1;
+      }).catch(error => {
+        console.error('统计数据加载失败:', error);
+        this.$message.error('统计数据加载失败');
+      });
+    },
+
+    formatDate(date) {
+      if (!date) return '';
+      const d = new Date(date);
+      const year = d.getFullYear();
+      const month = String(d.getMonth() + 1).padStart(2, '0');
+      const day = String(d.getDate()).padStart(2, '0');
+      return `${year}-${month}-${day}`;
+    },
+
+    handleCompanyChange(companyId) {
+      this.queryParams.deptId = null;
+      this.queryParams.userId = null;
+      this.deptList = [];
+      this.userList = [];
+
+      if (!companyId) return;
+
+      // 使用 getSearchDeptInfo 获取部门下拉数据
+      getSearchDeptInfo({ id: companyId }).then(response => {
+        this.deptList = response.data || [];
+
+        // 默认选择第一个部门(如果存在)
+        // 仅在部门维度或个人维度下默认选择第一个部门
+        if (this.deptList.length > 0 &&
+          (this.queryParams.dimension === 3 || this.queryParams.dimension === 1)) {
+          this.queryParams.deptId = this.deptList[0].deptId;
+
+          // 如果是个人维度,还需要加载用户数据
+          if (this.queryParams.dimension === 1 && this.queryParams.deptId) {
+            this.loadUserData(this.queryParams.deptId);
+          }
+        }
+      }).catch(error => {
+        console.error('部门数据加载失败:', error);
+        this.$message.error('部门数据加载失败');
+      });
+    },
+
+    // 新增加载用户数据的方法
+    loadUserData(deptId) {
+      if (!deptId) return;
+
+      getSearchUserInfo({ id: deptId }).then(response => {
+        this.userList = response.data || [];
+
+        // 可以选择默认选中第一个用户
+        if (this.userList.length > 0) {
+          // this.queryParams.userId = this.userList[0].userId;
+        }
+      }).catch(error => {
+        console.error('人员数据加载失败:', error);
+        this.$message.error('人员数据加载失败');
+      });
+    },
+
+    handleDeptChange(deptId) {
+      this.queryParams.userId = null;
+      this.userList = [];
+
+      if (!deptId) return;
+
+      // 使用 getSearchUserInfo 获取人员下拉数据
+      getSearchUserInfo({ id: deptId }).then(response => {
+        this.userList = response.data || [];
+
+        // 在个人维度下,默认选择第一个用户(可选)
+        if (this.userList.length > 0 && this.queryParams.dimension === 1) {
+          // this.queryParams.userId = this.userList[0].userId;
+        }
+      }).catch(error => {
+        console.error('人员数据加载失败:', error);
+        this.$message.error('人员数据加载失败');
+      });
+    },
+
+    handleQuery() {
+      // 触发统计数据请求
+      this.fetchStatisticsData();
+    },
+
+    handleDimensionChange() {
+      // 重置后续选择项
+      this.queryParams.companyId = null;
+      this.queryParams.deptId = null;
+      this.queryParams.userId = null;
+      this.deptList = [];
+      this.userList = [];
+    },
+
+    resetQuery() {
+      this.queryParams = {
+        dimension: null,
+        companyId: null,
+        deptId: null,
+        userId: null
+      };
+      // 重置时间为当天
+      const today = new Date();
+      this.dateRange = [today, today];
+      this.deptList = [];
+      this.userList = [];
+      this.tableData = [...this.rawData];
+      this.currentPage = 1;
+    },
+
+    handleSizeChange(val) {
+      this.pageSize = val;
+      this.currentPage = 1;
+    },
+
+    handleCurrentChange(val) {
+      this.currentPage = val;
+    }
+  }
+};
+</script>
+
+<style scoped>
+.app-container {
+  border: 1px solid #e6e6e6;
+  padding: 12px;
+  background-color: #f5f7fa;
+}
+
+.app-content {
+  background-color: white;
+  padding: 20px;
+  border-radius: 4px;
+  margin-bottom: 20px;
+}
+
+.title {
+  text-align: center;
+  font-size: 24px;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 20px;
+}
+
+.search-form {
+  display: flex;
+  justify-content: center;
+  flex-wrap: wrap;
+}
+
+.search-form .el-form-item {
+  margin-bottom: 10px;
+}
+
+.table-section {
+  background-color: white;
+  padding: 20px;
+  border-radius: 4px;
+}
+
+.table-section .el-table {
+  width: 100% !important;
+}
+
+@media (min-width: 1200px) {
+  .table-section {
+    padding: 20px 50px;
+  }
+}
+</style>

+ 170 - 0
src/views/his/statistics/hisOrderCountStats.vue

@@ -0,0 +1,170 @@
+<template>
+  <div class="app-container">
+    <div class="app-content">
+      <div class="title">互联网医院订单统计</div>
+      <el-form class="search-form" :inline="true">
+        <el-form-item label="公司名称" prop="companyId">
+          <el-select
+            style="width: 220px"
+            filterable
+            v-model="queryParams.companyId"
+            placeholder="请选择公司名"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in companys"
+              :key="item.companyId"
+              :label="item.companyName"
+              :value="item.companyId"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="员工" prop="companyUserId">
+          <el-select
+            filterable
+            v-model="queryParams.companyUserId"
+            placeholder="请选择员工"
+            clearable
+            size="small"
+            :disabled="!queryParams.companyId"
+          >
+            <el-option
+              v-for="item in users"
+              :key="item.userId"
+              :label="item.nickName"
+              :value="item.userId"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="下单日期">
+          <el-date-picker
+            clearable
+            size="small"
+            style="width: 205.4px"
+            v-model="dateRange"
+            type="daterange"
+            value-format="yyyy-MM-dd"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" @click="search">搜索</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div class="data-box">
+        <div class="table-box">
+          <el-table :data="tableData" border max-height="500" style="width: 100%">
+            <el-table-column prop="category" label="订单类型" width="180" />
+            <el-table-column prop="orderCount" label="订单数" />
+            <el-table-column prop="orderAmount" label="订单总金额(元)" />
+            <el-table-column prop="depositAmount" label="定金金额(元)" />
+            <el-table-column prop="codAmount" label="物流代收金额(元)" />
+          </el-table>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getHisOrderCountStats } from "@/api/company/statistics";
+import { getUserListByDeptId } from "@/api/company/companyUser";
+import { getCompanyList } from "@/api/company/company";
+
+export default {
+  name: "HisOrderCountStats",
+  data() {
+    return {
+      // 查询参数统一管理
+      queryParams: {
+        companyId: null,
+        companyUserId: null
+        // 其他参数如 pageNum 等在此场景非必需,可省略
+      },
+      companys: [],        // 公司列表
+      users: [],           // 员工列表
+      dateRange: [],       // 日期范围
+      tableData: []        // 表格数据
+    };
+  },
+  watch: {
+    // 监听公司变化,自动加载员工
+    'queryParams.companyId': {
+      handler(newVal) {
+        if (newVal != null) {
+          this.queryParams.companyUserId = null; // 清空员工选择
+          this.loadUsers();
+        } else {
+          this.users = [];
+          this.queryParams.companyUserId = null;
+        }
+      },
+      immediate: false
+    }
+  },
+  created() {
+    // 初始化公司列表
+    getCompanyList().then(response => {
+      this.companys = response.data || [];
+    });
+  },
+  methods: {
+    // 根据 companyId 加载员工
+    loadUsers() {
+      if (!this.queryParams.companyId) return;
+      getUserListByDeptId({ deptId: this.queryParams.companyId }).then(response => {
+        this.users = response.data || [];
+      });
+    },
+
+    // 搜索统计
+    search() {
+      const params = {
+        companyId: this.queryParams.companyId,
+        companyUserId: this.queryParams.companyUserId,
+        startTime: this.dateRange?.[0] || undefined,
+        endTime: this.dateRange?.[1] ? this.dateRange[1] + " 23:59:59" : undefined
+      };
+
+      getHisOrderCountStats(params).then(response => {
+        this.tableData = response.data || []; // 直接赋值数组
+      });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  border: 1px solid #e6e6e6;
+  padding: 12px;
+
+  .app-content {
+    background-color: white;
+    .title {
+      padding: 20px 30px 0px 30px;
+      font-size: 18px;
+      font-weight: bold;
+      color: black;
+    }
+    .search-form {
+      margin: 20px 30px 0px 30px;
+    }
+    .data-box {
+      padding: 30px;
+      background-color: rgb(255, 255, 255);
+      height: 100%;
+
+      .table-box {
+        margin-top: 15px;
+      }
+    }
+  }
+}
+</style>

+ 2 - 2
src/views/his/store/index.vue

@@ -232,7 +232,7 @@
             :on-success="licensehandleAvatarSuccess"
             :before-upload="beforeAvatarUpload">
             <img v-if="form.licenseImages" :src="form.licenseImages" class="avatar" width="200px">
-            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>          
           </el-upload>
         </el-form-item>
         <el-form-item label="店铺介绍" prop="descs" >
@@ -246,7 +246,7 @@
               v-model="form.cityIds"
               :options="citys"
               @change="handleCityChange">
-              </el-cascader>
+              </el-cascader>        
             </el-form-item>
           </el-col>
           <el-col :span="12">

+ 275 - 41
src/views/his/storeOrder/order1.vue

@@ -292,6 +292,17 @@
         </el-select>
       </el-form-item>
 
+      <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+        <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.id"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.id"
+          />
+        </el-select>
+      </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="changeTime"></el-date-picker>
       </el-form-item>
@@ -474,8 +485,8 @@
       <el-table ref="orderTable" height="500" v-loading="loading" border :data="orderList" @selection-change="handleSelectionChange"
         @sort-change="handleSortChange" :default-sort="{prop: 'createTime', order: 'descending'}">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="ERP电话" align="center" prop="erpPhone" v-if="SFDFopen && orderStatus!=null && orderStatus != 1"/>
-        <el-table-column label="ERP账号" align="center" prop="erpAccount" v-if="SFDFopen && orderStatus!=null && orderStatus != 1"/>
+        <el-table-column label="ERP电话" align="center" prop="erpPhone" width="120px" v-if="SFDFopen && orderStatus!=null && orderStatus != 1"/>
+        <el-table-column label="ERP账号" align="center" prop="erpAccount" width="120px" v-if="SFDFopen && orderStatus!=null && orderStatus != 1"/>
         <el-table-column label="处方单编号" align="center" prop="prescribeCode" width="180px"/>
         <el-table-column label="药品订单号" align="center" prop="orderCode" width="180px"/>
         <el-table-column label="所属公司" align="center" prop="companyName" />
@@ -486,6 +497,7 @@
           </template>
         </el-table-column>
         <el-table-column label="店铺名称" align="center" prop="storeName" />
+        <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
         <el-table-column label="就诊人" align="center" prop="patientName" />
         <el-table-column label="收货人" align="center" prop="userName" />
         <el-table-column label="套餐名称" align="center" prop="packageName" width="100px" sortable="custom" :sort-orders="['ascending', 'descending']">
@@ -514,6 +526,7 @@
         </el-table-column>
           <el-table-column label="下单时间" align="center" prop="createTime" width="180" />
         <el-table-column label="支付时间" align="center" prop="payTime" width="180" />
+        <el-table-column label="发货时间" align="center" prop="deliverySendTime" width="180" />
         <el-table-column label="订单状态" align="center" prop="status" >
           <template slot-scope="scope">
                 <dict-tag :options="orderOptions" :value="scope.row.status"/>
@@ -534,7 +547,7 @@
                 <dict-tag :options="deliveryPayStatusOptions" :value="scope.row.deliveryPayStatus"/>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right">
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100px" fixed="right">
           <template slot-scope="scope">
               <el-button
                   size="mini"
@@ -789,6 +802,50 @@
         >确认</el-button>
       </div>
     </el-dialog>
+
+    <!-- 导出字段选择对话框 -->
+    <el-dialog :title="exportFieldDialog.title" :visible.sync="exportFieldDialog.open" width="800px" append-to-body>
+      <div v-loading="exportFieldDialog.loading">
+        <div style="margin-bottom: 20px;">
+          <el-button type="primary" size="small" @click="selectAllFields">全选</el-button>
+          <el-button type="default" size="small" @click="unselectAllFields">全不选</el-button>
+          <el-button type="success" size="small" @click="selectDefaultFields">选择常用</el-button>
+        </div>
+        
+        <div class="field-selection-container">
+          <el-row :gutter="20">
+            <el-col :span="8" v-for="field in exportFieldOptions" :key="field.key">
+              <el-checkbox 
+                v-model="field.checked" 
+                :label="field.label"
+                style="margin-bottom: 12px; width: 100%;"
+              >
+                {{ field.label }}
+              </el-checkbox>
+            </el-col>
+          </el-row>
+        </div>
+        
+        <div class="field-count-info" style="margin-top: 20px; padding: 10px; background: #f5f7fa; border-radius: 4px;">
+          <i class="el-icon-info"></i>
+          <span v-if="getSelectedFieldsCount() > 0">
+            已选择 <span style="color: #409EFF; font-weight: bold;">{{ getSelectedFieldsCount() }}</span> 个字段
+          </span>
+          <span v-else style="color: #E6A23C; font-weight: bold;">
+            <i class="el-icon-warning"></i>
+            未选择任何字段,将导出所有字段
+          </span>
+        </div>
+      </div>
+      
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancelExportFieldDialog">取 消</el-button>
+        <el-button 
+          type="primary" 
+          @click="confirmExportFields"
+        >确认导出</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -804,6 +861,7 @@ import { treeselect } from "@/api/company/companyDept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "Order",
   components: { storeOrderDetails,Treeselect  },
@@ -926,6 +984,73 @@ export default {
       loading: true,
       // 导出遮罩层
       exportLoading: false,
+      // 导出字段选择弹窗
+      exportFieldDialog: {
+        open: false,
+        title: "选择导出字段",
+        loading: false
+      },
+      // 可选择的导出字段列表
+      exportFieldOptions: [
+        { key: 'orderCode', label: '订单号', checked: true },
+        { key: 'prescribeCode', label: '处方单号', checked: true },
+        { key: 'userId', label: '会员ID', checked: false },
+        { key: 'extendOrderId', label: '管易云订单号', checked: false },
+        { key: 'companyName', label: '所属公司', checked: true },
+        { key: 'companyUserNickName', label: '所属销售', checked: true },
+        { key: 'storeName', label: '店铺名称', checked: true },
+        { key: 'miniProgramName', label: '小程序名称', checked: true },
+        { key: 'orderType', label: '订单类型', checked: false },
+        { key: 'userName', label: '收货人姓名', checked: true },
+        { key: 'userPhone', label: '收货人电话', checked: true },
+        { key: 'userAddress', label: '详细地址', checked: true },
+        { key: 'totalPrice', label: '商品金额', checked: true },
+        { key: 'totalNum', label: '商品数量', checked: true },
+        { key: 'payPrice', label: '应付金额', checked: true },
+        { key: 'payMoney', label: '实付金额', checked: true },
+        { key: 'payRemain', label: '物流代收金额', checked: false },
+        { key: 'discountMoney', label: '优惠金额', checked: false },
+        { key: 'createTime', label: '下单时间', checked: true },
+        { key: 'payTime', label: '支付时间', checked: true },
+        { key: 'payType', label: '支付方式', checked: true },
+        { key: 'status', label: '订单状态', checked: true },
+        { key: 'refundTime', label: '退款时间', checked: false },
+        { key: 'deliverySendTime', label: '发货时间', checked: false },
+        { key: 'refundMoney', label: '退款金额', checked: false },
+        { key: 'deliveryCode', label: '快递公司编号', checked: false },
+        { key: 'deliveryName', label: '快递公司', checked: false },
+        { key: 'deliverySn', label: '快递单号', checked: false },
+        { key: 'remark', label: '备注', checked: false },
+        { key: 'deliveryPayStatus', label: '物流代收结算状态', checked: false },
+        { key: 'deliveryTime', label: '快递账单日期', checked: false },
+        { key: 'deliveryPayTime', label: '快递结算日期', checked: false },
+        { key: 'deliveryPayMoney', label: '物流结算费用', checked: false },
+        { key: 'deliveryStatus', label: '物流状态', checked: false },
+        { key: 'deliveryType', label: '物流跟踪状态', checked: false },
+        { key: 'packageName', label: '套餐名称', checked: true },
+        { key: 'packageSecondName', label: '套餐包别名', checked: false },
+        { key: 'orderBuyType', label: '订单购买类型', checked: false },
+        { key: 'channel', label: '公众号/渠道', checked: false },
+        { key: 'scheduleName', label: '档期归属', checked: false },
+        { key: 'tuiMoneyStatus', label: '推广佣金状态', checked: false },
+        { key: 'orderChannel', label: '渠道', checked: false },
+        { key: 'qwSubject', label: '企微主体', checked: false },
+        { key: 'cycle', label: '疗程天数', checked: false },
+        { key: 'followFrequency', label: '随访频率', checked: false },
+        { key: 'followCount', label: '随访次数', checked: false },
+        { key: 'patientName', label: '就诊人', checked: true },
+        { key: 'relation', label: '与本人关系', checked: false },
+        { key: 'user', label: '会员', checked: false },
+        { key: 'doctorName', label: '医生', checked: false },
+        { key: 'packageCateName', label: '套餐包分类', checked: false },
+        { key: 'age', label: '年龄', checked: false },
+        { key: 'sex', label: '性别', checked: false },
+        { key: 'erpPhone', label: 'ERP电话', checked: false },
+        { key: 'erpAccount', label: 'ERP账号', checked: false },
+        { key: 'source', label: '订单来源', checked: false }
+      ],
+      // 已选择的导出字段
+      selectedExportFields: [],
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -1010,6 +1135,7 @@ export default {
 		    source:null,
         companyId:null,
         companyIds:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -1029,6 +1155,7 @@ export default {
        storeOPtions:[],
        deliveryPayStatusOptions:[],
        deliveryStatusOptions:[],
+       appMallOptions:[],
     };
   },
   created() {
@@ -1093,6 +1220,7 @@ export default {
           this.deliveryStatusOptions = response.data;
     });
     this.getErpAccountList();
+    this.getAppMallOptions();
   },
   methods: {
     // 新增排序处理方法
@@ -1437,7 +1565,6 @@ export default {
           this.executeCreateErpOrder();
         });
       }
-      this.getList();
     },
 
     async executSetErpOrder() {
@@ -1488,6 +1615,7 @@ export default {
           this.$message.success('订单ERP账号设置成功');
           this.cancelErpAccountDialog();
           this.getErpAccountList(); // 刷新列表
+          this.getList();
         } else {
           this.$message.error(response.msg || 'ERP账号设置失败');
         }
@@ -1548,6 +1676,7 @@ export default {
           this.$message.success('ERP订单创建成功');
           this.cancelErpAccountDialog();
           this.getErpAccountList(); // 刷新列表
+          this.getList();
         } else {
           this.$message.error(response.msg || 'ERP订单创建失败');
         }
@@ -2113,64 +2242,154 @@ export default {
     },
     /** 导出按钮操作 */
     handleOrderExport() {
-		var that=this;
+      // 打开字段选择对话框
+      this.exportFieldDialog.open = true;
+    },
+    
+    // 导出字段选择相关方法
+    // 全选字段
+    selectAllFields() {
+      this.exportFieldOptions.forEach(field => {
+        field.checked = true;
+      });
+    },
+    
+    // 全不选字段
+    unselectAllFields() {
+      this.exportFieldOptions.forEach(field => {
+        field.checked = false;
+      });
+    },
+    
+    // 选择常用字段
+    selectDefaultFields() {
+      // 先全不选
+      this.unselectAllFields();
+      // 然后选择常用字段
+      const defaultFields = ['orderCode', 'prescribeCode', 'companyName', 'companyUserNickName', 
+                           'storeName', 'miniProgramName', 'userName', 'userPhone', 'userAddress', 'totalPrice', 
+                           'totalNum', 'payPrice', 'payMoney', 'createTime', 'payTime', 
+                           'payType', 'status', 'packageName', 'patientName'];
+      this.exportFieldOptions.forEach(field => {
+        if (defaultFields.includes(field.key)) {
+          field.checked = true;
+        }
+      });
+    },
+    
+    // 获取已选择字段数量
+    getSelectedFieldsCount() {
+      return this.exportFieldOptions.filter(field => field.checked).length;
+    },
+    
+    // 取消导出字段选择
+    cancelExportFieldDialog() {
+      this.exportFieldDialog.open = false;
+    },
+    
+    // 确认导出字段
+    confirmExportFields() {
+      // 获取已选择的字段
+      const selectedFieldsArray = this.exportFieldOptions.filter(field => field.checked);
+      
+      let selectedFields = '';
+      if (selectedFieldsArray.length === 0) {
+        // 如果没有选择任何字段,则导出全部字段(不传filter参数)
+        selectedFields = null;
+      } else {
+        // 如果选择了字段,则只导出选中的字段
+        selectedFields = selectedFieldsArray.map(field => field.key).join(',');
+      }
+      
+      // 关闭弹窗
+      this.exportFieldDialog.open = false;
+      
+      // 执行导出操作
+      this.doExportOrder(selectedFields);
+    },
+    
+    // 执行导出操作
+    doExportOrder(selectedFields) {
+      var that = this;
+      
+      // 处理查询参数
       if(this.payTypeArr.length>0){
         this.queryParams.payType=this.payTypeArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.payType=null
       }
+      
       if(this.scheduleIdArr.length>0){
         this.queryParams.scheduleId=this.scheduleIdArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.scheduleId=null
       }
+      
       if(this.buyTypeArr.length>0){
         this.queryParams.orderBuyType=this.buyTypeArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.orderbuyType=null
       }
+      
       if(this.channelArr.length>0){
         this.queryParams.orderChannel=this.channelArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.orderChannel=null
       }
+      
       if(this.qwSubjectArr.length>0){
         this.queryParams.qwSubject=this.qwSubjectArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.qwSubject=null
       }
+      
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有订单数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportOrder2(queryParams);
-        }).then(response => {
-			console.log(response)
-		  if(response.code==200){
-			  console.log(response.msg)
-		  that.msgSuccess(response.msg);
-		  that.taskId=response.data;
-		  that.time=setInterval(function(){
-			//查订单
-			getTask(that.taskId).then(res => {
-			  if(res.data.status==1){
-				that.exportLoading = false;
-				clearTimeout(that.time)
-				that.time=null;
-				that.download(res.data.fileUrl);
-			  }
-			});
-		  },10000);
-                }
-        }).catch(() => {});
+      
+      // 根据是否选择字段显示不同的确认消息
+      let confirmMessage = '';
+      if (selectedFields === null) {
+        confirmMessage = '没有选择字段,将导出所有字段的订单数据,确认继续?';
+      } else {
+        const fieldCount = selectedFields.split(',').length;
+        confirmMessage = `确认导出选中的 ${fieldCount} 个字段的订单数据?`;
+      }
+      
+      this.$confirm(confirmMessage, "确认导出", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        
+        // 构建请求参数
+        const requestParams = {...queryParams};
+        // 只有当selectedFields不为null时才添加filter参数
+        if (selectedFields !== null) {
+          requestParams.filter = selectedFields;
+        }
+        
+        return exportOrder2(requestParams);
+      }).then(response => {
+        console.log(response)
+        if(response.code==200){
+          console.log(response.msg)
+          that.msgSuccess(response.msg);
+          that.taskId=response.data;
+          that.time=setInterval(function(){
+            //查订单
+            getTask(that.taskId).then(res => {
+              if(res.data.status==1){
+                that.exportLoading = false;
+                clearTimeout(that.time)
+                that.time=null;
+                that.download(res.data.fileUrl);
+              }
+            });
+          },10000);
+        }
+      }).catch(() => {
+        this.exportLoading = false;
+      });
     },
       /** 查询部门下拉树结构 */
     getTreeselect() {
@@ -2207,6 +2426,12 @@ export default {
           this.queryParams.deptId=val;
           this.getList();
     },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>
@@ -2287,6 +2512,15 @@ export default {
   padding: 8px 0;
 }
 
+/* 表格布局优化 */
+.el-table {
+  min-width: 100%;
+  table-layout: fixed;
+}
+
+.el-table .el-table__body-wrapper {
+  overflow-x: auto;
+}
 
 .tip-text {
   display: flex;

+ 10 - 2
src/views/his/storeOrder/order2.vue

@@ -79,7 +79,6 @@
       </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>
@@ -186,6 +185,7 @@ import { listPrescribe, getPrescribe, delPrescribe, addPrescribe, updatePrescrib
 import prescribeDetails from '../../components/his/prescribeDetails.vue';
 import {allList}from "@/api/company/company";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "Prescribe",
   components: { prescribeDetails },
@@ -255,7 +255,8 @@ export default {
         auditSTime:null,
         auditETime:null,
         doctorName:null,
-        orderStatus:null
+        orderStatus:null,
+        appId:null
       },
        actName:"10",
       // 表单参数
@@ -267,6 +268,7 @@ export default {
       prescribeType:[],
       orOptions:[],
       sexOptions:[],
+      appMallOptions:[],
     };
   },
   created() {
@@ -287,9 +289,15 @@ export default {
         this.orderStatusOptions = response.data;
       });
 
+    this.getAppMallOptions();
     this.getList();
   },
   methods: {
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     getAllCompany() {
       allList().then(response => {
         this.companyList = response.rows;

+ 33 - 4
src/views/his/storePayment/index.vue

@@ -104,6 +104,16 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item> -->
+       <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+         <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+           <el-option
+             v-for="dict in appMallOptions"
+             :key="dict.id"
+             :label="dict.name + '(' + dict.appid + ')'"
+             :value="dict.id"
+           />
+         </el-select>
+       </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>
@@ -157,6 +167,7 @@
         </template>
       </el-table-column>
 
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
           <dict-tag :options="statusOptions" :value="scope.row.status"/>
@@ -213,6 +224,7 @@ import { listStorePayment, getStorePayment, delStorePayment, addStorePayment, up
 import { getTask } from "@/api/common";
 import storePayDetails from '../../components/his/storePayDetails.vue';
 import { getCompanyList } from "@/api/company/company";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "StorePayment",
   components: { storePayDetails },
@@ -251,6 +263,7 @@ export default {
       statusOptions: [],
       busineOptitons: [],
        actName:"10",
+      appMallOptions:[],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -274,6 +287,7 @@ export default {
         storeId: null,
         businessCode:null,
         phone:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -299,6 +313,9 @@ export default {
     this.getDicts("sys_store_payment_share_status").then(response => {
       this.shareOptions = response.data;
     });
+
+    // 获取小程序选项列表
+    this.getAppMallOptions();
   },
   methods: {
     handleClickX(tab, event) {
@@ -356,9 +373,15 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
-       this.createTime=null;
-        this.queryParams.sTime=null;
-        this.queryParams.eTime=null;
+      this.createTime=null;
+      this.queryParams.sTime=null;
+      this.queryParams.eTime=null;
+      this.queryParams.refundBeginTime=null;
+      this.queryParams.refundEndTime=null;
+      this.queryParams.payBeginTime=null;
+      this.queryParams.payEndTime=null;
+      this.refundTime=null
+      this.payTime=null
       this.handleQuery();
     },
     change(){
@@ -476,7 +499,13 @@ export default {
           },10000);
         }
         }).catch(() => {});
-    }
+    },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>

+ 52 - 3
src/views/his/user/index.vue

@@ -66,6 +66,17 @@
                  />
         </el-select>
       </el-form-item>
+
+      <el-form-item label="推广员" prop="isPromoter">
+        <el-select v-model="queryParams.isPromoter" placeholder="请选择推广员" clearable size="small">
+          <el-option
+            v-for="dict in userIsPromoterOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item label="注册时间" prop="createTime">
                 <el-date-picker v-model="createTime" size="small" style="width: 230px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
       </el-form-item>
@@ -122,6 +133,7 @@
           <dict-tag :options="userLevelOptions" :value="scope.row.level"/>
         </template>
       </el-table-column>
+
       <el-table-column label="上级昵称" align="center" prop="tuiName" />
       <el-table-column label="app来源" align="center" prop="source" />
       <el-table-column label="登陆设备" align="center" prop="loginDevice" />
@@ -170,7 +182,7 @@
     />
 
     <!-- 添加或修改用户对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="用户昵称" prop="nickName">
           <el-input v-model="form.nickName" placeholder="请输入用户昵称" />
@@ -196,6 +208,36 @@
             />
           </el-select>
         </el-form-item>
+        <el-form-item label="会员昵称" prop="nickname">
+          <el-input v-model="form.nickname" placeholder="请输入用户昵称" />
+        </el-form-item>
+        <el-form-item label="手机号码" prop="phone">
+          <el-input v-model="form.phone" disabled placeholder="请输入手机号码" />
+        </el-form-item>
+        <el-form-item label="进线日期" prop="registerDate">
+          <el-date-picker clearable size="small"
+                          v-model="form.registerDate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="选择进线日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="推线编码" prop="registerCode">
+          <el-input v-model="form.registerCode" placeholder="请输入推线编码" />
+        </el-form-item>
+        <el-form-item label="渠道来源" prop="source">
+          <el-input v-model="form.source" placeholder="请输入渠道来源" />
+        </el-form-item>
+        <el-form-item label="是否为推广员" prop="isPromoter">
+          <el-select style="width: 200px" v-model="form.isPromoter" placeholder="请选择" clearable size="small" >
+            <el-option
+              v-for="item in userIsPromoterOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item label="用户备注" prop="remark" >
           <el-input v-model="form.remark" placeholder="请输入用户备注" type="textarea"/>
         </el-form-item>
@@ -243,6 +285,7 @@ export default {
   components: {userDetails,userDetailsByNew},
   data() {
     return {
+      userIsPromoterOptions:[],
       companyName: null,
       companyUserNickName: null,
       companyOptions: [],
@@ -252,7 +295,8 @@ export default {
               open:false,
             },
       userOptions: [],
-      userLevelOptions:[], // 用户等级
+      // 用户等级
+      userLevelOptions:[],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -351,6 +395,10 @@ export default {
     this.getDicts("user_level").then(response => {
       this.userLevelOptions = response.data;
     });
+    this.getDicts("user_is_promoter").then((response) => {
+      this.userIsPromoterOptions = response.data;
+    });
+
   },
   methods: {
     /** 销售选择变化 */
@@ -399,10 +447,10 @@ export default {
         phone: null,
         integral: null,
         status: null,
-        level:null,
         tuiUserId: null,
         tuiTime: null,
         tuiUserCount: null,
+        level:null,
         maOpenId: null,
         mpOpenId: null,
         unionId: null,
@@ -451,6 +499,7 @@ export default {
         this.title = "修改用户";
         this.form.status = String(this.form.status)
         this.form.level = String(this.form.level)
+
       });
     },
     /** 提交按钮 */

+ 1 - 1
src/views/his/user/indexProject.vue

@@ -246,7 +246,7 @@
             type="text"
             icon="el-icon-delete"
             @click="handleDelete(scope.row)"
-            v-hasPermi="['store:user:remove']"
+            v-hasPermi="['his:userCompanyUser:remove']"
           >删除</el-button>
         </template>
       </el-table-column>

+ 0 - 310
src/views/his/userTag/index.vue

@@ -1,310 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="企业名称" prop="companyId">
-        <el-select  v-model="queryParams.companyId" placeholder="请选择销售公司" size="small" clearable @change="handleCompanyChange" style="width: 180px" >
-          <el-option
-            v-for="company in companyOptions"
-            :key="company.companyId"
-            :label="company.companyName"
-            :value="company.companyId"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="标签" prop="tag">
-        <el-input
-          v-model="queryParams.tag"
-          placeholder="请输入标签"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['tag:tag:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['tag:tag:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['tag:tag:remove']"
-        >删除</el-button>
-      </el-col>
-      <!-- <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          :loading="exportLoading"
-          @click="handleExport"
-          v-hasPermi="['tag:tag:export']"
-        >导出</el-button>
-      </el-col> -->
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table border v-loading="loading" :data="tagList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="id" align="center" prop="tagId"  />
-      <el-table-column label="企业名称" align="center" prop="companyName" >
-        <template slot-scope="scope">
-          <el-tag prop="companyId" v-for="item in companyOptions"
-                  :key="item.companyId"
-                  v-show="scope.row.companyId === item.companyId">
-            {{item.companyName}}
-          </el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="标签" align="center" prop="tag" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['tag:tag:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['tag:tag:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 添加或修改小程序会员标签对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="企业名称" prop="companyId" >
-          <el-select  v-model="form.companyId" placeholder="请选择销售公司" size="small" clearable style="width: 180px" >
-            <el-option
-              v-for="company in companyOptions"
-              :key="company.companyId"
-              :label="company.companyName"
-              :value="company.companyId"
-            />
-        </el-select>
-        </el-form-item>
-        <el-form-item label="标签" prop="tag">
-          <el-input v-model="form.tag" placeholder="请输入标签" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { listTag, getTag, delTag, addTag, updateTag, exportTag } from "@/api/his/userTag";
-import { listCompany } from '@/api/his/company'
-
-export default {
-  name: "Tag",
-  data() {
-    return {
-      companyOptions: [],
-      // 遮罩层
-      loading: true,
-      // 导出遮罩层
-      exportLoading: false,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 小程序会员标签表格数据
-      tagList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        companyId: null,
-        tag: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-        companyId: [
-          { required: true, message: "企业名称不能为空", trigger: "change" }
-        ],
-        tag: [
-          { required: true, message: "标签不能为空", trigger: "blur" }
-        ]
-      }
-    };
-  },
-  created() {
-    listCompany().then(res => {
-      this.companyOptions = res.rows;
-      // this.companyOptions = this.companyIntiOptions.filter(item => item.deptId === this.deptId);
-    });
-    this.getList();
- 
-  },
-  methods: {
-    handleCompanyChange(){
-      this.getList();
-    },
-    /** 查询小程序会员标签列表 */
-    getList() {
-      this.loading = true;
-      listTag(this.queryParams).then(response => {
-        this.tagList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        tagId: null,
-        companyId: null,
-        tag: null,
-        createTime: null
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.tagId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加小程序会员标签";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const tagId = row.tagId || this.ids
-      getTag(tagId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改小程序会员标签";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.tagId != null) {
-            updateTag(this.form).then(response => {
-              this.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addTag(this.form).then(response => {
-              this.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const tagIds = row.tagId || this.ids;
-      this.$confirm('是否确认删除小程序会员标签编号为"' + tagIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delTag(tagIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有小程序会员标签数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportTag(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
-    }
-  }
-};
-</script>

+ 0 - 580
src/views/hospital/hospital/index.vue

@@ -1,580 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="诊所名称" prop="hospitalName">
-        <el-input
-        style="width: 220px"
-          v-model="queryParams.hospitalName"
-          placeholder="请输入诊所名称"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="联系电话" prop="companyMobile">
-        <el-input
-          v-model="queryParams.companyMobile"
-          placeholder="请输入联系电话"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-     
-      <el-form-item label="状态" prop="status">
-        <el-select style="width: 220px" v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
-              <el-option
-                v-for="dict in statusOptions"
-                :key="dict.dictValue"
-                :label="dict.dictLabel"
-                :value="dict.dictValue"
-              />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['hospital:hospital:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['hospital:hospital:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['hospital:hospital:remove']"
-        >删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['hospital:hospital:export']"
-        >导出</el-button>
-      </el-col>
-	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table  height="660" border v-loading="loading" :data="hospitalList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="ID" align="center" prop="hospitalId" />
-      <el-table-column label="诊所名称" align="center" prop="hospitalName" />
-      <el-table-column label="管理员帐号" width="100px" align="center" prop="userName" />
-      <el-table-column label="余额" align="center" prop="money" />
-      <el-table-column label="联系电话" align="center" prop="hospitalMobile" />
-      <el-table-column label="用户数量" align="center" prop="limitUserCount" />
-      <el-table-column label="地址" align="center" prop="address" />
-      <el-table-column label="执照" align="center" prop="licenseUrl" width="120">
-         <template slot-scope="scope">
-           <el-popover
-             placement="right"
-             title=""
-             trigger="hover"
-           >
-             <img slot="reference" :src="scope.row.licenseUrl" width="100">
-             <img :src="scope.row.licenseUrl" style="max-width: 150px;">
-           </el-popover>
-         </template>
-      </el-table-column>
-      <el-table-column label="状态" align="center" prop="status" >
-        <template slot-scope="scope">
-              <el-tag prop="status" v-for="(item, index) in statusOptions"  :type="scope.row.status==1?'success':'danger'"  v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="创建时间" align="center" prop="createTime">
-      </el-table-column>
-      <!-- <el-table-column label="到期时间" align="center" prop="limitTime">
-      </el-table-column> -->
-      <el-table-column label="操作" align="center"  fixed="right" width="200px" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            style="margin-left:10px"
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['hospital:hospital:edit']"
-          >编辑</el-button>
-           
-           <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleResetPwd(scope.row)"
-            v-hasPermi="['hospital:hospital:resetPwd']"
-          >重置密码</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['hospital:hospital:remove']"
-          >删除</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleRecharge(scope.row)"
-            v-hasPermi="['hospital:hospital:recharge']"
-          >充值</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleDeduct(scope.row)"
-            v-hasPermi="['hospital:hospital:deduct']"
-          >扣款</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-
-    <!-- 添加或修改企业对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="650px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
-        <el-form-item label="诊所名称" prop="hospitalName">
-          <el-input v-model="form.hospitalName" placeholder="请输入诊所名称" />
-        </el-form-item>
-        <el-form-item label="诊所执照" prop="licenseUrl">
-          <el-upload
-              v-model="form.licenseUrl"
-              class="avatar-uploader"
-              :action="uploadUrl"
-              :show-file-list="false"
-              :on-success="handleAvatarSuccess"
-              :before-upload="beforeAvatarUpload">
-              <img v-if="form.licenseUrl" :src="form.licenseUrl" class="avatar" width="200px">
-              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
-          </el-upload>
-        </el-form-item>
-        <el-form-item label="联系电话" prop="mobile">
-          <el-input v-model="form.mobile" placeholder="请输入联系电话" />
-        </el-form-item>
-        <el-form-item label="员工数量" prop="limitUserCount">
-          <el-input-number v-model="form.limitUserCount"  :min="1" :max="10000"  ></el-input-number>
-        </el-form-item>
-        <el-form-item  label="管理员帐号" prop="userName" v-if="form.hospitalId==null">
-          <el-input v-model="form.userName" placeholder="请输入管理员帐号" />
-        </el-form-item>
-         <el-form-item  label="管理员密码" prop="password" v-if="form.hospitalId==null">
-          <el-input type="password" v-model="form.password" placeholder="请输入管理员密码" />
-        </el-form-item>
-        <el-form-item label="地址" prop="address">
-          <el-input v-model="form.address" placeholder="请输入地址" />
-        </el-form-item>
-        <el-form-item label="状态" prop="status">
-           <el-radio-group v-model="form.status">
-            <el-radio v-for="dict in statusOptions" :label="dict.dictValue">{{dict.dictLabel}}</el-radio>
-          </el-radio-group>
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-    <el-dialog :title="recharge.title" :visible.sync="recharge.open" width="500px" append-to-body>
-      <el-form ref="rechargeForm" :rules="rechargeRules" :model="rechargeForm"  label-width="80px">
-        <el-form-item label="诊所" >
-          <el-input v-model="rechargeForm.hospitalName" disabled />
-        </el-form-item>
-        <el-form-item label="余额" >
-          <el-input v-model="rechargeForm.balance" disabled />
-        </el-form-item>
-        <el-form-item label="充值金额" prop="money">
-          <el-input-number v-model="rechargeForm.money" :min="0" placeholder="请输入充值金额" />
-        </el-form-item>
-        <el-form-item label="备注" prop="remark">
-          <el-input v-model="rechargeForm.remark" placeholder="请输入备注" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitRechargeForm">确 定</el-button>
-        <el-button @click="recharge.open=false">取 消</el-button>
-      </div>
-    </el-dialog>
-    <el-dialog :title="deduct.title" :visible.sync="deduct.open" width="500px" append-to-body>
-      <el-form ref="deductForm" :rules="deductRules" :model="deductForm"  label-width="80px">
-        <el-form-item label="诊所" >
-          <el-input v-model="deductForm.hospitalName" disabled />
-        </el-form-item>
-        <el-form-item label="余额" >
-          <el-input v-model="deductForm.balance" disabled />
-        </el-form-item>
-        <el-form-item label="扣款金额" prop="money">
-          <el-input-number v-model="deductForm.money" :min="0" placeholder="请输入扣款金额" />
-        </el-form-item>
-        <el-form-item label="备注" prop="remark">
-          <el-input v-model="deductForm.remark" placeholder="请输入备注" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitDeductForm">确 定</el-button>
-        <el-button @click="deduct.open=false">取 消</el-button>
-      </div>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import {recharge,deduct, resetPwd,listHospital, getHospital, delHospital, addHospital, updateHospital, exportHospital } from "@/api/hospital/hospital";
-
-
-export default {
-  name: "hospital",
-  data() {
-    return {
-      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
-      // 表单参数
-      rechargeForm: {
-        money:0,
-      },
-      // 表单校验
-      rechargeRules: {
-        money: [
-          { required: true, message: "充值金额不能为空", trigger: "blur" }
-        ],
-      },
-      recharge:{
-        open:false,
-        title:"后台充值"
-      },
-      // 表单参数
-      deductForm: {
-        money:0,
-      },
-      // 表单校验
-      deductRules: {
-        money: [
-          { required: true, message: "扣款金额不能为空", trigger: "blur" }
-        ],
-      },
-      deduct:{
-        open:false,
-        title:"后台扣款"
-      },
-      packageIds: [],
-      packages:[],
-      typeOptions:[],
-      statusOptions:[],
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 企业表格数据
-      hospitalList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        hospitalName: null,
-        mobile: null,
-        address: null,
-        status: null,
-        startTime: null,
-        endTime: null,
-        money: null,
-        times: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-        hospitalName: [
-          { required: true, message: "诊所名称不能为空", trigger: "blur" }
-        ],
-        licenseUrl:[
-          { required: true, message: "诊所执照不能为空", trigger: "blur" }
-        ],
-        mobile: [
-          { required: true, message: "诊所电话不能为空", trigger: "blur" }
-        ],
-        address: [
-          { required: true, message: "诊所地址不能为空", trigger: "blur" }
-        ],
-        limitUserCount: [
-          { required: true, message: "用户数量不能为空", trigger: "blur" }
-        ],
-        userName: [
-          { required: true, message: "帐号不能为空", trigger: "blur" }
-        ],
-        password: [
-          { required: true, message: "密码不能为空", trigger: "blur" }
-        ],
-        status: [
-          { required: true, message: "状态不能为空", trigger: "blur" }
-        ],
-      }
-    };
-  },
-  created() {
-    this.getDicts("sys_company_status").then((response) => {
-      this.statusOptions = response.data;
-    });
-    this.getDicts("sys_hospital_type").then((response) => {
-      this.typeOptions = response.data;
-    });
-    this.getList();
-  },
-  methods: {
-    handleAvatarSuccess(res, file) {
-            if(res.code==200){
-              this.form.licenseUrl=res.url;
-              console.log(this.form.licenseUrl)
-              // self.$forceUpdate()
-            }
-            else{
-              this.msgError(res.msg);
-            }
-        },
-        beforeAvatarUpload(file) {
-          const isLt1M = file.size / 1024 / 1024 < 1;
-          if (!isLt1M) {
-            this.$message.error('上传图片大小不能超过 1MB!');
-          }
-          return   isLt1M;
-        },
-    handleDeduct(row) {
-      const hospitalId = row.hospitalId  
-      this.deductForm.hospitalId=row.hospitalId;
-      this.deductForm.hospitalName=row.hospitalName;
-      this.deductForm.balance=row.money;
-      this.deduct.open = true;
-    },
-    /** 提交按钮 */
-    submitDeductForm() {
-      this.$refs["deductForm"].validate(valid => {
-        if (valid) {
-          deduct(this.deductForm).then(response => {
-            if (response.code === 200) {
-              this.msgSuccess(response.msg);
-              this.deduct.open = false;
-              this.getList();
-            }
-          });
-        }
-      });
-    },
-    handleRecharge(row) {
-      const hospitalId = row.hospitalId  
-      this.rechargeForm.hospitalId=row.hospitalId;
-      this.rechargeForm.hospitalName=row.hospitalName;
-      this.rechargeForm.balance=row.money;
-      this.recharge.open = true;
-    },
-    /** 提交按钮 */
-    submitRechargeForm() {
-      this.$refs["rechargeForm"].validate(valid => {
-        if (valid) {
-          recharge(this.rechargeForm).then(response => {
-            if (response.code === 200) {
-              this.msgSuccess(response.msg);
-              this.recharge.open = false;
-              this.getList();
-            }
-          });
-        }
-      });
-    },
-    /** 查询企业列表 */
-    getList() {
-      this.loading = true;
-      listHospital(this.queryParams).then(response => {
-        this.hospitalList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        hospitalId: null,
-        hospitalName: null,
-        hospitalMobile: null,
-        hospitalAddress: null,
-        createTime: null,
-        updateTime: null,
-        status: '0',
-        startTime: null,
-        endTime: null,
-        money: null,
-        times: null,
-        voiceApiId: null
-      };
-      this.packageIds=[];
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.hospitalId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "创建诊所";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const hospitalId = row.hospitalId || this.ids
-      getHospital(hospitalId).then(response => {
-        this.form = response.data;
-        this.form.status = response.data.status.toString();
-        this.open = true;
-        this.title = "修改诊所";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.hospitalId != null) {
-            updateHospital(this.form).then(response => {
-              if (response.code === 200) {
-                this.msgSuccess("修改成功");
-                this.open = false;
-                this.getList();
-              }
-            });
-          } else {
-            addHospital(this.form).then(response => {
-              if (response.code === 200) {
-                this.msgSuccess("新增成功");
-                this.open = false;
-                this.getList();
-              }
-            });
-          }
-        }
-      });
-    },
-    
-    handleResetPwd(row) {
-      const hospitalIds = row.hospitalId || this.ids;
-      this.$confirm('是否确认重复密码为123456?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return resetPwd(hospitalIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("修改成功");
-        }).catch(function() {});
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const hospitalIds = row.hospitalId || this.ids;
-      this.$confirm('是否确认删除诊所编号为"' + hospitalIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delhospital(hospitalIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(function() {});
-    },
-
-    /** 导出按钮操作 */
-    handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有诊所数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return exporthospital(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-        }).catch(function() {});
-    },
-    
-    
-  }
-};
-</script>
-
-<style>
-.avatar-uploader .el-upload {
-     border: 1px dashed #d9d9d9;
-     border-radius: 6px;
-     cursor: pointer;
-     position: relative;
-     overflow: hidden;
-   }
-   .avatar-uploader .el-upload:hover {
-     border-color: #409EFF;
-   }
-
-   .avatar-uploader-icon {
-     font-size: 28px;
-     color: #8c939d;
-     width: 150px;
-     height: 150px;
-     line-height: 150px;
-     text-align: center;
-   }
-</style>

+ 1 - 1
src/views/qw/externalContact/index.vue

@@ -2,7 +2,7 @@
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px" style="border: 1px solid transparent">
       <el-form-item label="销售公司" prop="companyId">
-        <el-select v-model="queryParams.companyId" placeholder="销售公司"  size="small" @change="getAllUserlist(queryParams.companyId)" clearable>
+        <el-select v-model="queryParams.companyId" placeholder="销售公司"  size="small" @change="getAllUserlist(queryParams.companyId)">
           <el-option
               v-for="dict in qwCompanyList"
               :key="dict.companyId"

+ 342 - 0
src/views/qw/externalContactTransferAudit/index.vue

@@ -0,0 +1,342 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="主体名称" prop="corpId">
+        <el-select v-model="queryParams.corpId" placeholder="请选择主体名称" clearable filterable>
+          <el-option
+            v-for="item in corpOptions"
+            :key="item.CorpId"
+            :label="item.corpName"
+            :value="item.CorpId">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="公司名称" prop="companyName">
+        <el-input
+          v-model="queryParams.companyName"
+          placeholder="请输入销售公司名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="销售名称" prop="companyUserName">
+        <el-input
+          v-model="queryParams.companyUserName"
+          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 >
+          <el-option :value="0" label="全部"/>
+          <el-option
+            v-for="item in auditStatusOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="list" border>
+      <el-table-column label="ID" align="center" prop="id" width="80px"/>
+      <el-table-column label="接替公司名称" align="center" prop="companyName" />
+      <el-table-column label="主体名称" align="center">
+        <template slot-scope="scope">
+          {{ getCorpNameByCorpId(scope.row.corpId) || scope.row.corpName }}
+        </template>
+      </el-table-column>
+      <el-table-column label="接替销售名称" align="center" prop="companyUserName" />
+      <el-table-column label="接替企微用户名称" align="center" prop="qwUserName" />
+      <el-table-column label="审核状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="auditStatusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="提交时间" align="center" prop="createTime" />
+      <el-table-column label="审核时间" align="center" prop="auditTime" />
+      <el-table-column label="被拒原因" align="center" prop="reason" />
+      <el-table-column label="提交人" align="center" prop="createBy" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleAudit(scope.row)"
+            v-if="scope.row.status === 1"
+            v-hasPermi="['qw:externalContactTransferCompanyAudit:audit']"
+          >审核</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleView(scope.row)"
+            v-hasPermi="['qw:externalContactTransferCompanyAudit:detail']"
+          >详情</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-dialog title="审核" :visible.sync="dialogAuditVisible" width="800px" append-to-body>
+      <el-form :model="from" ref="auditForm" :rules="rules" label-width="100px">
+        <el-form-item label="审核结果" prop="type">
+          <el-radio-group v-model="from.type">
+            <el-radio label="1">通过</el-radio>
+            <el-radio label="2">拒绝</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="from.type === '2'" label="拒绝原因" prop="reason">
+          <el-input type="textarea" :rows="2" v-model="from.reason" placeholder="请输入拒绝原因" clearable size="small" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary"
+                   @click="submitForm"
+                   :disabled="submitLoading"
+                   :loading="submitLoading">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-drawer title="详情" size="75%" :visible.sync="dialogViewVisible" append-to-body>
+      <el-table v-loading="detailLoading" :data="userList" border>
+        <el-table-column label="ID" align="center" prop="id" />
+        <el-table-column label="客户名称" align="center" prop="externalUserName" />
+        <el-table-column label="原公司名称" align="center" prop="companyName" />
+        <el-table-column label="原销售名称" align="center" prop="companyUserName" />
+        <el-table-column label="原企微用户名称" align="center" prop="qwUserName" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="接替状态" align="center" prop="status">
+          <template slot-scope="scope">
+            <dict-tag :options="replaceStatusOptions" :value="scope.row.status"/>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        v-show="detailTotal>0"
+        :total="detailTotal"
+        :page.sync="detailQueryParams.pageNum"
+        :limit.sync="detailQueryParams.pageSize"
+        @pagination="handleDetailPagination"
+      />
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { audit, detail, listExternalContactTransferAudit } from '@/api/qw/externalContactTransferAudit'
+import { getMyQwCompanyList } from '@/api/qw/user'
+
+export default {
+  name: "externalContactTransferAudit",
+  data() {
+    return {
+      loading: false,
+      showSearch: true,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyName: null,
+        corpId: null,
+        companyUserName: null,
+        status: 0,
+      },
+      total: 0,
+      list: [],
+      auditStatusOptions: [],
+      replaceStatusOptions: [],
+      dialogAuditVisible: false,
+      dialogViewVisible: false,
+      detailLoading: false,
+      userList: [],
+      detailTotal: 0,
+      detailQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        auditId: null
+      },
+      from: {
+        id: null,
+        type: null,
+        reason: null
+      },
+      rules: {
+        type: [
+          { required: true, message: "请选择审核结果", trigger: "blur" }
+        ]
+      },
+      submitLoading: false,
+      corpOptions: [],
+    }
+  },
+  created() {
+    this.getDicts("sys_qw_transfer_audit_status").then((response) => {
+      this.auditStatusOptions = response.data;
+    });
+    this.getDicts("sys_qw_transfer_status").then((response) => {
+      this.replaceStatusOptions = response.data;
+    });
+    this.getCorpOptions()
+    this.handleQuery()
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        companyName: null,
+        corpId: null,
+        companyUserName: null,
+        status: 0,
+      };
+      this.$nextTick(() => {
+        this.resetForm("queryForm");
+        this.handleQuery();
+      });
+    },
+    getCorpOptions() {
+      // 调用接口获取主体名称下拉选项
+      getMyQwCompanyList().then(response => {
+        console.log('获取到的主体名称数据:', response.data);
+        if (response.data && Array.isArray(response.data)) {
+          // 确保CorpId和corpName字段正确处理
+          this.corpOptions = response.data.map(item => {
+            return {
+              CorpId: item.dictValue ? item.dictValue.toString() : '',  // 使用corpId而不是CorpId
+              corpName: item.dictLabel || ''
+            };
+          });
+          console.log('处理后的corpOptions:', this.corpOptions);
+        } else {
+          this.corpOptions = [];
+        }
+      }).catch(error => {
+        console.error('获取主体名称列表失败:', error);
+        this.corpOptions = [];
+      });
+    },
+    // 添加一个方法来根据CorpId获取corpName
+    getCorpNameByCorpId(corpId) {
+      if (!corpId || !this.corpOptions || this.corpOptions.length === 0) {
+        return '';
+      }
+      
+      // 查找匹配的corpName
+      const corp = this.corpOptions.find(item => item.CorpId === (corpId ? corpId.toString() : ''));
+      return corp ? corp.corpName : '';
+    },
+    getList() {
+      this.loading = true
+      const params = {
+        ...this.queryParams,
+        status: this.queryParams.status === 0 ? null : this.queryParams.status
+      }
+      
+      // 如果选择了主体名称,则将其作为corpId传递,否则删除该参数
+      if (this.queryParams.corpId) {
+        params.corpId = this.queryParams.corpId;
+      } else {
+        delete params.corpId;
+      }
+      
+      listExternalContactTransferAudit(params).then(response => {
+        this.list = response.rows.map(item => {
+          return {
+            ...item,
+            corpId: item.corpId ? item.corpId.toString() : item.corpId, // 确保corpId也是字符串类型
+            createTime: item.createTime ? item.createTime.replace("T", " ") : null,
+            auditTime: item.auditTime ? item.auditTime.replace("T", " ") : null,
+          }
+        })
+        this.total = response.total
+        this.loading = false
+      })
+    },
+    reset() {
+      this.from = {
+        id: null,
+        type: null,
+        reason: null
+      }
+      this.resetForm("auditForm")
+    },
+    handleAudit(row) {
+      this.reset()
+      this.from.id = row.id
+      this.submitLoading = false
+      this.dialogAuditVisible = true
+    },
+    handleView(row) {
+      this.detailLoading = true
+      this.detailQueryParams.auditId = row.id
+      this.detailQueryParams.pageNum = 1
+      this.getDetailList()
+      this.dialogViewVisible = true
+    },
+    handleDetailPagination({ page, limit }) {
+      this.detailQueryParams.pageNum = page
+      this.detailQueryParams.pageSize = limit
+      this.getDetailList()
+    },
+    getDetailList() {
+      this.detailLoading = true
+      // 确保传递正确的分页参数
+      const params = {
+        pageNum: this.detailQueryParams.pageNum,
+        pageSize: this.detailQueryParams.pageSize
+      };
+      
+      detail(this.detailQueryParams.auditId, params).then(response => {
+        this.userList = response.rows
+        this.detailTotal = response.total
+        this.detailLoading = false
+      }).catch(() => {
+        this.detailLoading = false
+      })
+    },
+    submitForm() {
+      this.$refs["auditForm"].validate(valid => {
+        if (valid) {
+          if (this.submitLoading) {
+             return
+          }
+          this.submitLoading = true
+          const params = {
+            auditId: this.from.id,
+            type: this.from.type,
+            reason: this.from.reason
+          }
+          audit(params).then(() => {
+            this.$message.success("操作成功, 请在详情查看转接结果");
+            this.dialogAuditVisible = false
+            this.getList()
+          })
+        }
+      })
+    },
+    cancel() {
+      this.dialogAuditVisible = false
+      this.reset()
+    },
+  }
+}
+</script>

+ 39 - 1
src/views/qw/qwCompany/index.vue

@@ -178,7 +178,18 @@
           <el-input v-model="form.serverAgentId" placeholder="请输入serverAgentId" />
         </el-form-item>
         <el-form-item label="小程序id" prop="miniAppId" >
-          <el-input v-model="form.miniAppId" placeholder="请输入小程序id" />
+          <el-select
+            v-model="form.miniAppId"
+            placeholder="请选择"
+            size="small"
+          >
+            <el-option
+              v-for="item in miniAppList"
+              :key="item.appId"
+              :label="item.appName"
+              :value="item.appId"
+            />
+          </el-select>
         </el-form-item>
         <el-form-item label="企业可信IP" >
           <div>42.194.245.189;119.29.195.254;129.204.130.233;43.138.187.210;129.204.76.229;159.75.239.132119.29.249.66;122.152.230.82</div>
@@ -223,6 +234,7 @@
 <script>
 import { listQwCompany, getQwCompany, delQwCompany, addQwCompany, updateQwCompany, exportQwCompany } from "@/api/qw/qwCompany";
 import { getCompanyList } from "@/api/company/company";
+import { listAll } from '@/api/course/coursePlaySourceConfig'
 export default {
   name: "QwCompany",
   watch: {
@@ -288,6 +300,9 @@ export default {
       // 表单参数
       form: {},
       companys:[],
+      maAppList:[],
+      miniAppList:[],
+      customAppList:[],
       // 表单校验
       rules: {
         corpId: [{ required: true, message: '请输入企业CorpID', trigger: 'blur' }],
@@ -358,6 +373,27 @@ export default {
       this.resetForm("queryForm");
       this.handleQuery();
     },
+    getAppList() {
+      this.maAppList = []
+      this.miniAppList = []
+      this.customAppList = []
+      listAll().then(response => {
+        const { code, data } = response
+        if (code === 200) {
+          if (data) {
+            this.maAppList = data.filter(v => v.type == 2).map(v => {
+              return { appId: v.appid, appName: v.name }
+            })
+            this.miniAppList = data.filter(v => v.type == 1).map(v => {
+              return { appId: v.appid, appName: v.name }
+            })
+            this.customAppList = data.filter(v => v.type == 3).map(v => {
+              return { appId: v.appid, appName: v.name }
+            })
+          }
+        }
+      })
+    },
     // 多选框选中数据
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.id)
@@ -367,6 +403,7 @@ export default {
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
+      this.getAppList()
       this.open = true;
       this.form.token="1o62d3YxvdHd4LEUiltnu7sK";
       this.form.encodingAesKey="UJfTQ5qKTKlegjkXtp1YuzJzxeHlUKvq5GyFbERN1iU";
@@ -375,6 +412,7 @@ export default {
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
+      this.getAppList()
       const id = row.id || this.ids
       getQwCompany(id).then(response => {
         this.form = response.data;

+ 18 - 1
src/views/qw/sop/sop.vue

@@ -1,6 +1,16 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="销售公司" prop="companyId">
+        <el-select filterable v-model="queryParams.companyId" clearable placeholder="请选择公司名" 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 label="规则编号" prop="id">
         <el-input
           v-model="queryParams.id"
@@ -150,6 +160,7 @@
 import { listSop, exportSop, } from "@/api/qw/sop";
 
 import sopLogsDetails from '@/views/qw/sopLogs/sopLogsList.vue'
+import { getCompanyList } from '@/api/company/company'
 export default {
   name: "Sop",
     components: { sopLogsDetails},
@@ -168,6 +179,7 @@ export default {
       myQwCompanyList:[],
       //销售员工列表
       companyUserLists:[],
+      companys: [],
       courseList:[],
       // videoList:[],
       tags:null,
@@ -227,7 +239,8 @@ export default {
         setting: null,
         createBy: null,
         corpId: null,
-        createTime: null
+        createTime: null,
+        companyId: null
       },
       sopLogsDialog:{
         title:'',
@@ -272,6 +285,10 @@ export default {
     this.getDicts("sys_qw_sop_type").then(response => {
       this.sysQwSopType = response.data;
     });
+
+    getCompanyList().then(response => {
+      this.companys = response.data;
+    });
     this.getList();
 
   },

+ 152 - 0
src/views/qw/user/selectDoctor.vue

@@ -0,0 +1,152 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="医生名称" prop="doctorName">
+        <el-input
+          style="width:220px"
+          v-model="queryParams.doctorName"
+          placeholder="请输入医生名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="医生手机" prop="mobile">
+        <el-input
+        style="width:220px"
+          v-model="queryParams.mobile"
+          placeholder="请输入医生手机"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table  height="500" border v-loading="loading" :data="doctorList" ref="doctorList" >
+      <el-table-column label="医生名称" align="center" prop="doctorName" />
+      <el-table-column label="手机号码" align="center" prop="mobile" />
+      <el-table-column label="操作"   align="center" fixed="right" width="120px" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="medium"
+            type="primary"
+            plain
+            @click="handleBind(scope.row)"
+          >绑定</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+
+  </div>
+</template>
+
+<script>
+import { listDoctorVO } from "@/api/doctor/doctor";
+
+export default {
+  name: "miniCustomer",
+  components: {},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 客户表格数据
+      doctorList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        doctorName: null,
+        mobile: null,
+      },
+      // 表单参数
+      form: {
+      },
+      // 表单校验
+      rules: {
+      },
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+
+    /** 查询客户列表 */
+    getList() {
+      this.loading = true;
+
+      listDoctorVO(this.queryParams).then(response => {
+        this.doctorList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    //绑定选择
+    handleBind(row){
+      this.$emit("bindCompanyUserDoctorId",row.doctorId)
+      this.$refs.doctorList.clearSelection();
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+  }
+};
+</script>
+<style>
+  .el-tag + .el-tag {
+    margin-left: 10px;
+  }
+  .button-new-tag {
+    margin-left: 10px;
+    height: 32px;
+    line-height: 30px;
+    padding-top: 0;
+    padding-bottom: 0;
+  }
+  .input-new-tag {
+    width: 90px;
+    margin-left: 10px;
+    vertical-align: bottom;
+  }
+  .el-dialog__wrapper{
+    z-index: 100000;
+  }
+</style>

+ 159 - 154
src/views/sop/companySopRole/index.vue

@@ -1,86 +1,88 @@
 <template>
   <div class="app-container">
-<!--    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">-->
-<!--      <el-form-item label="销售公司" prop="companyId">-->
-<!--        <el-input-->
-<!--          v-model="queryParams.companyId"-->
-<!--          placeholder="请输入销售公司"-->
-<!--          clearable-->
-<!--          size="small"-->
-<!--          @keyup.enter.native="handleQuery"-->
-<!--        />-->
-<!--      </el-form-item>-->
-<!--      <el-form-item label="权限名称" prop="roleName">-->
-<!--        <el-input-->
-<!--          v-model="queryParams.roleName"-->
-<!--          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-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">-->
+    <!--      <el-form-item label="销售公司" prop="companyId">-->
+    <!--        <el-input-->
+    <!--          v-model="queryParams.companyId"-->
+    <!--          placeholder="请输入销售公司"-->
+    <!--          clearable-->
+    <!--          size="small"-->
+    <!--          @keyup.enter.native="handleQuery"-->
+    <!--        />-->
+    <!--      </el-form-item>-->
+    <!--      <el-form-item label="权限名称" prop="roleName">-->
+    <!--        <el-input-->
+    <!--          v-model="queryParams.roleName"-->
+    <!--          placeholder="请输入权限名称"-->
+    <!--          clearable-->
+    <!--          size="small"-->
+    <!--          @keyup.enter.native="handleQuery"-->
+    <!--        />-->
+    <!--      </el-form-item>-->
+    <!--      <el-form-item>-->
+    <!--        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>-->
+    <!--        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>-->
+    <!--      </el-form-item>-->
+    <!--    </el-form>-->
 
-<!--    <el-row :gutter="10" class="mb8">-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="primary"-->
-<!--          plain-->
-<!--          icon="el-icon-plus"-->
-<!--          size="mini"-->
-<!--          @click="handleAdd"-->
-<!--          v-hasPermi="['sop:companySopRole:add']"-->
-<!--        >新增</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="success"-->
-<!--          plain-->
-<!--          icon="el-icon-edit"-->
-<!--          size="mini"-->
-<!--          :disabled="single"-->
-<!--          @click="handleUpdate"-->
-<!--          v-hasPermi="['sop:companySopRole:edit']"-->
-<!--        >修改</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="danger"-->
-<!--          plain-->
-<!--          icon="el-icon-delete"-->
-<!--          size="mini"-->
-<!--          :disabled="multiple"-->
-<!--          @click="handleDelete"-->
-<!--          v-hasPermi="['sop:companySopRole:remove']"-->
-<!--        >删除</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="warning"-->
-<!--          plain-->
-<!--          icon="el-icon-download"-->
-<!--          size="mini"-->
-<!--          :loading="exportLoading"-->
-<!--          @click="handleExport"-->
-<!--          v-hasPermi="['sop:companySopRole:export']"-->
-<!--        >导出</el-button>-->
-<!--      </el-col>-->
-<!--    </el-row>-->
+    <!--    <el-row :gutter="10" class="mb8">-->
+    <!--      <el-col :span="1.5">-->
+    <!--        <el-button-->
+    <!--          type="primary"-->
+    <!--          plain-->
+    <!--          icon="el-icon-plus"-->
+    <!--          size="mini"-->
+    <!--          @click="handleAdd"-->
+    <!--          v-hasPermi="['sop:companySopRole:add']"-->
+    <!--        >新增</el-button>-->
+    <!--      </el-col>-->
+    <!--      <el-col :span="1.5">-->
+    <!--        <el-button-->
+    <!--          type="success"-->
+    <!--          plain-->
+    <!--          icon="el-icon-edit"-->
+    <!--          size="mini"-->
+    <!--          :disabled="single"-->
+    <!--          @click="handleUpdate"-->
+    <!--          v-hasPermi="['sop:companySopRole:edit']"-->
+    <!--        >修改</el-button>-->
+    <!--      </el-col>-->
+    <!--      <el-col :span="1.5">-->
+    <!--        <el-button-->
+    <!--          type="danger"-->
+    <!--          plain-->
+    <!--          icon="el-icon-delete"-->
+    <!--          size="mini"-->
+    <!--          :disabled="multiple"-->
+    <!--          @click="handleDelete"-->
+    <!--          v-hasPermi="['sop:companySopRole:remove']"-->
+    <!--        >删除</el-button>-->
+    <!--      </el-col>-->
+    <!--      <el-col :span="1.5">-->
+    <!--        <el-button-->
+    <!--          type="warning"-->
+    <!--          plain-->
+    <!--          icon="el-icon-download"-->
+    <!--          size="mini"-->
+    <!--          :loading="exportLoading"-->
+    <!--          @click="handleExport"-->
+    <!--          v-hasPermi="['sop:companySopRole:export']"-->
+    <!--        >导出</el-button>-->
+    <!--      </el-col>-->
+    <!--    </el-row>-->
 
     <el-table border v-loading="loading" :data="companySopRoleList">
       <el-table-column label="销售公司" align="center" prop="companyId">
         <template slot-scope="scope">
-          <el-tag v-for="item in companyList" v-if="item.companyId == scope.row.companyId"> {{scope.row.companyName}}</el-tag>
+          <el-tag v-for="item in companyList" v-if="item.companyId == scope.row.companyId">
+            {{ scope.row.companyName }}
+          </el-tag>
         </template>
       </el-table-column>
       <el-table-column label="权限" align="center">
         <template slot-scope="scope">
           <div style="display: flex;flex-flow: wrap;justify-content: flex-start;">
-            <el-tag style="width: 30%;margin: 0 5px" v-for="item in scope.row.rules">{{roleMap[item]}}</el-tag>
+            <el-tag style="width: 30%;margin: 0 5px" v-for="item in scope.row.rules">{{ roleMap[item] }}</el-tag>
           </div>
         </template>
       </el-table-column>
@@ -92,7 +94,8 @@
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['sop:companySopRole:edit']"
-          >修改</el-button>
+          >修改
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -109,7 +112,7 @@
     <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="销售公司" prop="companyId">
-          <el-select filterable  v-model="form.companyId" placeholder="请选择公司名" size="small">
+          <el-select filterable v-model="form.companyId" placeholder="请选择公司名" size="small">
             <el-option
               v-for="item in companyList"
               :key="item.companyId"
@@ -121,7 +124,9 @@
         <el-form-item label="权限" prop="rules">
           <div style="margin: 15px 0;"></div>
           <el-checkbox-group v-model="form.rules" style="display: flex;flex-flow: wrap;justify-content: flex-start;">
-            <el-checkbox style="width: 28%" v-for="item in roleOptions" :label="item.dictValue" :key="item.dictValue">{{item.dictLabel}}</el-checkbox>
+            <el-checkbox style="width: 28%" v-for="item in roleOptions" :label="item.dictValue" :key="item.dictValue">
+              {{ item.dictLabel }}
+            </el-checkbox>
           </el-checkbox-group>
         </el-form-item>
       </el-form>
@@ -134,11 +139,18 @@
 </template>
 
 <script>
-import { listCompanySopRole, getCompanySopRole, delCompanySopRole, addCompanySopRole, updateCompanySopRole, exportCompanySopRole } from "@/api/sop/companySopRole";
-import { getCompanyList } from "@/api/company/company";
+import {
+  listCompanySopRole,
+  getCompanySopRole,
+  delCompanySopRole,
+  addCompanySopRole,
+  updateCompanySopRole,
+  exportCompanySopRole
+} from '@/api/sop/companySopRole'
+import { getCompanyList } from '@/api/company/company'
 
 export default {
-  name: "CompanySopRole",
+  name: 'CompanySopRole',
   data() {
     return {
       // 遮罩层
@@ -160,7 +172,7 @@ export default {
       roleOptions: [],
       roleMap: [],
       // 弹出层标题
-      title: "",
+      title: '',
       // 是否显示弹出层
       open: false,
       companyList: [],
@@ -170,43 +182,42 @@ export default {
         pageSize: 10,
         companyId: null,
         roleName: null,
-        roleValue: null,
+        roleValue: null
       },
       // 表单参数
       form: {},
       // 表单校验
-      rules: {
-      }
-    };
+      rules: {}
+    }
   },
   created() {
-    this.getList();
-    this.getDicts("company_sop_role").then(response => {
-      this.roleOptions = response.data;
+    this.getList()
+    this.getDicts('company_sop_role').then(response => {
+      this.roleOptions = response.data
       this.roleMap = response.data.reduce((obj, item) => {
-        obj[item.dictValue] = item.dictLabel;
-        return obj;
-      }, {});
-    });
+        obj[item.dictValue] = item.dictLabel
+        return obj
+      }, {})
+    })
     getCompanyList().then(response => {
-      this.companyList = response.data;
-    });
+      this.companyList = response.data
+    })
   },
   methods: {
     /** 查询公司SOP权限列表 */
     getList() {
-      this.loading = true;
+      this.loading = true
       listCompanySopRole(this.queryParams).then(response => {
         console.info(response.rows)
-        this.companySopRoleList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
+        this.companySopRoleList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
     },
     // 取消按钮
     cancel() {
-      this.open = false;
-      this.reset();
+      this.open = false
+      this.reset()
     },
     // 表单重置
     reset() {
@@ -221,90 +232,84 @@ export default {
         updateTime: null,
         rules: this.roleOptions.map(e => e.dictValue),
         remark: null
-      };
-      this.resetForm("form");
+      }
+      this.resetForm('form')
     },
     /** 搜索按钮操作 */
     handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
+      this.queryParams.pageNum = 1
+      this.getList()
     },
     /** 重置按钮操作 */
     resetQuery() {
-      this.resetForm("queryForm");
-      this.handleQuery();
+      this.resetForm('queryForm')
+      this.handleQuery()
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.id)
-      this.single = selection.length!==1
+      this.single = selection.length !== 1
       this.multiple = !selection.length
     },
     /** 新增按钮操作 */
     handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加公司SOP权限";
+      this.reset()
+      this.open = true
+      this.title = '添加公司SOP权限'
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-      this.reset();
-      if(row.rules && row.rules.length > 0){
-        this.form.rules = row.rules;
+      this.reset()
+      if (row.rules && row.rules.length > 0) {
+        this.form.rules = row.rules
       }
-      this.form.companyId = row.companyId;
-      this.open = true;
-      this.title = "修改公司SOP权限";
+      this.form.companyId = row.companyId
+      this.open = true
+      this.title = '修改公司SOP权限'
     },
     /** 提交按钮 */
     submitForm() {
-      this.$refs["form"].validate(valid => {
+      this.$refs['form'].validate(valid => {
         if (valid) {
-          if (this.form.id != null) {
-            updateCompanySopRole(this.form).then(response => {
-              this.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addCompanySopRole(this.form).then(response => {
-              this.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
+          updateCompanySopRole(this.form).then(response => {
+            this.msgSuccess('修改成功')
+            this.open = false
+            this.getList()
+          })
         }
-      });
+      })
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      const ids = row.id || this.ids;
-      this.$confirm('是否确认删除公司SOP权限编号为"' + ids + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delCompanySopRole(ids);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      const ids = row.id || this.ids
+      this.$confirm('是否确认删除公司SOP权限编号为"' + ids + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delCompanySopRole(ids)
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('删除成功')
+      }).catch(() => {
+      })
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有公司SOP权限数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportCompanySopRole(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
-    },
+      const queryParams = this.queryParams
+      this.$confirm('是否确认导出所有公司SOP权限数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.exportLoading = true
+        return exportCompanySopRole(queryParams)
+      }).then(response => {
+        this.download(response.msg)
+        this.exportLoading = false
+      }).catch(() => {
+      })
+    }
   }
-};
+}
 </script>

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

@@ -146,6 +146,14 @@
           <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
           <el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
           <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
+          <el-table-column label="账户角色" align="center" key="roleName" v-if="columns[7].visible" :show-overflow-tooltip="true">
+            <template slot-scope="scope">
+              <span v-if="scope.row.roleName && scope.row.roleName.length > 0">
+                {{ Array.isArray(scope.row.roleName) ? scope.row.roleName.join('、') : scope.row.roleName }}
+              </span>
+              <span v-else>-</span>
+            </template>
+          </el-table-column>
           <el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
             <template slot-scope="scope">
               <el-switch
@@ -434,7 +442,8 @@ export default {
         { key: 3, label: `部门`, visible: true },
         { key: 4, label: `手机号码`, visible: true },
         { key: 5, label: `状态`, visible: true },
-        { key: 6, label: `创建时间`, visible: true }
+        { key: 6, label: `创建时间`, visible: true },
+        { key: 7, label: `账户角色`, visible: true }
       ],
       // 表单校验
       rules: {