Bläddra i källkod

Merge remote-tracking branch 'origin/master'

yjwang 3 veckor sedan
förälder
incheckning
4885fb4407
38 ändrade filer med 5433 tillägg och 74 borttagningar
  1. 2 2
      .env.prod-bjyjb
  2. 2 2
      .env.prod-kyt
  3. 22 0
      .env.prod-syysy
  4. 22 0
      .env.prod-zkzh
  5. 1 0
      package.json
  6. 62 0
      src/api/crm/assist.js
  7. 7 0
      src/api/crm/customer.js
  8. 9 0
      src/api/crm/customerLevel.js
  9. 7 0
      src/api/qw/user.js
  10. 59 0
      src/api/store/coupon.js
  11. 143 0
      src/api/store/doctor.js
  12. 72 0
      src/api/store/storeOrderOffline.js
  13. 66 0
      src/api/store/userCoupon copy.js
  14. 9 0
      src/api/user/fsUser.js
  15. BIN
      src/assets/logo/kyt.jpg
  16. BIN
      src/assets/logo/syysy.png
  17. BIN
      src/assets/logo/zkzh_logo.png
  18. 1029 0
      src/components/course/userCoursePeriod.vue
  19. 1 0
      src/views/company/companyRecharge/index.vue
  20. 662 0
      src/views/crm/components/assistUser.vue
  21. 817 0
      src/views/crm/customer/assist.vue
  22. 36 1
      src/views/member/mylist.vue
  23. 5 1
      src/views/qw/externalContactTransfer/index.vue
  24. 6 2
      src/views/qw/externalContactUnassigned/index.vue
  25. 2 2
      src/views/qw/friendWelcome/indexNew.vue
  26. 4 4
      src/views/qw/sop/addSop.vue
  27. 1 0
      src/views/qw/sopTemp/addSopTemp.vue
  28. 1 0
      src/views/qw/sopTemp/updateSopTemp.vue
  29. 1 0
      src/views/qw/sopTemp/updateSopTemp2.vue
  30. 9 0
      src/views/qw/user/cuDeptIdIndex.vue
  31. 21 0
      src/views/qw/user/index.vue
  32. 735 0
      src/views/store/components/addOrder.vue
  33. 313 0
      src/views/store/components/addOrderOffline.vue
  34. 152 0
      src/views/store/components/couponDetails.vue
  35. 117 28
      src/views/store/components/storeOrderDetails.vue
  36. 568 0
      src/views/store/coupon/index.vue
  37. 38 32
      src/views/store/package/index.vue
  38. 432 0
      src/views/store/userCoupon/index.vue

+ 2 - 2
.env.prod-bjyjb

@@ -3,9 +3,9 @@ VUE_APP_TITLE =医健宝SCRM销售端
 # 公司名称
 VUE_APP_COMPANY_NAME = 医健宝智慧(北京)医药科技有限公司
 # ICP备案号
-VUE_APP_ICP_RECORD =
+VUE_APP_ICP_RECORD =京ICP备2025133930号-2
 # ICP网站访问地址
-VUE_APP_ICP_URL =
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
 # 网站LOG
 VUE_APP_LOG_URL =@/assets/logo/bjyjb.jpg
 

+ 2 - 2
.env.prod-kyt

@@ -1,5 +1,5 @@
 # 页面标题
-VUE_APP_TITLE =互联网医院管理系统
+VUE_APP_TITLE =宽益堂SCRM销售端
 # 公司名称
 VUE_APP_COMPANY_NAME =云联融智互联网医院有限公司
 # ICP备案号
@@ -7,7 +7,7 @@ VUE_APP_ICP_RECORD =渝ICP备2024031984号-1
 # ICP网站访问地址
 VUE_APP_ICP_URL =https://beian.miit.gov.cn
 # 网站LOG
-VUE_APP_LOG_URL =@/assets/logo/ylrz.png
+VUE_APP_LOG_URL =@/assets/logo/kyt.jpg
 
 # 生产环境配置
 ENV = 'production'

+ 22 - 0
.env.prod-syysy

@@ -0,0 +1,22 @@
+# 页面标题
+VUE_APP_TITLE =互联网医院管理系统
+# 公司名称
+VUE_APP_COMPANY_NAME =沈阳铁西益寿缘中医院有限责任公司
+# ICP备案号
+VUE_APP_ICP_RECORD = 辽ICP备2024035076号-17
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/syysy.png
+
+# 生产环境配置
+ENV = 'production'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 22 - 0
.env.prod-zkzh

@@ -0,0 +1,22 @@
+# 页面标题
+VUE_APP_TITLE = 中康SCRM管理系统
+# 公司名称
+VUE_APP_COMPANY_NAME = 陕西中康智慧药房有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD = 陕ICP备2024048690号-2
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/zkzh_logo.png
+
+# 生产环境配置
+ENV = 'production'
+
+#FS管理系统/生产环境
+VUE_APP_BASE_API = '/prod-api'
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 2

+ 1 - 0
package.json

@@ -34,6 +34,7 @@
     "build:prod-bjyjb": "vue-cli-service build --mode prod-bjyjb",
     "build:prod-kyt": "vue-cli-service build --mode prod-kyt",
     "build:prod-fby": "vue-cli-service build --mode prod-fby",
+    "build:prod-syysy": "vue-cli-service build --mode prod-syysy",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src",
     "test:unit": "jest --clearCache && vue-cli-service test:unit",

+ 62 - 0
src/api/crm/assist.js

@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 查询客户员工协作列表
+export function listAssist(query) {
+  return request({
+    url: '/crm/assist/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询客户员工协作详细
+export function getAssist(id) {
+  return request({
+    url: '/crm/assist/' + id,
+    method: 'get'
+  })
+}
+
+// 新增客户员工协作
+export function addAssist(data) {
+  return request({
+    url: '/crm/assist',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改客户员工协作
+export function updateAssist(data) {
+  return request({
+    url: '/crm/assist',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除客户员工协作
+export function delAssist(id) {
+  return request({
+    url: '/crm/assist/' + id,
+    method: 'delete'
+  })
+}
+
+// 删除客户员工协作
+export function remove(data) {
+  return request({
+    url: '/crm/assist/remove',
+    method: 'post',
+    data: data
+  })
+}
+
+// 导出客户员工协作
+export function exportAssist(query) {
+  return request({
+    url: '/crm/assist/export',
+    method: 'get',
+    params: query
+  })
+}

+ 7 - 0
src/api/crm/customer.js

@@ -189,3 +189,10 @@ export function updateCustomerSource(data) {
     data: data
   })
 }
+export function getMyAssistList(query) {
+  return request({
+    url: '/crm/customer/getMyAssistList',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
src/api/crm/customerLevel.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export const customerLevelOptions = (query) => {
+  return request({
+    url: "/crm/customerLevel/getCustomerLevelOption",
+    method: "get",
+    params: query,
+  });
+};

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

@@ -175,6 +175,13 @@ export function getQwIpad(data) {
     data: data
   })
 }
+export function changeVideoStatus(id) {
+  return request({
+    url: '/qw/user/changeVideoStatus',
+    method: 'get',
+    params: {id}
+  })
+}
 export function delQwIpad(data) {
   return request({
     url: '/qw/user/delQwIpad',

+ 59 - 0
src/api/store/coupon.js

@@ -0,0 +1,59 @@
+import request from '@/utils/request'
+
+// 查询优惠券列表
+export function listCoupon(query) {
+  return request({
+    url: '/store/coupon/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询优惠券详细
+export function getCoupon(couponId) {
+  return request({
+    url: '/store/coupon/' + couponId,
+    method: 'get'
+  })
+}
+
+export function allList() {
+  return request({
+    url: '/store/coupon/allList',
+    method: 'get'
+  })
+}
+// 新增优惠券
+export function addCoupon(data) {
+  return request({
+    url: '/store/coupon',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改优惠券
+export function updateCoupon(data) {
+  return request({
+    url: '/store/coupon',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除优惠券
+export function delCoupon(couponId) {
+  return request({
+    url: '/store/coupon/' + couponId,
+    method: 'delete'
+  })
+}
+
+// 导出优惠券
+export function exportCoupon(query) {
+  return request({
+    url: '/store/coupon/export',
+    method: 'get',
+    params: query
+  })
+}

+ 143 - 0
src/api/store/doctor.js

@@ -0,0 +1,143 @@
+import request from '@/utils/request'
+
+// 查询医生管理列表
+export function listDoctor(query) {
+  return request({
+    url: '/store/doctor/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getUserList(name) {
+  return request({
+    url: '/store/doctor/user/list',
+    method: 'get',
+    params: name
+  })
+}
+export function getFollowDoctorList(query) {
+  return request({
+    url: '/store/doctor/followDoctorList',
+    method: 'get',
+    params: query
+  })
+}
+export function getAllFollowDoctorList(query) {
+  return request({
+    url: '/store/doctor/allFollowDoctorList',
+    method: 'get',
+    params: query
+  })
+}
+export function docList() {
+  return request({
+    url: '/store/doctor/doc/list',
+    method: 'get',
+
+  })
+}
+// 查询医生名称列表
+export function listdocuser(query) {
+  return request({
+    url: '/store/doctor/userdoc/list',
+    method: 'get',
+    params: query
+  })
+}
+export function getDoctorPrice(doctorId) {
+  return request({
+    url: '/store/price/getDoctorPrice/' + doctorId,
+    method: 'get'
+  })
+}
+
+
+export function editPassWord(data) {
+  return request({
+    url: '/store/doctor/editPassWord',
+    method: 'put',
+    data: data
+  })
+}
+
+export function editDoctorPrice(data) {
+  return request({
+    url: '/store/price/editDoctorPrice',
+    method: 'post',
+    data: data
+  })
+}
+// 查询医生管理详细
+export function getDoctor(doctorId) {
+  return request({
+    url: '/store/doctor/' + doctorId,
+    method: 'get'
+  })
+}
+// 新增医生管理
+export function addDoctor(data) {
+  return request({
+    url: '/store/doctor',
+    method: 'post',
+    data: data
+  })
+}
+export function editFollow(data) {
+  return request({
+    url: '/store/doctor/editFollow',
+    method: 'put',
+    data: data
+  })
+}
+// 修改医生管理
+export function updateDoctor(data) {
+  return request({
+    url: '/store/doctor',
+    method: 'put',
+    data: data
+  })
+}
+
+// 修改医生管理
+export function editPrice(data) {
+  return request({
+    url: '/store/doctor/editDoctorPrice',
+    method: 'put',
+    data: data
+  })
+}
+
+// 修改医生管理
+export function updateAuditDoctor(data) {
+  return request({
+    url: '/store/doctor/editDoctor',
+    method: 'put',
+    data: data
+  })
+}
+
+
+// 删除医生管理
+export function delDoctor(doctorId) {
+  return request({
+    url: '/store/doctor/' + doctorId,
+    method: 'delete'
+  })
+}
+
+// 导出医生管理
+export function getWxaCodeUnLimit() {
+  return request({
+    url: '/store/doctor/getWxaCodeUnLimit',
+    method: 'get',
+  })
+}
+// 导出医生管理
+export function exportDoctor(query) {
+  return request({
+    url: '/store/doctor/export',
+    method: 'get',
+    params: query
+  })
+}

+ 72 - 0
src/api/store/storeOrderOffline.js

@@ -0,0 +1,72 @@
+import request from '@/utils/request'
+
+// 查询线下订单列表
+export function listStoreOrderOffline(query) {
+  return request({
+    url: '/store/storeOrderOffline/list',
+    method: 'get',
+    params: query
+  })
+}
+
+
+// 查询线下订单列表
+export function myOrderList(query) {
+  return request({
+    url: '/store/storeOrderOffline/myList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询线下订单详细
+export function getStoreOrderOffline(orderId) {
+  return request({
+    url: '/store/storeOrderOffline/' + orderId,
+    method: 'get'
+  })
+}
+
+// 新增线下订单
+export function createOrder(data) {
+  return request({
+    url: '/store/storeOrderOffline/createOrder',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改线下订单
+export function updateStoreOrderOffline(data) {
+  return request({
+    url: '/store/storeOrderOffline',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除线下订单
+export function delStoreOrderOffline(orderId) {
+  return request({
+    url: '/store/storeOrderOffline/' + orderId,
+    method: 'delete'
+  })
+}
+
+// 导出线下订单
+export function exportStoreOrderOffline(query) {
+  return request({
+    url: '/store/storeOrderOffline/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 上传凭证
+export function uploadCredentials(data) {
+  return request({
+    url: '/store/storeOrderOffline/uploadCredentials',
+    method: 'post',
+    data: data
+  })
+}

+ 66 - 0
src/api/store/userCoupon copy.js

@@ -0,0 +1,66 @@
+import request from '@/utils/request'
+
+// 查询会员优惠券列表
+export function listUserCoupon(query) {
+  return request({
+    url: '/store/userCoupon/list',
+    method: 'get',
+    params: query
+  })
+}
+export function getListUserCoupon(query) {
+  return request({
+    url: '/store/userCoupon/getList',
+    method: 'get',
+    params: query
+  })
+}
+// 查询会员优惠券详细
+export function getUserCoupon(id) {
+  return request({
+    url: '/store/userCoupon/' + id,
+    method: 'get'
+  })
+}
+
+// 新增会员优惠券
+export function addUserCoupon(data) {
+  return request({
+    url: '/store/userCoupon',
+    method: 'post',
+    data: data
+  })
+}
+export function sendCoupon(data) {
+  return request({
+    url: '/store/userCoupon/sendCoupon',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改会员优惠券
+export function updateUserCoupon(data) {
+  return request({
+    url: '/store/userCoupon',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除会员优惠券
+export function delUserCoupon(id) {
+  return request({
+    url: '/store/userCoupon/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出会员优惠券
+export function exportUserCoupon(query) {
+  return request({
+    url: '/store/userCoupon/export',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
src/api/user/fsUser.js

@@ -94,3 +94,12 @@ export function getQwRepeatData(data){
     data: data
   })
 }
+
+// 批量发送IM
+export function batchSendCourse(data) {
+  return request({
+    url: '/user/fsUser/batchSendCourse',
+    method: 'post',
+    data: data
+  })
+}

BIN
src/assets/logo/kyt.jpg


BIN
src/assets/logo/syysy.png


BIN
src/assets/logo/zkzh_logo.png


+ 1029 - 0
src/components/course/userCoursePeriod.vue

@@ -0,0 +1,1029 @@
+<template>
+    <div class="app-container">
+        <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+            <el-form-item label="营期名称" prop="periodName">
+                <el-input v-model="queryParams.periodName" placeholder="请输入营期名称" clearable size="small"
+                    @keyup.enter.native="handleQuery" />
+            </el-form-item>
+            <el-form-item label="公司" prop="companyIdList">
+                <el-select v-model="queryParams.companyIdList" placeholder="请选择公司" clearable size="small" multiple>
+                    <el-option v-for="item in companyOptions" :key="item.companyId" :label="item.companyName"
+                        :value="item.companyId" />
+                </el-select>
+            </el-form-item>
+            <el-form-item label="开营日期开始" prop="periodStartingTime" label-width="120px">
+                <el-date-picker clearable size="small" style="width: 200px" v-model="queryParams.periodStartingTime"
+                    type="date" value-format="yyyy-MM-dd" placeholder="请选择开营日期开始时间">
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item label="开营日期结束" prop="periodEndTime" label-width="120px">
+                <el-date-picker clearable size="small" style="width: 300px" v-model="queryParams.periodEndTime"
+                    type="date" value-format="yyyy-MM-dd" placeholder="请选择开营日期结束时间">
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item>
+                <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery"
+                    v-hasPermi="['course:period:list']">搜索</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="periodList" @selection-change="handleSelectionChange" border>
+            <el-table-column label="营期名称" align="center" prop="periodName" />
+            <el-table-column label="公司名称" align="center" prop="companyName" />
+            <el-table-column label="营期状态" align="center" prop="periodStatus" width="100"
+                :formatter="periodStatusFormatter" />
+            <el-table-column label="营期线" align="center" prop="periodLine" width="180" />
+            <el-table-column label="开营开始时间" align="center" prop="periodStartingTime" width="180" />
+            <el-table-column label="开营结束时间" align="center" prop="periodEndTime" width="180" />
+            <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
+            <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-setting"
+                        @click="handlePeriodSettings(scope.row)">选择视频</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+
+        <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
+            :limit.sync="queryParams.pageSize" @pagination="getList" />
+
+
+
+
+
+
+
+
+
+
+
+        <!-- 营期相关设置抽屉 -->
+        <el-drawer title="营期相关设置" :visible.sync="periodSettingsVisible" direction="rtl" size="74%"
+            :destroy-on-close="true" append-to-body custom-class="period-settings-drawer">
+            <div class="drawer-content" style="margin-left: 25px">
+                <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+                    <el-tab-pane label="课程管理" name="course">
+                        <el-table ref="courseTable" v-loading="course.loading" :data="course.list"
+                            @selection-change="handleSelectionCourseChange" border>
+                            <el-table-column label="课程" align="center" prop="courseName" width="180" />
+                            <el-table-column label="小节" align="center" prop="videoName" />
+                            <el-table-column label="开课状态" align="center" prop="status" width="100"
+                                :formatter="courseStatusFormatter" />
+                            <el-table-column label="营期时间" align="center" prop="dayDate" width="100" />
+                            <el-table-column label="开始时间" align="center" prop="startDateTime" width="100">
+                                <!--              <template slot-scope="scope">-->
+                                <!--                <el-tag>{{scope.row.startDateTime}}</el-tag>-->
+                                <!--              </template>-->
+                            </el-table-column>
+                            <el-table-column label="结束时间" align="center" prop="endDateTime" width="100">
+                                <!--              <template slot-scope="scope">-->
+                                <!--                <el-tag type="success">{{parseTime(scope.row.endDateTime, '{h}:{i}:{s}')}}</el-tag>-->
+                                <!--              </template>-->
+                            </el-table-column>
+                            <el-table-column label="领取红包时间" align="center" prop="lastJoinTime" width="160">
+                                <template slot-scope="scope">
+                                    <el-tag type="danger">{{ scope.row.lastJoinTime }}</el-tag>
+                                </template>
+                            </el-table-column>
+                            <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+                                <template slot-scope="scope">
+                                    <el-button size="mini" type="text" @click="handleSend(scope.row)"
+                                        v-hasPermi="['course:period:courseMove']">发送</el-button>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                        <pagination v-show="course.total > 0" :total="course.total"
+                            :page.sync="course.queryParams.pageNum" :limit.sync="course.queryParams.pageSize"
+                            @pagination="getCourseList" style="height: 40px" />
+                    </el-tab-pane>
+
+                </el-tabs>
+            </div>
+        </el-drawer>
+
+        <el-dialog title="IM发送" :visible.sync="imOpen" width="800px" append-to-body>
+            <el-form ref="imSendForm" :model="imSendForm" :rules="imRules" label-width="220px">
+                <el-form-item label="标题" prop="title">
+                    <el-input v-model="imSendForm.title" placeholder="请输入标题" />
+                </el-form-item>
+                <el-form-item label="发送消息时间" prop="sendTime">
+                    <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="imSendForm.sendTime" type="datetime"
+                        placeholder="选择日期时间">
+                    </el-date-picker>
+                </el-form-item>
+                <el-form-item label="有效时长(分钟)" prop="effectiveDuration">
+                    <el-input-number v-model="imSendForm.effectiveDuration" :min="0"
+                        label="链接有效时长(分钟)"></el-input-number>
+                </el-form-item>
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-button type="primary" @click="imSubmit">确 定</el-button>
+                <el-button @click="imCancel">取 消</el-button>
+            </div>
+        </el-dialog>
+
+    </div>
+</template>
+
+
+<script>
+import { addPeriod, delPeriod, exportPeriod, getPeriod, pagePeriod, updatePeriod, getDays, addCourse, delPeriodDay, updateCourseTime, updateCourseDate, updateListCourseData, periodCourseMove, closePeriod } from "@/api/course/userCoursePeriod";
+import { getCompanyList } from "@/api/company/company";
+import { batchSendCourse } from "@/api/user/fsUser";
+import { listCamp, addCamp, editCamp, delCamp, copyCamp } from "@/api/course/userCourseCamp";
+import { courseList, videoList } from '@/api/course/courseRedPacketLog'
+import Da from "element-ui/src/locale/lang/da";
+import { getConfigByKey } from '@/api/system/config'
+export default {
+    props: {
+        userIds: {
+            type: Array,
+            default: () => []
+        },
+        companyId: {
+            type: Number,
+            default: 0
+        },
+        companyUserId: {
+            type: Number,
+            default: 0
+        }
+    },
+    name: "Period",
+    components: {
+    },
+    data() {
+        return {
+            imSendForm: {
+
+            },
+            imOpen: false,
+            // 遮罩层
+            loading: true,
+            updateDateOpen: false,
+            // 左侧遮罩层
+            leftLoading: true,
+            // 选中数组
+            ids: [],
+            // 非单个禁用
+            single: true,
+            // 非多个禁用
+            multiple: true,
+            // 显示搜索条件
+            showSearch: true,
+            // 总条数
+            total: 0,
+            // 左侧总条数
+            leftTotal: 0,
+            // 会员营期表格数据
+            periodList: [],
+            // 左侧列表数据
+            leftList: [],
+            videoList: [],
+            // 弹出层标题
+            title: "",
+            isDisabledDateRange: false, //是否禁用开营日期
+            // 是否显示弹出层
+            open: false,
+            // 查询参数
+            queryParams: {
+                pageNum: 1,
+                pageSize: 10,
+                periodName: null,
+                periodStartingTime: null,
+                periodEndTime: null,
+                companyIdList: []
+            },
+            // 左侧查询参数
+            leftQueryParams: {
+                pageNum: 1,
+                pageSize: 10,
+                hasNextPage: false,
+                scs: 'order_number(desc),training_camp_id(desc)',
+                trainingCampName: null
+            },
+            // 表单参数
+            form: {},
+            // 课程相关数据
+            course: {
+                open: false,
+                row: {},
+                list: [],
+                queryParams: {
+                    pageNum: 1,
+                    pageSize: 10,
+                },
+                loading: true,
+                total: 0,
+                addOpen: false,
+                form: {},
+            },
+            //修改营期时间参数
+            updatePeriodDate: {
+                open: false,
+                loading: true,
+                ids: [],
+                form: {},
+            },
+            joinTimeSwitch: true,
+            updateCourse: {
+                open: false,
+                loading: true,
+                ids: [],
+                form: {
+                    timeRange: null,
+                    joinTime: null
+                },
+            },
+            imRules: {
+                title: [
+                    { required: true, message: "发送标题不能为空", trigger: "blur" }
+                ],
+            },
+            // 表单校验
+            rules: {
+                periodName: [
+                    { required: true, message: '营期名称不能为空', trigger: 'blur' }
+                ],
+                companyId: [
+                    { required: true, message: '公司不能为空', trigger: 'change' }
+                ],
+                courseStyle: [
+                    { required: true, message: '课程风格不能为空', trigger: 'change' }
+                ],
+                // redPacketGrantMethod: [
+                //   { required: true, message: '红包发放方式不能为空', trigger: 'change' }
+                // ],
+                periodType: [
+                    { required: true, message: '营期类型不能为空', trigger: 'change' }
+                ],
+                maxViewNum: [
+                    { required: true, message: '销售可查看天数不能为空', trigger: 'blur' }
+                ],
+                periodStartingTime: [
+                    { required: true, message: '开营日期不能为空', trigger: 'change' }
+                ]
+            },
+            // 公司选项
+            companyOptions: [],
+            // 训练营列表
+            campList: [],
+            // 激活的训练营索引
+            activeCampIndex: null,
+            // 训练营对话框是否显示
+            campDialogVisible: false,
+            courseList: false,
+            // 训练营表单
+            campForm: {
+                trainingCampId: null,
+                trainingCampName: ''
+            },
+            // 训练营表单校验
+            campRules: {
+                trainingCampName: [
+                    { required: true, message: '训练营名称不能为空', trigger: 'blur' },
+                    { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
+                ]
+            },
+            // 添加课程表单校验
+            courseAddRules: {
+                courseId: [
+                    { required: true, message: '请选择课程', trigger: 'change' }
+                ],
+                videoIds: [
+                    { required: true, message: '请选择小节', trigger: 'change' },
+                    { type: 'array', min: 1, message: '请至少选择一个小节', trigger: 'change' }
+                ]
+            },
+            // 修改看课时间表单校验
+            courseUpdateRules: {
+                timeRange: [
+                    {
+                        required: true,
+                        validator: (rule, value, callback) => {
+                            if (!value || !Array.isArray(value) || value.length !== 2) {
+                                callback(new Error('请选择完整的看课时间范围'));
+                            } else {
+                                // 检查时间格式是否正确(yyyy-MM-dd HH:mm:ss)
+                                const timeRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
+                                if (!timeRegex.test(value[0]) || !timeRegex.test(value[1])) {
+                                    callback(new Error('时间格式不正确'));
+                                } else if (value[0] >= value[1]) {
+                                    callback(new Error('结束时间必须大于开始时间'));
+                                } else {
+                                    callback();
+                                }
+                            }
+                        },
+                        trigger: 'change'
+                    }
+                ],
+                joinTime: [
+                    {
+                        required: true,
+                        validator: (rule, value, callback) => {
+                            if (!value) {
+                                callback(new Error('请选择领取红包时间'));
+                            } else {
+                                // 检查时间格式是否正确(yyyy-MM-dd HH:mm:ss)
+                                const timeRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
+                                if (!timeRegex.test(value)) {
+                                    callback(new Error('时间格式不正确'));
+                                } else {
+                                    // 检查领取红包时间是否在看课时间范围内
+                                    const timeRange = this.updateCourse.form.timeRange;
+                                    if (timeRange && Array.isArray(timeRange) && timeRange.length === 2) {
+                                        if (value < timeRange[0] || value > timeRange[1]) {
+                                            callback(new Error('领取红包时间必须在看课时间范围内'));
+                                        } else {
+                                            callback();
+                                        }
+                                    } else {
+                                        callback();
+                                    }
+                                }
+                            }
+                        },
+                        trigger: 'change'
+                    }
+                ]
+            },
+            // 滚动节流标志
+            scrollThrottle: false,
+            // 加载更多状态
+            loadingMore: false,
+            // 设置红包对话框
+            redPacketVisible: false,
+            periodCompanyList: [],
+            currentRedPacketData: {
+                periodId: '',
+                videoId: ''
+            },
+            // 营期相关设置抽屉
+            periodSettingsVisible: false,
+            activeTab: 'course',
+            periodSettingsData: {},
+            companyList: [],
+            courseDialogVisible: false,
+            redPacketList: [],
+            currentCompany: null,
+            // 选中的营期数据
+            selectedPeriods: [],
+            // 批量设置红包按钮是否禁用
+            batchSetRedPacketDisabled: true,
+
+        };
+    },
+    created() {
+        courseList().then(response => {
+            this.courseList = response.list;
+        });
+        // this.getList();
+        this.getLeftList();
+        this.getCompanyList();
+
+    },
+    methods: {
+        imSubmit() {
+            console.log("imSendForm:", this.imSendForm)
+            this.$refs["imSendForm"].validate(valid => {
+                if (valid) {
+                    batchSendCourse(this.imSendForm).then(res => {
+                        if (res.errCode == 0) {
+                            this.imCancel();
+                            this.$message.success('发送成功')
+                        }
+                    })
+                }
+
+            });
+        },
+        handleSend(row) {
+            this.imOpen = true;
+            this.imSendForm = {
+                userIds: this.userIds,
+                companyUserId: this.companyUserId,
+                companyId: this.companyId,
+                id: row.id,
+                periodId: row.periodId,
+                courseId: row.courseId,
+                videoId: row.videoId
+            }
+        },
+        imCancel() {
+            this.imOpen = false;
+            this.imRest();
+        },
+        imRest() {
+            this.imSendForm = {
+                userIds: [],
+                companyUserId: null,
+                companyId: null,
+                periodId: null,
+                courseId: null,
+                videoId: null,
+                tagIds: [],
+                sendTime: null,
+                title: null,
+                effectiveDuration: null,
+                id: null,
+            };
+            this.resetForm("imSendForm")
+        },
+        /** 删除按钮操作 */
+        async handleDeleteCourse(row) {
+            const periodDayIds = row.id || this.updateCourse.ids;
+            try {
+                await this.$confirm('是否确认删除该课程?', "提示", {
+                    confirmButtonText: "确定",
+                    cancelButtonText: "取消",
+                    type: "warning"
+                });
+
+                const res = await delPeriodDay(periodDayIds);
+
+                if (res && res.code === 200) {
+                    this.getCourseList();// 刷新列表
+                    this.$message.success('删除成功');
+                } else {
+                    this.$message.error(res.msg);
+                }
+            } catch (error) {
+
+            }
+        },
+        /** 查询会员营期列表 */
+        getList() {
+            this.loading = true;
+            const params = { ...this.queryParams };
+            params.trainingCampId = null,
+                pagePeriod(params).then(response => {
+                    this.periodList = response.rows;
+                    this.total = response.total;
+                    this.loading = false;
+                });
+        },
+        /** 查询左侧列表 */
+        getLeftList() {
+            this.leftLoading = true;
+            // 重置页码和加载更多状态
+            this.leftQueryParams.pageNum = 1;
+            this.loadingMore = false;
+
+            // 训练营数据
+            listCamp(this.leftQueryParams).then(response => {
+                if (response && response.code === 200) {
+                    this.campList = response.data.list || [];
+                    this.leftQueryParams.hasNextPage = response.data.hasNextPage;
+                    this.activeCampIndex = this.campList.length > 0 ? 0 : null;
+                    this.selectCamp(this.activeCampIndex);
+                    // 如果当前显示的列表高度不足以触发滚动,但还有更多数据,自动加载下一页
+                    this.$nextTick(() => {
+                        const scrollEl = this.$refs.campList;
+                        if (scrollEl && this.leftQueryParams.hasNextPage && scrollEl.scrollHeight <= scrollEl.clientHeight) {
+                            this.loadMoreCamps();
+                        }
+                    });
+                } else {
+                    this.$message.error(response.msg || '获取训练营列表失败');
+                    this.campList = [];
+                    this.leftQueryParams.hasNextPage = false;
+                }
+                this.leftLoading = false;
+            }).catch(error => {
+                console.error('获取训练营列表失败:', error);
+                this.$message.error('获取训练营列表失败');
+                this.campList = [];
+                this.leftQueryParams.hasNextPage = false;
+                this.leftLoading = false;
+            });
+        },
+        /** 搜索按钮操作 */
+        handleQuery() {
+            this.queryParams.pageNum = 1;
+            this.getList();
+        },
+        /** 左侧搜索按钮操作 */
+        handleLeftQuery() {
+            // 重置页码和列表
+            this.leftQueryParams.pageNum = 1;
+            this.campList = [];
+            this.getLeftList();
+        },
+        /** 重置按钮操作 */
+        resetQuery() {
+            this.resetForm("queryForm");
+            this.queryParams.companyIdList = [];
+            this.handleQuery();
+        },
+        /** 多选框选中数据 */
+        handleSelectionChange(selection) {
+            this.ids = selection.map(item => item.periodId)
+            this.single = selection.length !== 1
+            this.multiple = !selection.length
+            // 更新批量设置红包相关数据
+            this.selectedPeriods = selection;
+            this.batchSetRedPacketDisabled = selection.length === 0;
+        },
+        handleSelectionCourseChange(selection) {
+            this.updateCourse.ids = selection.map(item => item.id)
+        },
+
+
+
+
+
+
+
+        /** 获取公司下拉列表*/
+        getCompanyList() {
+            this.loading = true;
+            getCompanyList().then(response => {
+                this.companyOptions = response.data;
+                this.loading = false;
+            });
+        },
+        // 取消按钮
+        cancel() {
+            this.open = false;
+            this.reset();
+        },
+        // 表单重置
+        reset() {
+            this.form = {
+                periodId: null,
+                periodName: null,
+                companyId: null,
+                courseId: null,
+                videoId: null,
+                trainingCampId: null,
+                createTime: null,
+                updateTime: null,
+                courseStyle: null,
+                liveRoomStyle: null,
+                redPacketGrantMethod: 1,
+                periodType: 1,
+                periodStartingTime: null,
+                dateRange: [],
+                date: null,
+                days: [],
+                maxViewNum: 0,
+                periodEndTime: null,
+                timeRange: [], // 看课时间范围
+                viewStartTime: null, // 看课开始时间
+                viewEndTime: null, // 看课结束时间
+                lastJoinTime: null // 领取红包时间
+            };
+            this.resetForm("form");
+        },
+
+
+
+
+        /** 重置训练营表单 */
+        resetCampForm() {
+            this.campForm = {
+                trainingCampId: null,
+                trainingCampName: ''
+            };
+            // 如果表单已经创建,则重置校验结果
+            if (this.$refs.campForm) {
+                this.$refs.campForm.resetFields();
+            }
+        },
+
+
+
+        /** 选中训练营 */
+        selectCamp(index) {
+            if (index == null || index == undefined) return;
+            this.activeCampIndex = index;
+            // 加载对应的训练营营期数据
+            const selectedCamp = this.campList[index];
+            this.queryParams.trainingCampId = selectedCamp.trainingCampId;
+            this.getList();
+        },
+        /** 处理滚动事件,实现滚动到底部加载更多 */
+        handleScroll() {
+            // 如果正在节流中或者正在加载中,则不处理
+            if (this.scrollThrottle || this.loadingMore) return;
+
+            // 设置节流,200ms内不再处理滚动事件
+            this.scrollThrottle = true;
+            setTimeout(() => {
+                this.scrollThrottle = false;
+            }, 200);
+
+            const scrollEl = this.$refs.campList;
+            if (!scrollEl) return;
+
+            // 判断是否滚动到底部:滚动高度 + 可视高度 >= 总高度 - 30(添加30px的容差,提前触发加载)
+            const isBottom = scrollEl.scrollTop + scrollEl.clientHeight >= scrollEl.scrollHeight - 30;
+
+            // 如果滚动到底部,且有下一页数据,且当前不在加载中,则加载更多
+            if (isBottom && this.leftQueryParams.hasNextPage && !this.leftLoading && !this.loadingMore) {
+                this.loadMoreCamps();
+            }
+        },
+        /** 加载更多训练营数据 */
+        loadMoreCamps() {
+            // 已在加载中,防止重复加载
+            if (this.leftLoading || this.loadingMore) return;
+
+            // 设置加载状态
+            this.loadingMore = true;
+
+            // 页码加1
+            this.leftQueryParams.pageNum += 1;
+
+            // 加载下一页数据
+            listCamp(this.leftQueryParams).then(response => {
+                if (response && response.code === 200) {
+                    // 将新数据追加到列表中
+                    const newList = response.data.list || [];
+                    if (newList.length > 0) {
+                        this.campList = [...this.campList, ...newList];
+                    }
+
+                    // 更新是否有下一页的标志
+                    this.leftQueryParams.hasNextPage = response.data.hasNextPage;
+
+                    // 如果当前显示的列表高度不足以触发滚动,但还有更多数据,自动加载下一页
+                    this.$nextTick(() => {
+                        const scrollEl = this.$refs.campList;
+                        if (scrollEl && this.leftQueryParams.hasNextPage && scrollEl.scrollHeight <= scrollEl.clientHeight) {
+                            // 延迟一点再加载下一页,避免过快加载
+                            setTimeout(() => {
+                                this.loadMoreCamps();
+                            }, 300);
+                        }
+                    });
+                } else {
+                    this.$message.error(response.msg || '加载更多训练营失败');
+                }
+                this.loadingMore = false;
+            }).catch(error => {
+                console.error('加载更多训练营失败:', error);
+                this.$message.error('加载更多训练营失败');
+                this.loadingMore = false;
+            });
+        },
+        timeChange(type) {
+            if (type == 1) {
+                this.form.periodStartingTime = this.form.dateRange[0];
+                this.form.periodEndTime = this.form.dateRange[1];
+                if (!Array.isArray(this.form.days)) {
+                    this.form.days = [];
+                }
+                this.form.days = [];
+                let days = this.getDiff(this.form.periodStartingTime, this.form.periodEndTime);
+                for (let i = 0; i < days; i++) {
+                    this.form.days.push({ lesson: i + 1 });
+                }
+            }
+            if (type == 2) {
+                this.form.periodStartingTime = this.form.date;
+                this.form.periodEndTime = this.form.date;
+                this.form.days = [];
+            }
+        },
+        getDiff(start, end) {
+            if (start == null || start == undefined || start == '') return 0;
+            if (end == null || end == undefined || end == '') return 0;
+            if (start == end) 1;
+            const startDate = this.getUTCDate(start);
+            const endDate = this.getUTCDate(end);
+
+            const timeDiff = endDate - startDate;
+            return (Math.floor(timeDiff / (1000 * 3600 * 24))) + 1; // 直接取整
+        },
+        getUTCDate(dateStr) {
+            const [year, month, day] = dateStr.split('-').map(Number);
+            return new Date(Date.UTC(year, month - 1, day)); // 月份从0开始
+        },
+
+        getCourseList() {
+            this.course.loading = true;
+            getDays(this.course.queryParams).then(e => {
+                this.course.list = e.rows;
+                this.course.total = e.total;
+                this.course.loading = false;
+            });
+        },
+
+
+
+
+
+
+
+
+
+        handlePeriodSettings(row) {
+            console.log("公司id:", this.companyId, this.companyUserId)
+            this.periodSettingsData = row;
+            this.periodSettingsVisible = true;
+            // 初始化课程列表
+            this.course.queryParams.periodId = row.periodId;
+            // 根据当前激活的tab加载对应数据
+            this.handleTabClick({ name: this.activeTab });
+        },
+
+
+        /** 处理tab切换 */
+        handleTabClick(tab) {
+            if (tab.name === 'course') {
+                this.getCourseList();
+            } else if (tab.name === 'company') {
+                this.redPacketVisible = true;
+            }
+        },
+
+
+        /** 营期状态格式化 */
+        periodStatusFormatter(row) {
+            const statusMap = {
+                1: '未开始',
+                2: '进行中',
+                3: '已结束'
+            };
+            return statusMap[row.periodStatus] || '未知状态';
+        },
+        /** 开课状态格式化 */
+        courseStatusFormatter(row) {
+            const statusMap = {
+                0: '未开始',
+                1: '进行中',
+                2: '已结束'
+            };
+            return statusMap[row.status] || '未知状态';
+        },
+
+
+
+
+
+    },
+};
+</script>
+
+<style scoped>
+.left-aside {
+    background-color: #fff;
+    border-right: 1px solid #EBEEF5;
+    padding: 0;
+    display: flex;
+    flex-direction: column;
+    height: 800px;
+}
+
+.left-header {
+    padding: 10px;
+    border-bottom: 1px solid #EBEEF5;
+}
+
+.left-header-top {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 10px;
+}
+
+.search-btn {
+    width: 50%;
+    height: 36px;
+    background-color: #409EFF;
+    color: white;
+    border: none;
+}
+
+.search-input-wrapper {
+    margin-bottom: 10px;
+}
+
+.sort-wrapper {
+    display: flex;
+    align-items: center;
+    margin-bottom: 10px;
+}
+
+.sort-label {
+    width: 70px;
+    font-size: 14px;
+    font-weight: 600;
+    color: #909399;
+}
+
+.sort-select {
+    margin-left: 10px;
+    width: 280px;
+}
+
+.color-wrapper {
+    display: flex;
+    align-items: center;
+    margin-bottom: 10px;
+}
+
+.color-label {
+    width: 70px;
+    color: #606266;
+}
+
+.color-hint {
+    margin-left: 10px;
+    color: #606266;
+    font-size: 12px;
+}
+
+.color-help {
+    margin-left: 5px;
+    color: #909399;
+    cursor: pointer;
+}
+
+.hint-text {
+    color: #606266;
+    font-size: 12px;
+    margin-top: 5px;
+}
+
+.camp-list {
+    flex: 1;
+    overflow-y: auto;
+    padding: 3px;
+}
+
+.camp-item {
+    margin-bottom: 5px;
+    padding: 15px;
+    background-color: #ffffff;
+    position: relative;
+    cursor: pointer;
+    display: flex;
+    justify-content: space-between;
+    border: 1px solid #eaedf2;
+}
+
+.camp-item:last-child {
+    margin-bottom: 0;
+}
+
+.camp-item:hover {
+    background-color: #f5f9ff;
+}
+
+.camp-item.active {
+    background-color: #eaf4ff;
+    border-left: 1px solid #75b8fc;
+}
+
+.camp-content {
+    flex: 1;
+    padding-right: 10px;
+}
+
+.camp-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 8px;
+    color: #333;
+    display: flex;
+    align-items: center;
+}
+
+.camp-icon {
+    font-size: 16px;
+    margin-right: 6px;
+    color: #409EFF;
+}
+
+.camp-info {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 8px;
+    font-size: 12px;
+    color: #c4c1c1;
+    line-height: 1.5;
+}
+
+.camp-stats {
+    display: flex;
+    justify-content: space-between;
+    font-size: 12px;
+    color: #666;
+    background-color: #f5f9ff;
+    padding: 6px 10px;
+    border-radius: 4px;
+    line-height: 1.5;
+}
+
+.stat-item {
+    display: flex;
+    align-items: center;
+}
+
+.stat-item i {
+    margin-right: 4px;
+    font-size: 14px;
+    color: #409EFF;
+}
+
+.camp-actions {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: flex-end;
+    gap: 8px;
+    border-left: 1px dashed #eaedf2;
+    padding-left: 12px;
+    min-width: 50px;
+}
+
+.action-btn {
+    padding: 2px 5px;
+    font-size: 12px;
+    border-radius: 4px;
+    transition: all 0.2s;
+}
+
+.action-btn:hover {
+    background-color: rgba(255, 255, 255, 0.8);
+}
+
+.delete-btn {
+    color: #f56c6c;
+}
+
+.delete-btn:hover {
+    background-color: rgba(245, 108, 108, 0.1);
+}
+
+.copy-btn {
+    color: #409EFF;
+}
+
+.copy-btn:hover {
+    background-color: rgba(64, 158, 255, 0.1);
+}
+
+.warning-icon {
+    color: #E6A23C;
+    font-size: 16px;
+    margin-left: 5px;
+}
+
+.el-main {
+    padding: 10px;
+}
+
+/* 添加训练营表单样式 */
+.drawer-footer {
+    /* position: absolute; */
+    bottom: 0;
+    left: 0;
+    right: 0;
+    padding: 20px;
+    background: #fff;
+    text-align: right;
+    border-top: 1px solid #e8e8e8;
+}
+
+.el-input-number {
+    width: 100%;
+}
+
+/* 加载更多样式 */
+.loading-more {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 12px 0;
+    color: #909399;
+    font-size: 14px;
+}
+
+.loading-more i {
+    margin-right: 5px;
+    font-size: 16px;
+}
+
+/* 无更多数据提示 */
+.no-more-data {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 12px 0;
+    color: #c0c4cc;
+    font-size: 13px;
+}
+
+.no-more-data span {
+    position: relative;
+    display: flex;
+    align-items: center;
+}
+</style>

+ 1 - 0
src/views/company/companyRecharge/index.vue

@@ -44,6 +44,7 @@
           type="primary"
           icon="el-icon-edit"
           @click="handleRecharge"
+          v-hasPermi="['company:companyRecharge:Recharge']"
         >充值</el-button>
       </el-col>
 	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>

+ 662 - 0
src/views/crm/components/assistUser.vue

@@ -0,0 +1,662 @@
+<template>
+    <div>
+        <el-form label-position="left" ref="assistForm" :model="assistForm"  label-width="120px" v-if="!flag">
+            <el-form-item label="未添加协作客户" >
+                <span>{{this.noAssistCount}}个</span>
+            </el-form-item>
+            <el-form-item label="未添加协作客户" >
+                <span>{{this.assistCount}}个</span>
+            </el-form-item>
+
+            <el-form-item label="协作人" prop="users" label-width="60px">
+                <el-row :gutter="10" class="mb8">
+                    <el-col :span="1.5">
+                        <el-button @click="handleUserSelect">添加协作人</el-button>
+                    </el-col>
+                </el-row>
+            </el-form-item>
+            <el-form-item  label-width="0">
+                <el-table border  :data="users">
+                    <el-table-column label="ID" align="center" prop="userId"/>
+                    <el-table-column label="员工帐号" align="center" prop="userName" width="100px"/>
+                    <el-table-column label="员工姓名" align="center" prop="nickName" />
+                    <el-table-column label="所属部门" align="center" prop="deptName"/>
+                    <el-table-column label="添加数量" align="center"  prop="count" width="150px" v-if="!flag">
+                        <template slot-scope="scope">
+                            <div>
+                                <el-input-number ref="stepTxtNum" :min="0" v-model="scope.row.count"  @change="changeVal(scope.row)"   size="mini"   ></el-input-number>
+                            </div>
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="操作"   align="center" fixed="right"  width="60px" class-name="small-padding fixed-width">
+                        <template slot-scope="scope">
+                            <el-button
+                            size="mini"
+                            type="text"
+                            @click="handleRemoveUser(scope.row.$index)"
+                            >删除</el-button>
+                        </template>
+                    </el-table-column>
+                </el-table>
+            </el-form-item>
+        </el-form>
+        <div   class="footer" v-if="!flag">
+            <el-button type="primary" @click="submitAssistForm">确 定</el-button>
+        </div>
+        <el-dialog :title="userSelect.title" :visible.sync="userSelect.open" width="1000px" append-to-body>
+            <user-select ref="userSelects" @selectUser="selectUser"  ></user-select>
+        </el-dialog>
+
+        <!-- 手动分佣模式 -->
+        <el-form label-position="left" ref="assistForm2" :model="assistForm2"  label-width="120px" v-if="flag">
+            <el-form-item  label-width="0">
+                <div v-for="(customer, customerIndex) in customers" :key="customer.customerId || customerIndex" class="customer-section">
+                    <el-card class="customer-card" shadow="hover">
+                        <div slot="header" class="customer-header">
+                            <span class="customer-title">
+                                <strong>{{ customer.customerName }}</strong>
+                                <span class="customer-code">({{ customer.customerCode }})</span>
+                            </span>
+                            <el-button
+                                size="mini"
+                                type="primary"
+                                @click="handleAddCollaborator(customerIndex)"
+                                icon="el-icon-plus">
+                                添加协作人
+                            </el-button>
+                        </div>
+
+                        <div class="collaborator-content">
+                            <el-table
+                                :data="customer.collaborators"
+                                border
+                                size="small"
+                                v-if="customer.collaborators && customer.collaborators.length > 0">
+                                <el-table-column label="员工姓名" align="center" prop="companyUserName" width="100px"/>
+                                <el-table-column label="员工ID" align="center" prop="companyUserId" width="80px"/>
+                                <el-table-column label="分佣比例(%)" align="center" width="160px">
+                                    <template slot-scope="scope">
+                                        <el-input-number
+                                            v-model="scope.row.rate"
+                                            :min="0"
+                                            :max="100"
+                                            size="mini"
+                                            @input="handleRateChange(customerIndex, scope.$index, scope.row)">
+                                        </el-input-number>
+                                    </template>
+                                </el-table-column>
+                                <el-table-column label="状态" align="center" width="80px">
+                                    <template slot-scope="scope">
+                                        <el-tag :type="scope.row.isNew ? 'success' : 'info'" size="mini">
+                                            {{ scope.row.isNew ? '新增' : '原有' }}
+                                        </el-tag>
+                                    </template>
+                                </el-table-column>
+                                <el-table-column label="操作" align="center" width="80px">
+                                    <template slot-scope="scope">
+                                        <el-button
+                                            size="mini"
+                                            type="text"
+                                            @click="handleRemoveCollaborator(customerIndex, scope.$index)">
+                                            删除
+                                        </el-button>
+                                    </template>
+                                </el-table-column>
+                            </el-table>
+
+                            <div v-else class="no-collaborator">
+                                <i class="el-icon-user" style="font-size: 48px; color: #ddd;"></i>
+                                <p>暂无协作人员</p>
+                            </div>
+
+                            <!-- 分佣比例汇总 -->
+                            <div class="rate-summary-container">
+                                <div class="rate-summary">
+                                    <div class="rate-item">
+                                        <span class="rate-label">协作人员总分佣比例:</span>
+                                        <span :class="getTotalRateClass(customerIndex)">
+                                            {{ getTotalRate(customerIndex) }}%
+                                        </span>
+                                        <span v-if="getTotalRate(customerIndex) > 100" class="rate-warning">
+                                            (超出100%,请调整)
+                                        </span>
+                                    </div>
+                                    <div class="rate-item owner-rate">
+                                        <span class="rate-label">本人佣金比例:</span>
+                                        <span :class="getOwnerRateClass(customerIndex)">
+                                            {{ getOwnerRate(customerIndex) }}%
+                                        </span>
+                                        <span v-if="getOwnerRate(customerIndex) < 0" class="rate-warning">
+                                            (协作人员分佣超出100%,请调整)
+                                        </span>
+                                    </div>
+                                    <div class="rate-item total-check" v-if="customer.collaborators && customer.collaborators.length > 0">
+                                        <span class="rate-label">总计:</span>
+                                        <span class="rate-total">
+                                            {{ getTotalRate(customerIndex) + getOwnerRate(customerIndex) }}%
+                                        </span>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </el-card>
+                </div>
+            </el-form-item>
+        </el-form>
+
+        <div class="footer" v-if="flag">
+            <el-button @click="$emit('close')">取 消</el-button>
+            <el-button type="primary" @click="submitAssistForm2" :loading="submitLoading">确 定</el-button>
+        </div>
+    </div>
+</template>
+
+<script>
+import { assistToUser,selectByCustomerIds,allOperation } from "@/api/crm/customer";
+import userSelect from '../../company/components/userSelect.vue';
+export default {
+    components: {userSelect },
+    name: "visit",
+    data() {
+        return {
+            originalCollaborators: {}, // 确保初始化为空对象
+            flag:false,
+            noAssistCount:0,
+            assistCount:0,
+            customerIds:[],
+            currentCustomerIndex: -1,
+            submitLoading: false,
+            userSelect:{
+                title:"选择员工",
+                open:false,
+            },
+            assistForm: {
+            },
+            assistForm2:{},
+            // 表单校验
+            assistRules: {
+
+            },
+            users:[],
+            customers:[]
+
+        };
+    },
+    created() {
+
+    },
+    methods: {
+         // 检查并更新所有协作者的操作状态
+         checkAndUpdateOperations() {
+            // 确保 originalCollaborators 存在
+            if (!this.originalCollaborators) {
+                this.originalCollaborators = {};
+            }
+            this.customers.forEach(customer => {
+                if (customer.collaborators) {
+                    customer.collaborators.forEach(collaborator => {
+                        if (collaborator.id && (!collaborator.operation || collaborator.operation === 'NONE')) {
+                            const originalKey = `${collaborator.customerId}_${collaborator.companyUserId}`;
+                            const originalCollaborator = this.originalCollaborators[originalKey];
+
+                            if (originalCollaborator &&
+                                (originalCollaborator.rate !== collaborator.rate ||
+                                 originalCollaborator.remark !== (collaborator.remark || ''))) {
+                                collaborator.operation = 'UPDATE';
+                            } else if (!originalCollaborator && collaborator.id) {
+                                // 如果找不到原始数据但有ID,说明可能是数据加载问题,标记为UPDATE
+                                collaborator.operation = 'UPDATE';
+                            }
+                        }
+                    });
+                }
+            });
+        },
+         // 处理分佣比例变化
+         handleRateChange(customerIndex, collaboratorIndex, collaborator) {
+            // 确保 originalCollaborators 存在
+            if (!this.originalCollaborators) {
+                this.originalCollaborators = {};
+            }
+            // 如果是原有协作者且分佣比例发生变化,标记为UPDATE
+            if (collaborator.operation === 'NONE' || !collaborator.operation) {
+                const originalKey = `${collaborator.customerId}_${collaborator.companyUserId}`;
+                const originalCollaborator = this.originalCollaborators[originalKey];
+
+
+
+                if (originalCollaborator) {
+                    // 检查分佣比例或备注是否发生变化
+                    if (originalCollaborator.rate !== collaborator.rate ||
+                        originalCollaborator.remark !== (collaborator.remark || '')) {
+                        collaborator.operation = 'UPDATE';
+                    }
+                } else {
+                    // 如果找不到原始数据,但有id,说明是原有数据,标记为UPDATE
+                    if (collaborator.id) {
+                        collaborator.operation = 'UPDATE';
+                    }
+                }
+            }
+
+            this.validateTotalRate(customerIndex);
+        },
+        validateTotalRate(customerIndex) {
+            const total = this.getTotalRate(customerIndex);
+            const ownerRate = this.getOwnerRate(customerIndex);
+
+            if(total > 100) {
+                this.$message.warning(`客户 ${this.customers[customerIndex].customerName} 的协作人员总分佣比例不能超过100%`);
+            } else if(ownerRate < 10) {
+                this.$message.warning(`客户 ${this.customers[customerIndex].customerName} 的本人佣金比例过低,建议调整协作人员分佣比例`);
+            }
+        },
+        // 获取本人佣金比例(100% - 协作人员总分佣比例)
+        getOwnerRate(customerIndex) {
+            const collaboratorTotalRate = this.getTotalRate(customerIndex);
+            return Math.max(0, 100 - collaboratorTotalRate);
+        },
+        // 获取本人佣金比例的样式类
+        getOwnerRateClass(customerIndex) {
+            const ownerRate = this.getOwnerRate(customerIndex);
+            if(ownerRate < 0) return 'rate-error';
+            if(ownerRate === 0) return 'rate-warning';
+            return 'rate-success';
+        },
+        getTotalRateClass(customerIndex) {
+            const total = this.getTotalRate(customerIndex);
+            if(total > 100) return 'rate-error';
+            if(total === 100) return 'rate-success';
+            return 'rate-normal';
+        },
+        handleAddCollaborator(customerIndex) {
+            // 为特定客户添加协作人
+            this.currentCustomerIndex = customerIndex;
+            var that = this;
+            this.userSelect.open = true;
+            setTimeout(() => {
+                that.$refs.userSelects.getList();
+            }, 500);
+        },
+        handleRemoveCollaborator(customerIndex, collaboratorIndex) {
+            const customer = this.customers[customerIndex];
+            const collaborator = customer.collaborators[collaboratorIndex];
+            if (collaborator.operation === 'ADD') {
+                // 如果是新增的协作者,直接从列表中移除
+                customer.collaborators.splice(collaboratorIndex, 1);
+            } else {
+                // 如果是原有的协作者,标记为删除但不从列表中移除
+                collaborator.operation = 'DELETE';
+                // 可以选择隐藏已删除的项目或者用特殊样式显示
+                // 这里我们从界面上移除,但在提交时会包含删除操作
+                customer.collaborators.splice(collaboratorIndex, 1);
+
+                // 将删除的协作者添加到待删除列表中
+                if (!customer.deletedCollaborators) {
+                    this.$set(customer, 'deletedCollaborators', []);
+                }
+                customer.deletedCollaborators.push(collaborator);
+            }
+        },
+        getTotalRate(customerIndex) {
+            const customer = this.customers[customerIndex];
+            if(!customer.collaborators) return 0;
+
+            return customer.collaborators.reduce((total, collaborator) => {
+                // 只计算未删除的协作者
+                if (collaborator.operation !== 'DELETE') {
+                    return total + (collaborator.rate || 0);
+                }
+                return total;
+            }, 0);
+        },
+        async loadCustomerCollaborators() {
+            // 确保 originalCollaborators 存在
+            if (!this.originalCollaborators) {
+                this.originalCollaborators = {};
+            }
+
+            // 加载每个客户的协作者信息
+            let customerIds = this.customers.map(customer => customer.customerId || null);
+            this.customerIds = customerIds;
+
+            if(customerIds && customerIds.length > 0){
+                try {
+                    //查询用户分佣信息
+                    selectByCustomerIds(customerIds).then(response => {
+                        if(response && response.code == 200){
+                            // 清空原始数据
+                            this.originalCollaborators = {};
+
+                            // 遍历每个客户,匹配对应的协作者数据
+                            this.customers.forEach(customer => {
+                                // 查找当前客户的协作者数据
+                                const customerData = response.data.find(item => item.customerId === customer.customerId);
+
+                                if(customerData && customerData.assistList && customerData.assistList.length > 0) {
+                                    // 将协作者数据转换为组件需要的格式
+                                    const collaborators = customerData.assistList.map(item => {
+                                        const collaborator = {
+                                            id: item.id,
+                                            companyId: item.companyId,
+                                            companyUserId: item.companyUserId,
+                                            companyUserName: item.companyUserName,
+                                            customerId: item.customerId,
+                                            rate: item.rate || 0,
+                                            remark: item.remark || '',
+                                            operation: 'NONE' // 标记为原有数据,无变化
+                                        };
+
+                                        // 保存原始数据用于对比
+                                        const originalKey = `${item.customerId}_${item.companyUserId}`;
+                                        this.originalCollaborators[originalKey] = {
+                                            id: item.id,
+                                            rate: item.rate || 0,
+                                            remark: item.remark || ''
+                                        };
+
+
+                                        return collaborator;
+                                    });
+
+                                    // 设置客户的协作者列表
+                                    this.$set(customer, 'collaborators', collaborators);
+                                    // 初始化删除列表
+                                    this.$set(customer, 'deletedCollaborators', []);
+                                } else {
+                                    // 如果没有协作者数据,设置为空数组
+                                    this.$set(customer, 'collaborators', []);
+                                    this.$set(customer, 'deletedCollaborators', []);
+                                }
+                            });
+
+                        } else {
+                            // 如果查询失败,确保 originalCollaborators 是空对象
+                            this.originalCollaborators = {};
+                        }
+                    }).catch(error => {
+                        this.originalCollaborators = {};
+                        this.$message.error("加载协作者数据失败,请重试");
+                    });
+                } catch(error) {
+                    // 异常情况下,确保 originalCollaborators 是空对象
+                    this.originalCollaborators = {};
+                    // 异常情况下,为所有客户设置空的协作者列表
+                    this.customers.forEach(customer => {
+                        this.$set(customer, 'collaborators', []);
+                        this.$set(customer, 'deletedCollaborators', []);
+                    });
+                    this.$message.error("加载协作者数据失败,请重试");
+                }
+            } else {
+                // 如果没有客户ID,确保 originalCollaborators 是空对象
+                this.originalCollaborators = {};
+            }
+        },
+        changeVal(row) {
+            this.$forceUpdate();//解决点击计数器失效问题
+            this.computeCount();
+            if(this.assistCount>this.customerIds.length){
+                this.$nextTick(() => {
+                        row.count=0;
+                        this.computeCount();
+                });
+
+            }
+        },
+        handleRemoveUser(index){
+            this.users.splice(index,1);
+            this.computeCount();
+            this.$refs.userSelects.delUser(index);
+        },
+        selectUser(data){
+            if(this.flag){
+                // 手动分佣模式 - 为特定客户添加协作人
+                if(this.currentCustomerIndex >= 0) {
+                    const customer = this.customers[this.currentCustomerIndex];
+                    if(!customer.collaborators) {
+                        this.$set(customer, 'collaborators', []);
+                    }
+                    data.forEach(user => {
+                        // 检查是否已存在
+                        const exists = customer.collaborators.some(c => c.userId === user.userId);
+                        const existsInDeleted = customer.deletedCollaborators &&
+                            customer.deletedCollaborators.some(c => c.companyUserId === user.userId);
+                        if(!exists && !existsInDeleted) {
+                            const collaborator = {
+                                companyUserId: user.userId,
+                                companyUserName: user.nickName,
+                                customerId: customer.customerId,
+                                rate: 0,
+                                remark: '',
+                                operation: 'ADD' // 标记为新增
+                            };
+                            customer.collaborators.push(collaborator);
+                        } else if (existsInDeleted) {
+                            // 如果在删除列表中存在,则恢复该协作者
+                            const deletedIndex = customer.deletedCollaborators.findIndex(c => c.companyUserId === user.userId);
+                            if (deletedIndex >= 0) {
+                                const restoredCollaborator = customer.deletedCollaborators[deletedIndex];
+                                restoredCollaborator.operation = 'NONE'; // 恢复为原有状态
+                                customer.collaborators.push(restoredCollaborator);
+                                customer.deletedCollaborators.splice(deletedIndex, 1);
+                            }
+                        }
+                    });
+                    this.userSelect.open=false;
+                }
+            } else{
+                var users=[];
+                var number=parseInt(this.customerIds.length/data.length);
+                data.forEach(element => {
+                    var user={
+                        userId:element.userId,
+                        userName:element.userName,
+                        nickName:element.nickName,
+                        deptName:element.dept.deptName,
+                        nowDayCustomerCount:element.nowDayCustomerCount,
+                        phonenumber:element.phonenumber,
+                        count:number,
+                    }
+                    users.push(user)
+                });
+                this.users=users;
+                this.userSelect.open=false;
+                this.computeCount()
+            }
+
+        },
+        computeCount(){
+            this.assistCount=0;
+            var that=this;
+            this.users.forEach(element => {
+                that.assistCount+=element.count;
+            });
+            this.noAssistCount=this.customerIds.length-this.assistCount
+        },
+        handleUserSelect(){
+            var that=this;
+            this.userSelect.open=true;
+            setTimeout(() => {
+                that.$refs.userSelects.getList();
+            }, 500);
+        },
+        async init(customerIds,flag){
+            this.flag = flag //是否设置分佣
+            if(flag){
+                this.customers = customerIds;
+                await this.loadCustomerCollaborators();
+            } else {
+                this.customerIds =  customerIds;
+                this.assistCount=0;
+                this.noAssistCount=this.customerIds.length;
+                this.users=[];
+            }
+
+        },
+        async submitAssistForm2(){
+            // 提交前检查并更新操作状态
+            this.checkAndUpdateOperations();
+            // 验证数据
+            let hasError = false;
+            for(let i = 0; i < this.customers.length; i++) {
+                const customer = this.customers[i];
+                const totalRate = this.getTotalRate(i);
+
+                if(totalRate > 100) {
+                    this.$message.error(`客户 ${customer.customerName} 的协作人员总分佣比例不能超过100%`);
+                    hasError = true;
+                    break;
+                }
+            }
+
+            if(hasError) return;
+
+            this.submitLoading = true;
+
+            try {
+                // 准备提交数据 - 包含所有操作类型
+                const submitData = {
+                    customerIds: this.customers.map(c => c.customerId), // 包含所有客户ID
+                    operations: []
+                };
+
+                this.customers.forEach(customer => {
+                    if(customer.collaborators && customer.collaborators.length > 0) {
+                        customer.collaborators.forEach(collaborator => {
+                            if (collaborator.operation !== 'DELETE') {
+                                 // 确保每个协作者都有正确的operation字段
+                                 let operation = collaborator.operation;
+                                 // 如果没有operation字段,根据是否有id来判断
+                                if (!operation) {
+                                    if (collaborator.id) {
+                                        // 有id说明是原有数据,检查是否有变化
+                                        const originalKey = `${collaborator.customerId}_${collaborator.companyUserId}`;
+                                        const originalCollaborator = this.originalCollaborators[originalKey];
+
+                                        if (originalCollaborator &&
+                                            (originalCollaborator.rate !== collaborator.rate ||
+                                             originalCollaborator.remark !== (collaborator.remark || ''))) {
+                                            operation = 'UPDATE';
+                                        } else {
+                                            operation = 'NONE';
+                                        }
+                                    } else {
+                                        // 没有id说明是新增数据
+                                        operation = 'ADD';
+                                    }
+                                }
+                                submitData.operations.push({
+                                    operation: operation, // ADD, UPDATE, NONE
+                                    id: collaborator.id || null,
+                                    companyId: collaborator.companyId,
+                                    companyUserId: collaborator.companyUserId,
+                                    companyUserName: collaborator.companyUserName,
+                                    customerId: customer.customerId,
+                                    rate: collaborator.rate,
+                                    remark: collaborator.remark || ''
+                                });
+                            }
+                        });
+                    }
+                    // 处理已删除的协作者
+                    if(customer.deletedCollaborators && customer.deletedCollaborators.length > 0) {
+                        customer.deletedCollaborators.forEach(collaborator => {
+                            submitData.operations.push({
+                                operation: 'DELETE',
+                                id: collaborator.id,
+                                companyUserId: collaborator.companyUserId,
+                                customerId: customer.customerId
+                            });
+                        });
+                    }
+
+                });
+
+                console.log("提交的完整分佣数据:", JSON.stringify(submitData, null, 2));
+
+                // 这里需要根据你的实际更新接口来调用
+                const response = await allOperation(submitData.operations);
+
+                if(response.code === 200) {
+                    this.$message.success("分佣设置保存成功");
+                    this.$emit('close');
+                } else {
+                    this.$message.error(response.msg || "保存失败");
+                }
+            } catch(error) {
+                this.$message.error("保存失败,请重试");
+            } finally {
+                this.submitLoading = false;
+            }
+        },
+        /** 提交按钮 */
+        submitAssistForm() {
+            var that=this;
+            this.$refs["assistForm"].validate(valid => {
+                if (valid) {
+                    var users=[];
+                    var customerIds=[];
+                    var idIndex=0;
+                    var totalAssistCount=0;
+                    console.log("qxj users",JSON.stringify(this.users));
+                    this.users.forEach(element => {
+                        if(element.count>0){
+                            var ids=that.customerIds.slice(idIndex,idIndex+element.count)
+                            console.log("qxj customerIds:"+that.customerIds+" count:"+element.count);
+                            console.log("qxj ids:"+ids);
+                            customerIds=customerIds.concat(ids);
+                            idIndex=idIndex+element.count;
+                            var data={companyUserId:element.userId,count:element.count};
+                            users.push(data);
+                            totalAssistCount+=element.count;
+                        }
+                    });
+                    if(users.length==0){
+                        this.msgError("请选择员工");
+                        return;
+                    }
+                    if(totalAssistCount>(this.assistCount+this.noAssistCount)){
+                        this.msgError("添加数量有误");
+                        return;
+                    }
+                    this.myloading = this.$loading({
+                        lock: true,
+                        text: '处理中...',
+                        spinner: 'el-icon-loading',
+                        background: 'rgba(0, 0, 0, 0.7)'
+                    });
+                    var data={customerIds:customerIds,users:users}
+                    console.log("qxj data:",JSON.stringify(data));
+                    assistToUser(data).then(response => {
+                        this.myloading.close()
+                        if (response.code === 200) {
+                            this.msgSuccess("操作成功");
+                            this.$emit('close');
+                        }
+                    });
+                }
+            });
+        },
+        closeAction(){
+            this.$refs.userSelects.users=[];
+        }
+    }
+};
+</script>
+<style lang="scss" scoped>
+.contents{
+    height: 100%;
+    background-color: #fff;
+    padding: 20px;
+
+}
+.footer{
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+}
+</style>
+
+
+

+ 817 - 0
src/views/crm/customer/assist.vue

@@ -0,0 +1,817 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="客户编码" prop="customerCode">
+        <el-input
+          style="width:220px"
+          v-model="queryParams.customerCode"
+          placeholder="请输入客户编码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户名称" prop="customerName">
+        <el-input
+          style="width:220px"
+          v-model="queryParams.customerName"
+          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 label="跟进阶段" prop="status">
+        <el-select style="width:220px" multiple filterable  v-model="statusArr" placeholder="请选择跟进阶段" clearable size="small">
+           <el-option
+                v-for="item in statusOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.dictValue"
+              />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="客户类型" prop="customerLevel">
+        <el-select style="width:220px" filterable  v-model="queryParams.customerLevel" placeholder="请选择客户类型" clearable size="small">
+           <el-option
+                v-for="item in customerLevelOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.dictValue"
+              />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="客户标签" prop="tags">
+            <el-select style="width:220px" multiple  filterable v-model="tagIds" placeholder="请选择客户标签" clearable size="small">
+              <el-option
+                    v-for="item in tagsOptions"
+                    :key="item.dictLabel"
+                    :label="item.dictLabel"
+                    :value="item.dictLabel"
+                  />
+            </el-select>
+          </el-form-item>
+      <el-form-item label="客户来源" prop="source">
+        <el-select style="width:220px" multiple filterable  v-model="sourceArr" placeholder="请选择客户来源" clearable size="small">
+           <el-option
+                v-for="item in sourceOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.dictValue"
+              />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTimeRange">
+        <el-date-picker
+          style="width:205.4px"
+          clearable size="small"
+          v-model="createTimeRange"
+          type="daterange"
+          value-format="yyyy-MM-dd"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="领取时间" prop="receiveTime">
+        <el-date-picker
+              style="width:220px"
+              clearable size="small"
+              v-model="dateRange"
+              type="daterange"
+              value-format="yyyy-MM-dd"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期">
+            </el-date-picker>
+      </el-form-item>
+      <el-form-item label="历史订单" prop="isHisOrder">
+          <el-select style="width:220px" filterable v-model="queryParams.isHisOrder" placeholder="请选择历史订单" clearable size="small">
+            <el-option key="1"  label="已下单" value="1" />
+            <el-option key="0"  label="未下单" value="0" />
+          </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-row :gutter="10" class="mb8">
+
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="multiple"
+          @click="handleAssist"
+          v-hasPermi="['crm:customer:assistToUser']"
+        >客户协作</el-button>
+      </el-col>
+
+
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          size="mini"
+          :disabled="multiple"
+          @click="handleSendBatchSms"
+          v-hasPermi="['crm:customer:sendBatchSms']"
+        >批量发送短信</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-dropdown
+          @command="handleCommand"
+          trigger="click"
+          placement="bottom-start"
+        >
+          <el-dropdown-menu slot="dropdown" style="width: 120px;">
+            <el-dropdown-item
+              v-for="option in sysCreateType"
+              :key="option.dictValue"
+              :command="option.dictValue"
+            >
+              <i :class="option.iconClass" style="margin-right: 10px;"></i>
+              {{ option.dictLabel }}
+            </el-dropdown-item>
+          </el-dropdown-menu>
+          <!-- <span class="el-dropdown-link" >
+              <el-button  type="success"   size="mini" >
+                创建订单
+              </el-button>
+            </span> -->
+        </el-dropdown>
+
+<!--        <el-button-->
+<!--          type="success"-->
+<!--          size="mini"-->
+<!--          @click="addPackageOrder"-->
+<!--        >创建订单</el-button>-->
+      </el-col>
+
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['crm:customer:export']"
+        >导出</el-button>
+      </el-col> -->
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table  height="500" border v-loading="loading" :data="customerList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="客户编码" align="center" prop="customerCode" />
+      <el-table-column  label="客户名称"   align="center" prop="customerName" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <el-link @click="handleShow(scope.row)" :underline="false" type="primary" >{{scope.row.customerName}}</el-link>
+        </template>
+      </el-table-column>
+      <el-table-column  label="手机" width="120px"  align="center" prop="mobile"   >
+        <template slot-scope="scope">
+          {{scope.row.mobile}}
+          <el-button type="text"    size="mini" @click="callNumber(scope.row.customerId,null)">拨号</el-button>
+          <el-button v-hasPermi="['crm:customer:addVisit']"  type="text" size="mini" @click="handleAddVisit(scope.row)">写跟进</el-button>
+          <el-button type="text"    size="mini" @click="addPackageOrder(scope.row)" style="margin-right: 15px;">创建订单</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column  label="客户来源" align="center" prop="source">
+        <template slot-scope="scope">
+            <el-tag prop="status" v-for="(item, index) in sourceOptions"    v-if="scope.row.source==item.dictValue">{{item.dictLabel}}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column  label="跟进阶段"  width="200" align="center" prop="visitStatus">
+        <template slot-scope="scope">
+            <el-tag prop="visitStatus" v-for="(item, index) in statusOptions"    v-if="scope.row.visitStatus==item.dictValue">{{item.dictLabel}}</el-tag><br/>
+            <el-button  v-hasPermi="['crm:customer:addVisitStatus']"  type="text" size="mini" @click="handleVisitStatus(scope.row)">修改</el-button>
+          </template>
+      </el-table-column>
+      <el-table-column  label="客户类型"  width="200" align="center" prop="customerLevel">
+        <template slot-scope="scope">
+            <el-tag prop="status" v-for="(item, index) in customerLevelOptions"    v-if="scope.row.customerLevel===item.dictValue">{{item.dictLabel}}</el-tag>
+            <el-button   v-hasPermi="['crm:customer:addCustomerType']"  type="text" size="mini" @click="handleCustomerType(scope.row)">修改</el-button>
+          </template>
+      </el-table-column>
+      <el-table-column  label="标签" width="120px"  align="center" prop="tags"   >
+        <template slot-scope="scope">
+          {{scope.row.tags}}
+          <el-button  v-hasPermi="['crm:customer:addTag']"  type="text" size="mini" @click="handleAddTag(scope.row)">打标签</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column  label="备注" width="150px"  align="center" prop="remark"   >
+        <template slot-scope="scope">
+          {{scope.row.remark}}
+          <el-button v-hasPermi="['crm:customer:addRemark']" type="text" size="mini" @click="handleAddRemark(scope.row)">修改备注</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column  label="邀请人" width="150px" align="center" >
+        <template slot-scope="scope">
+          <div v-for="(user, index) in scope.row.assistUser" :key="index">
+            {{ user }}
+            <br v-if="index < scope.row.assistUser.length - 1"> <!-- 在最后一个元素之前添加换行 -->
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="进线客户详情" align="center" :show-overflow-tooltip="true" prop="registerDesc" />
+      <el-table-column label="最新跟进时间" align="center" prop="lastTime" />
+      <el-table-column label="领取时间" align="center" prop="receiveTime" />
+      <el-table-column label="进线客户提交日期" align="center" prop="registerSubmitTime" />
+      <el-table-column label="创建时间" align="center" prop="customerCreateTime" width="180">
+      </el-table-column>
+      <el-table-column label="操作"   align="center" fixed="right" width="120px" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleShow(scope.row)"
+            v-hasPermi="['crm:customer:query']"
+          >查看</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleRecover(scope.row)"
+            v-hasPermi="['crm:customer:recover']"
+          >回收公海</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" />
+    </el-drawer>
+    <el-dialog :title="addSms.title" :visible.sync="addSms.open" width="1000px" append-to-body>
+       <add-batch-sms ref="sms" @close="closeSms()"></add-batch-sms>
+    </el-dialog>
+
+
+    <el-dialog :title="source.title" :visible.sync="source.open" width="1000px" append-to-body>
+       <edit-source ref="editSource" @close="closeSource()"></edit-source>
+    </el-dialog>
+
+    <el-dialog :title="visit.title" :visible.sync="visit.open" width="600px" append-to-body>
+      <add-visit @closeVisit="closeVisit"   ref="addVisit" />
+    </el-dialog>
+    <el-dialog :title="customer.title" :visible.sync="customer.open" width="1000px" append-to-body>
+       <add-or-edit-customer ref="customer" @close="closeCustomer()"></add-or-edit-customer>
+    </el-dialog>
+    <el-dialog :title="assign.title" :visible.sync="assign.open" width="800px" append-to-body>
+        <assign-user  ref="assignUser" @close="closeAssign"   />
+    </el-dialog>
+    <el-dialog :title="assist.title" :visible.sync="assist.open" width="800px" append-to-body>
+        <assist-user  ref="assistUser" @close="closeAssist"   />
+    </el-dialog>
+
+    <el-dialog :title="addTag.title" :visible.sync="addTag.open" width="600px" append-to-body>
+        <add-tag ref="tag" @close="closeTag()"></add-tag>
+    </el-dialog>
+    <el-dialog :title="addRemark.title" :visible.sync="addRemark.open" width="600px" append-to-body>
+        <add-remark ref="remark" @close="closeRemark()"></add-remark>
+    </el-dialog>
+    <el-dialog :title="addCustomerType.title" :visible.sync="addCustomerType.open" width="600px" append-to-body>
+        <add-customer-type ref="customerType" @close="closeCustomerType()"></add-customer-type>
+    </el-dialog>
+    <el-dialog :title="addVisitStatus.title" :visible.sync="addVisitStatus.open" width="600px" append-to-body>
+        <add-visit-status ref="visitStatus" @close="closeVisitStatus()"></add-visit-status>
+    </el-dialog>
+    <el-dialog title="创建线上订单" :visible.sync="addPackageOpen" width="1000px" append-to-body>
+      <addPackage  @closePackage="closePackage"   ref="addPackageVisit"  :customerId="customerId"/>
+    </el-dialog>
+    <el-dialog title="创建线下订单" :visible.sync="addOfflineOrder.open" width="1000px" append-to-body>
+      <add-order-offline @closeOrderOffline="closeOrderOffline"   ref="addOrderOffline" />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getMyAssistList,recover,exportCustomer  } from "@/api/crm/customer";
+import { remove,listAssist, getAssist, delAssist, addAssist, updateAssist, exportAssist } from "@/api/crm/assist";
+import customerDetails from '../components/customerDetails.vue';
+import addVisit from '../components/addVisit.vue';
+import {getCitys} from "@/api/store/city";
+import addBatchSms from '../components/addBatchSms.vue';
+import editSource from '../components/editSource.vue';
+import addOrEditCustomer from '../components/addOrEditCustomer.vue';
+import assignUser from '../components/assignUser.vue';
+import assistUser from '../components/assistUser.vue';
+import addTag from '../components/addTag.vue';
+import addRemark from '../components/addRemark.vue';
+import addCustomerType from '../components/addCustomerType.vue';
+import addVisitStatus from '../components/addVisitStatus.vue';
+import addPackage from "@/views/store/components/addOrder";
+import addOrderOffline from "@/views/store/components/addOrderOffline";
+import {customerLevelOptions} from "@/api/crm/customerLevel";
+export default {
+  name: "Customer",
+  components: {addPackage,addOrderOffline,addVisitStatus,addCustomerType,addRemark,addTag,assignUser,assistUser,addOrEditCustomer,editSource, addBatchSms,customerDetails,addVisit },
+  data() {
+    return {
+      customerId:null,
+      addOfflineOrder:{
+        open:false,
+      },
+      sysCreateType:[
+        { dictLabel: "线下订单", dictValue: "1" },
+
+        { dictLabel: "线上订单", dictValue: "2" },
+      ],
+      addPackageOpen:false,
+      addVisitStatus:{
+          open:false,
+          title:"跟进阶段"
+      },
+      addCustomerType:{
+          open:false,
+          title:"客户类型"
+      },
+      addRemark:{
+          open:false,
+          title:"客户备注"
+      },
+      addTag:{
+          open:false,
+          title:"打标签"
+      },
+      tagIds:[],
+      statusArr:[],
+      ctsTypeArr:[],
+      sourceArr:[],
+      tagsOptions:[],
+      createTimeRange:[],
+      customer:{
+          open:false,
+          title:"新增客户"
+      },
+      users:[],
+      visit:{
+          open:false,
+          title:"写跟进"
+      },
+      source:{
+          open:false,
+          title:"修改客户来源"
+      },
+      assign:{
+        title:"分配客户",
+        open:false,
+      },
+      assist:{
+        title:"添加协作人",
+        open:false,
+      },
+      assignForm: {
+      },
+      // 表单校验
+      assignRules: {
+        // companyUserId: [
+        //   { required: true, message: "员工不能为空", trigger: "blur" }
+        // ],
+      },
+      dateRange:[],
+      addSms:{
+          open:false,
+          title:"批量发短信"
+      },
+      cityIds:[],
+      citys:[],
+      tags:[],
+      inputVisible: false,
+      inputValue: '',
+      statusOptions:[],
+      typeOptions:[],
+      sourceOptions:[],
+      sexOptions:[],
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 客户表格数据
+      customerList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        customerCode: null,
+        customerName: null,
+        mobile: null,
+        sex: null,
+        weixin: null,
+        userId: null,
+        createUserId: null,
+        receiveUserId: null,
+        customerUserId: null,
+        address: null,
+        location: null,
+        detailAddress: null,
+        lng: null,
+        lat: null,
+        status: null,
+        deptId: null,
+        isDel: null,
+        customerType: null,
+        receiveTime: null,
+        poolTime: null,
+        companyId: null,
+        isLine: null,
+        source: null,
+        tags: null,
+        customerLevel: null,
+      },
+      // 表单参数
+      form: {
+        province:null,
+        city:null,
+        district:null,
+      },
+      // 表单校验
+      rules: {
+        customerName: [
+          { required: true, message: "客户名称不能为空", trigger: "blur" }
+        ],
+        mobile: [
+          { required: true, message: "手机号不能为空", trigger: "blur" }
+        ],
+        sex: [
+          { required: true, message: "性别不能为空", trigger: "blur" }
+        ],
+        source: [
+          { required: true, message: "客户来源不能为空", trigger: "blur" }
+        ],
+      },
+      loading:null,
+      customerLevelOptions: []
+    };
+  },
+  created() {
+    this.getDicts("crm_customer_source").then((response) => {
+      this.sourceOptions = response.data;
+    });
+    this.getDicts("common_sex").then((response) => {
+      this.sexOptions = response.data;
+    });
+    this.getDicts("crm_customer_user_status").then((response) => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("crm_customer_type").then((response) => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("crm_customer_tag").then((response) => {
+        this.tagsOptions = response.data;
+    });
+    this.getCitys();
+    this.getList();
+    this.getCustomerLevelOptions()
+  },
+  methods: {
+    getCustomerLevelOptions(){
+      customerLevelOptions().then((response) => {
+        this.customerLevelOptions = response.data;
+      });
+    },
+    handleCommand(command){
+      if (command==="1"){
+        this.addOfflineOrder.open = true
+      }else {
+        this.addPackageOpen=true;
+      }
+    },
+    closeOrderOffline(){
+      this.addOfflineOrder.open = false
+    },
+    addPackageOrder(row){
+        this.customerId = row.customerId;
+       this.addPackageOpen=true;
+    },
+    closePackage(){
+      this.addPackageOpen=false;
+    },
+    closeVisitStatus(){
+        this.addVisitStatus.open=false;
+        this.getList();
+    },
+    handleVisitStatus(row){
+        this.addVisitStatus.open=true;
+        var that=this;
+        setTimeout(() => {
+            that.$refs.visitStatus.reset(row);
+        }, 500);
+
+    },
+    closeCustomerType(){
+        this.addCustomerType.open=false;
+        this.getList();
+    },
+    handleCustomerType(row){
+        this.addCustomerType.open=true;
+        var that=this;
+        setTimeout(() => {
+            that.$refs.customerType.reset(row);
+        }, 500);
+
+    },
+    closeRemark(){
+        this.addRemark.open=false;
+        this.getList();
+    },
+    handleAddRemark(row){
+        this.addRemark.open=true;
+        var that=this;
+        setTimeout(() => {
+            that.$refs.remark.reset(row);
+        }, 500);
+
+    },
+    closeTag(){
+        this.addTag.open=false;
+        this.getList();
+    },
+    handleAddTag(row){
+        this.addTag.open=true;
+        var that=this;
+        setTimeout(() => {
+            that.$refs.tag.reset(row);
+        }, 500);
+
+    },
+    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);
+    },
+    handleAdd() {
+      this.customer.open = true;
+      var that=this;
+      setTimeout(() => {
+        that.$refs.customer.handleAdd(2);
+      }, 200);
+    },
+    closeCustomer(){
+        this.customer.open=false;
+        this.getList();
+    },
+    closeVisit(){
+        this.visit.open=false;
+        this.getList();
+    },
+    handleAddVisit(row){
+        this.visit.open=true;
+        setTimeout(() => {
+            this.$refs.addVisit.reset(row.customerId);
+        }, 200);
+    },
+    handleAssist(){
+      var that=this;
+      var ids=this.ids;
+      that.assist.open=true;
+      setTimeout(() => {
+          that.$refs.assistUser.init(ids);
+      }, 200);
+    },
+    handleRemoveAllAssist(){
+      const ids = this.ids;
+      const data = {customerIds:ids,companyUserId:null}
+      this.$confirm('是否确认删除协作人?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return  remove(data);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    handleRemoveAssist(row,userName){
+      const match = userName.match(/\((\d+)\)/);
+      const companyUserId = match[1];
+      const data = {customerIds:[row.customerId],companyUserId:companyUserId}
+      this.$confirm('是否确认删除"' + userName + '"协作?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return  remove(data);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    handleAssign(){
+      var that=this;
+      var ids=this.ids;
+      that.assign.open=true;
+      setTimeout(() => {
+          that.$refs.assignUser.init(ids,3);
+      }, 200);
+    },
+    closeAssign(){
+      this.assign.open=false;
+      this.getList();
+    },
+    closeAssist(){
+      this.assist.open=false;
+      this.getList();
+    },
+    handleEditScource(){
+      this.source.open=true;
+      var that=this;
+      setTimeout(() => {
+        that.$refs.editSource.handleEdit(that.ids);
+      }, 200);
+
+    },
+    closeSource(){
+        this.source.open=false;
+        this.getList();
+    },
+    closeSms(){
+        this.addSms.open=false;
+    },
+    handleSendBatchSms(){
+      const customerIds =  this.ids;
+      this.addSms.open=true;
+      var that=this;
+      setTimeout(() => {
+          console.log(customerIds)
+          that.$refs.sms.reset(customerIds);
+      }, 500);
+
+    },
+    handleRecover(row) {
+      this.$confirm('是否确认回收客户"' + row.customerName + '"?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          var data={customerUserId:row.customerUserId}
+          return recover(data);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("操作成功");
+        }).catch(function() {});
+    },
+    handleCityChange(value) {
+      console.log(value);
+      var nodes=this.$refs.citySelect.getCheckedNodes();
+      this.form.address=nodes[0].pathLabels[0]+"-"+nodes[0].pathLabels[1]+"-"+nodes[0].pathLabels[2];
+      this.form.cityIds=value.toString();
+    },
+    getCitys(){
+        getCitys().then(res => {
+          this.loading = false;
+          this.citys=res.data;
+        })
+    },
+
+    /** 查询客户列表 */
+    getList() {
+      this.loading = true;
+      if(this.createTimeRange!=null&&this.createTimeRange.length==2){
+        this.queryParams.createTimeRange=this.createTimeRange[0]+"--"+this.createTimeRange[1]
+      }
+      else{
+        this.queryParams.createTimeRange=null;
+      }
+      if(this.statusArr.length>0){
+        this.queryParams.status=this.statusArr.toString();
+      }
+      else{
+        this.queryParams.status=null
+      }
+
+      if(this.ctsTypeArr.length>0){
+        this.queryParams.customerType=this.ctsTypeArr.toString();
+      }
+      else{
+        this.queryParams.customerType=null
+      }
+
+      if(this.sourceArr.length>0){
+        this.queryParams.source=this.sourceArr.toString();
+      }
+      else{
+        this.queryParams.source=null
+      }
+
+      if(this.tagIds.length>0){
+        this.queryParams.tags=this.tagIds.toString();
+      }
+      else{
+        this.queryParams.tags=null
+      }
+      getMyAssistList(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+        this.customerList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.customerId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+
+
+
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const customerIds = row.customerId || this.ids;
+      this.$confirm('是否确认删除客户编号为"' + customerIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delLineCustomer(customerIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有客户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportCustomer(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    },
+  }
+};
+</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>

+ 36 - 1
src/views/member/mylist.vue

@@ -137,6 +137,17 @@
       <!--          v-hasPermi="['user:fsUser:export']"-->
       <!--        >导出</el-button>-->
       <!--      </el-col>-->
+            <el-col :span="1.5">
+              <el-button
+              type="success"
+              plain
+              icon="el-icon-edit"
+              size="mini"
+              :disabled="multiple"
+              @click="batchSend"
+              v-hasPermi="['course:userVideo:audit']"
+              >批量IM发送</el-button>
+            </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -296,6 +307,16 @@
       <userDetails  ref="userDetails" />
     </el-drawer>
 
+    <el-dialog
+      title="营期"
+      :visible.sync="dialogVisible"
+      width="80%"
+      :before-close="handleClose">
+      <userCoursePeriod :userIds="ids" :companyId="companyId" :companyUserId="companyUserId"/>
+    </el-dialog>
+
+   
+
   </div>
 </template>
 
@@ -304,11 +325,13 @@ import { listUser, getUser, addUser, updateUser, delUser, exportUser, auditUser
 import {transferUser} from "@/api/users/user";
 import {getUserList} from "@/api/company/companyUser";
 import userDetails from '@/views/store/components/userDetails.vue';
+import userCoursePeriod from '../../components/course/userCoursePeriod.vue'
 export default {
   name: "FsUser",
-  components: {userDetails},
+  components: {userDetails,userCoursePeriod},
   data() {
     return {
+      
       show:{
         title:"会员详情",
         open:false,
@@ -317,6 +340,7 @@ export default {
         targetUserId: [{required: true, message: '请选择转移至销售', trigger: 'change'}],
         content: [{required: true, message: '请选择转移至销售', trigger: 'change'}]
       },
+      dialogVisible:false,
       companyUserList: [],
       openTransferDialog: false,
       transferForm: {
@@ -327,6 +351,8 @@ export default {
       loading: true,
       // 选中数组
       ids: [],
+      companyUserId:null,
+      companyId:null,
       // 非单个禁用
       single: true,
       // 非多个禁用
@@ -559,6 +585,8 @@ export default {
       this.ids = selection.map(item => item.userId);
       this.single = selection.length !== 1;
       this.multiple = !selection.length;
+      this.companyId = selection[0].companyId;
+      this.companyUserId = selection[0].companyUserId;
     },
 
     /** 新增按钮操作 */
@@ -663,6 +691,13 @@ export default {
     getProjectLabel(projectId) {
       return this.projectOptions.find(item => parseInt(item.dictValue) === projectId)?.dictLabel;
     },
+
+    batchSend(){
+      this.dialogVisible = true;
+    },
+    handleClose(){
+      this.dialogVisible = false;
+    }
   }
 };
 </script>

+ 5 - 1
src/views/qw/externalContactTransfer/index.vue

@@ -306,6 +306,7 @@ export default {
       isQwUserISNull:false,
       qwUserNameList:[],
       qwUserName:null,
+      type:'0',
       qwUserNameParam:{
         qwUserName:null
       },
@@ -476,6 +477,7 @@ export default {
 
     handleTransfer(row) {
       this.reset();
+      this.type="0";
       if(this.ids==null||this.ids==""){
         return  this.$message('请选择需要分配的客户');
       }
@@ -491,6 +493,7 @@ export default {
      handleTransferAll(row) {
       this.reset();
       this.qwUserName=this.queryParams.qwUserName;
+      this.type="1";
       setTimeout(() => {
                     this.$refs.qwUserSelectOne.getDetails(this.queryParams.corpId);
        }, 1);
@@ -507,9 +510,10 @@ export default {
             var form={
               ids:this.ids,
               qwUserName:this.qwUserName,
+              type:this.type,
               userId:this.form.userId,
               corpId:this.queryParams.corpId,
-			  content:this.form.content,
+              content:this.form.content,
             }
             transfer(form).then(response => {
               this.msgSuccess(response.msg);

+ 6 - 2
src/views/qw/externalContactUnassigned/index.vue

@@ -272,6 +272,7 @@ export default {
       qwUserList:[],
       isQwUserISNull:false,
       qwUserName:null,
+      type:'0',
        qwUserNameList:[],
       qwUserNameParam:{
         qwUserName:null
@@ -440,6 +441,7 @@ export default {
 
     handleTransfer(row) {
       this.reset();
+      this.type = '0'
       if(this.ids==null||this.ids==""){
         return  this.$message('请选择需要分配的客户');
       }
@@ -451,10 +453,11 @@ export default {
 
     },
 
-    
+
      handleTransferAll(row) {
       this.reset();
      this.qwUserName=this.queryParams.qwUserName;
+       this.type="1";
       setTimeout(() => {
                     this.$refs.qwUserSelectOne.getDetails(this.queryParams.corpId);
        }, 1);
@@ -468,7 +471,8 @@ export default {
       this.$refs["form"].validate(valid => {
         if (valid) {
             var form={
-              qwUserName:this.qwUserName, 
+              qwUserName:this.qwUserName,
+              type:this.type,
               ids:this.ids,
               userId:this.form.userId,
               corpId:this.queryParams.corpId,

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

@@ -12,11 +12,11 @@
           </el-select>
       </el-form-item>
       <el-form-item label="使用的成员" >
-        <el-select v-model="queryParams.qwUserIds" filterable  clearable placeholder="公司员工"   size="small">
+        <el-select filterable v-model="queryParams.qwUserIds" filterable  clearable placeholder="公司员工"   size="small">
           <el-option
              v-for="dict in companyUserList"
              :key="dict.id"
-             :label="dict.qwUserName"
+             :label="dict.qwUserName+'('+dict.qwUserId+')'"
              :value="dict.id">
           </el-option>
         </el-select>

+ 4 - 4
src/views/qw/sop/addSop.vue

@@ -29,10 +29,10 @@
               :label="1"
             >标签
             </el-radio>
-            <el-radio
-              :label="2"
-            >群聊
-            </el-radio>
+<!--            <el-radio-->
+<!--              :label="2"-->
+<!--            >群聊-->
+<!--            </el-radio>-->
           </el-radio-group>
           <Tip :title="'标签:根据企微客户的标签筛选客户进入SOP\r\n群聊:选择企微用户所属的群聊,并且只能选择课程模板,课程模板里面第一条规则是发送到群聊,其他规则催课会发送到群里面的个人'" />
         </el-form-item>

+ 1 - 0
src/views/qw/sopTemp/addSopTemp.vue

@@ -585,6 +585,7 @@ export default {
       setList.desc = val.desc;
       setList.url = val.url;
       setList.extras = val.extras;
+      setList.videoId = val.id;
 
       this.videoNumOptions.open=false;
     },

+ 1 - 0
src/views/qw/sopTemp/updateSopTemp.vue

@@ -1341,6 +1341,7 @@ export default {
       setList.desc = val.desc;
       setList.url = val.url;
       setList.extras = val.extras;
+      setList.videoId = val.id;
 
       this.videoNumOptions.open = false;
 

+ 1 - 0
src/views/qw/sopTemp/updateSopTemp2.vue

@@ -509,6 +509,7 @@ export default {
       setList.desc = val.desc;
       setList.url = val.url;
       setList.extras = val.extras;
+      setList.videoId = val.id;
 
       this.videoNumOptions.open=false;
     },

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

@@ -95,6 +95,15 @@
       </el-table-column>
       <el-table-column label="绑定的AI客服" align="center" prop="fastGptRoleName" />
       <el-table-column label="授权码" align="center" prop="appKey" />
+      <el-table-column label="发送方式" align="center" prop="sendMsgType">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.sendMsgType == 0">方式一</el-tag>
+          <el-tag v-if="scope.row.sendMsgType == 1" type="success">方式二</el-tag>
+          <el-tag v-if="scope.row.sendMsgType == 2" type="warning">掉线通知</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="vid" align="center" prop="vid" />
+      <el-table-column label="serverId" align="center" prop="serverId" />
      <el-table-column label="ai状态" align="center" prop="loginStatus">
         <template slot-scope="scope">
           <el-tag v-if="scope.row.ipadStatus == 1" type="success">在线</el-tag>

+ 21 - 0
src/views/qw/user/index.vue

@@ -111,6 +111,7 @@
         <template slot-scope="scope">
           <el-tag v-if="scope.row.sendMsgType == 0">方式一</el-tag>
           <el-tag v-if="scope.row.sendMsgType == 1" type="success">方式二</el-tag>
+          <el-tag v-if="scope.row.sendMsgType == 2" type="warning">掉线通知</el-tag>
         </template>
       </el-table-column>
       <el-table-column label="UUID" align="center" prop="uid" />
@@ -287,6 +288,15 @@
           >
             解除主机
           </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            :icon="scope.row.videoGetStatus == 0 ? 'el-icon-circle-check' : 'el-icon-remove-outline'"
+            plain
+            @click="changeVideoStatus(scope.row)"
+          >
+            {{ scope.row.videoGetStatus == 0 ? "开启" : "禁用" }}视频号接收
+          </el-button>
         </template>
       </el-table-column>
       <el-table-column label="AI客服" align="center" class-name="small-padding fixed-width" width="100px" fixed="right">
@@ -508,6 +518,10 @@
               :label="1"
             >方式二
             </el-radio>
+            <el-radio
+              :label="2"
+            >掉线通知
+            </el-radio>
           </el-radio-group>
         </el-form-item>
       </el-form>
@@ -535,6 +549,7 @@ import {
   delQwIpad,
   qrCodeVerify,
   outLoginQwIpad,
+  changeVideoStatus,
   handleAllocateRemoteHost,
   qwBindCloudHost, qwUnbindCloudHost, handleAuthAppKey, handleInputAuthAppKey, selectCloudAP, staffListUser
 } from '../../../api/qw/user'
@@ -714,6 +729,12 @@ export default {
       this.reset();
       this.getList();
     },
+    changeVideoStatus(val){
+      changeVideoStatus(val.id).then(res => {
+        this.$message.success("修改状态成功");
+        this.getList()
+      })
+    },
 
     //绑定AI客服
     bindFastGptRole(row) {

+ 735 - 0
src/views/store/components/addOrder.vue

@@ -0,0 +1,735 @@
+<template>
+  <div class="app-container">
+
+
+        <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+           <el-form-item label="会员信息" prop="userId">
+                <el-row  >
+                  <el-col >
+                      <el-input placeholder="请输入会员手机号" style="width:240px;cursor:pointer" v-model="phone">
+                      </el-input>
+                      <el-button plain style="margin-left:10px;"    @click="searchUser()">查询</el-button>
+                      <el-button plain style="margin-left:10px;" icon="el-icon-plus"  type="primary" @click="handleAddUser()">添加会员</el-button>
+                  </el-col>
+                </el-row>
+                <el-table border style="margin-top:5px;"  v-loading="userloading" :data="users">
+                  <el-table-column label="ID" align="center" prop="userId" />
+                  <el-table-column label="会员头像" align="center" width="80">
+                    <template slot-scope="scope">
+                      <el-popover
+                        placement="right"
+                        title=""
+                        trigger="hover"
+                      >
+                        <img slot="reference" :src="scope.row.avatar" width="50" >
+                        <img :src="scope.row.avatar" style="max-width: 120px;">
+                      </el-popover>
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="昵称" align="center" prop="nickname" />
+                  <el-table-column label="手机号" align="center" prop="phone" />
+                  <el-table-column label="状态" align="center" prop="status" >
+                      <template slot-scope="scope">
+                          <el-tag prop="status" v-for="(item, index) in userStatusOptions"    v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
+                      </template>
+                  </el-table-column>
+                </el-table>
+            </el-form-item>
+            <el-form-item label="收货信息" prop="addressId">
+              <el-row  >
+                <el-col >
+                      <el-button plain  type="primary" icon="el-icon-plus"  @click="handleAddUserAddress()">添加收货地址</el-button>
+                </el-col>
+              </el-row>
+              <el-radio-group v-model="form.addressId" style="width:100%">
+              <el-table border  style="margin-top:5px;"  v-loading="addressloading" :data="address">
+                <el-table-column label="ID" align="center"  >
+                    <template slot-scope="scope">
+                       <el-radio :label="scope.row.id"></el-radio>
+                    </template>
+                </el-table-column>
+                <el-table-column label="收货人姓名" align="center" prop="realName" />
+                <el-table-column label="收货人电话" align="center" prop="phone" />
+                <el-table-column label="地址" align="center" prop="detail" >
+                    <template slot-scope="scope">
+                       {{scope.row.province}} {{scope.row.city}} {{scope.row.district}} {{scope.row.detail}}
+                    </template>
+                </el-table-column>
+              </el-table>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="商品列表" >
+              <el-row  >
+                <el-col >
+                      <el-button plain  type="primary" icon="el-icon-plus" @click="handleAddProduct">添加商品</el-button>
+                </el-col>
+              </el-row>
+              <el-table border :key = "tablekey" width="100%" style="margin-top:5px;"  :data="products">
+                <el-table-column label="商品编号" align="center" prop="barCode" />
+                <el-table-column label="商品图片" align="center" width="100">
+                  <template slot-scope="scope">
+                    <el-popover
+                      placement="right"
+                      title=""
+                      trigger="hover"
+                    >
+                      <img slot="reference" :src="scope.row.image" width="50">
+                      <img :src="scope.row.image" style="max-width: 50px;">
+                    </el-popover>
+                  </template>
+                </el-table-column>
+                <el-table-column label="商品名称" show-overflow-tooltip align="center" prop="productName" />
+                <el-table-column label="商品规格" align="center" prop="sku" />
+                <el-table-column label="库存" align="center" prop="stock" />
+                <el-table-column label="单价" align="center" prop="price" />
+                <el-table-column label="数量" align="center"  prop="count" width="200px" :key="tablekey">
+                   <template slot-scope="scope">
+                    <div>
+                        <el-input-number v-model="scope.row.count"  @change="handleProductCountChange(scope.row)"  size="mini" :min="1" :max="scope.row.stock"  ></el-input-number>
+                    </div>
+                  </template>
+                </el-table-column>
+                <el-table-column label="小计" align="center" prop="money"   />
+                <el-table-column label="操作" align="center" width="100px" >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="mini"
+                      type="text"
+                      icon="el-icon-delete"
+                      @click="handleDelete(scope.row)"
+                    >删除</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+              <el-row>
+                <el-col>
+                      <span>商品合计:{{products.length}}</span><span style="margin-left:10px;">商品总价:{{totalMoney.toFixed(2)}}</span>
+                </el-col>
+              </el-row>
+            </el-form-item>
+            <el-form-item label="订单类型" prop="orderType">
+              <el-select   v-model="form.orderType" placeholder="请选择订单类型" clearable size="small" >
+              <el-option
+                      v-for="item in orderTypeOptions"
+                      :key="item.dictValue"
+                      :label="item.dictLabel"
+                      :value="item.dictValue"
+                    />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="媒体来源" prop="orderMedium" v-if="orderMediumOptions.length>0">
+              <el-select   v-model="form.orderMedium" placeholder="请选择媒体来源" clearable size="small" >
+              <el-option
+                      v-for="item in orderMediumOptions"
+                      :key="item.dictValue"
+                      :label="item.dictLabel"
+                      :value="item.dictValue"
+                    />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="支付方式" prop="payType">
+              <el-select   v-model="form.payType" placeholder="请选择支付方式" clearable size="small" >
+              <el-option
+                      v-for="item in payTypeOptions"
+                      :key="item.dictValue"
+                      :label="item.dictLabel"
+                      :value="item.dictValue"
+                    />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="改价" prop="payPrice">
+              <el-input-number  v-model="form.payPrice" placeholder="修改商品总价" size="medium" :precision="2" :min="0.01" :step="0.1" />
+            </el-form-item>
+            <el-form-item label="物流代收" prop="amount" v-if="form.payType == '3'">
+              <el-input-number  v-model="form.amount" placeholder="平台支付价格" size="medium" :precision="2" :min="0.01" :step="0.1" />
+            </el-form-item>
+            <el-form-item label="订单备注" prop="mark">
+              <el-input  type="textarea" rows="2" v-model="form.mark" placeholder="" />
+            </el-form-item>
+        </el-form>
+      <div slot="footer" class="dialog-footer" style="float: right; margin-bottom: 20px;">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    <el-dialog :title="product.title" v-if="product.open"  :visible.sync="product.open" width="1000px" append-to-body>
+        <product-select  @selectProduct="selectProduct" />
+    </el-dialog>
+    <el-dialog :title="user.title" v-if="user.open"  :visible.sync="user.open" width="500px" append-to-body>
+        <add-user @addUser="addUser" />
+    </el-dialog>
+    <el-dialog :title="userAddress.title" v-if="userAddress.open"  :visible.sync="userAddress.open" width="800px" append-to-body>
+        <add-user-address ref="addUserAddress"   @addUserAddress="addUserAddress" />
+    </el-dialog>
+    <el-dialog :title="payQr.title" v-if="payQr.open"  :visible.sync="payQr.open" width="240px" append-to-body>
+        <div style="padding-bottom:15px;" >
+            <div  class="qrcode" ref="qrCodeUrl"></div>
+        </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import {exportStoreOrderItems, createUserOrder,listStoreOrder, getStoreOrder, delStoreOrder, addStoreOrder, updateStoreOrder, exportStoreOrder } from "@/api/store/storeOrder";
+import { getUserList } from "@/api/users/user";
+import { getAddressList } from "@/api/users/userAddress";
+import { getTcmScheduleList } from "@/api/company/tcmScheduleReport";
+import productOrder from "@/views/store/components/productOrder";
+import productSelect from "@/views/store/components/productSelect";
+import addUser from "@/views/store/components/addUser";
+import addUserAddress from "@/views/store/components/addUserAddress";
+import config from "@/utils/config";
+import QRCode from 'qrcodejs2'
+import { treeselect } from "@/api/company/companyDept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+export default {
+  components: { Treeselect,productOrder,productSelect,addUser,addUserAddress },
+  name: "StoreOrder",
+  props: {
+    customerId: {
+      type: Number, // 或 Number,根据实际情况选择
+      required: false
+    },
+    userId: {
+      type: Number, // 或 Number,根据实际情况选择
+      required: false
+    }
+  },
+  data() {
+    return {
+      // 部门树选项
+      deptOptions: undefined,
+      // 部门名称
+      deptName: undefined,
+      defaultProps: {
+        children: "children",
+        label: "label",
+      },
+      deliveryPayStatusOptions:[],
+      deliveryStatusOptions:[],
+      dateRange: [],
+      orderTypeOptions:[],
+      orderMediumOptions:[],
+      payTypeOptions:[],
+      payQr:{
+        open:false,
+        title:"付款二维码"
+      },
+      user:{
+        open:false,
+        title:"创建会员"
+      },
+      userAddress:{
+        open:false,
+        title:"创建收货地址"
+      },
+      tablekey:false,
+      totalMoney:0.00,
+      products:[],
+      product:{
+        open:false,
+        title:"商品选择"
+      },
+      phone:null,
+      address:[],
+      addressloading: false,
+      userloading: false,
+      users:[],
+      userStatusOptions:[],
+      show:{
+        open:false,
+        title:"订单详情"
+      },
+      activeName:"00",
+      statusOptions:[],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 订单表格数据
+      storeOrderList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      createTimeRange:[],
+      payTimeRange:[],
+      deliveryImportTimeRange:[],
+      scheduleOptions:[],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        orderCode: null,
+        extendOrderId: null,
+        userId: null,
+        realName: null,
+        userPhone: null,
+        userAddress: null,
+        cartId: null,
+        freightPrice: null,
+        totalNum: null,
+        totalPrice: null,
+        totalPostage: null,
+        payPrice: null,
+        payPostage: null,
+        deductionPrice: null,
+        couponId: null,
+        couponPrice: null,
+        paid: null,
+        payTime: null,
+        payType: null,
+        status: null,
+        refundStatus: null,
+        refundReasonWapImg: null,
+        refundReasonWapExplain: null,
+        refundReasonTime: null,
+        refundReasonWap: null,
+        refundReason: null,
+        refundPrice: null,
+        deliverySn: null,
+        deliveryName: null,
+        deliveryType: null,
+        deliveryId: null,
+        gainIntegral: null,
+        useIntegral: null,
+        payIntegral: null,
+        backIntegral: null,
+        mark: null,
+        isDel: null,
+        cost: null,
+        verifyCode: null,
+        storeId: null,
+        shippingType: null,
+        isChannel: null,
+        isRemind: null,
+        isSysDel: null
+      },
+      // 表单参数
+      form: {
+        addressId:null,
+        userId:null,
+        products:[],
+      },
+      // 表单校验
+      rules: {
+        userId: [
+          { required: true, message: "会员信息不能为空", trigger: "submit" }
+        ],
+        addressId: [
+          { required: true, message: "收货信息不能为空", trigger: "submit" }
+        ],
+        products: [
+          { required: true, message: "商品不能为空", trigger: "submit" }
+        ],
+
+      }
+    };
+  },
+  watch: {
+    // 根据名称筛选部门树
+    deptName(val) {
+        this.$refs.tree.filter(val);
+    },
+  },
+  created() {
+    this.getTreeselect();
+    // 媒体来源 如需要则增加字典 
+    this.getDicts("store_order_medium").then((response) => {
+      this.orderMediumOptions = response.data;
+    });
+    this.getDicts("store_order_type").then((response) => {
+      this.orderTypeOptions = response.data;
+    });
+    this.getDicts("store_pay_type").then((response) => {
+      this.payTypeOptions = response.data;
+    });
+    this.getDicts("user_status").then((response) => {
+      this.userStatusOptions = response.data;
+    });
+    this.getDicts("store_order_status").then((response) => {
+      this.statusOptions = response.data;
+      console.log(response.data)
+    });
+    this.getDicts("store_order_delivery_status").then((response) => {
+      this.deliveryStatusOptions = response.data;
+    });
+    this.getDicts("store_delivery_pay_status").then((response) => {
+      this.deliveryPayStatusOptions = response.data;
+    });
+    getTcmScheduleList().then(response => {
+      this.scheduleOptions = response.data;
+    });
+    this.initUser();
+  },
+  methods: {
+    initUser(){
+      console.log("--------------",this.userId)
+      if(this.userId != null){
+        var data={userId:this.userId}
+        this.userloading = true;
+        this.users=[];
+        this.address=[];
+        getUserList(data).then(response => {
+          this.users = response.data;
+          this.userloading = false;
+          if(this.users!=null&&this.users.length==1){
+            this.form.userId=this.users[0].userId;
+            this.getAddressList(this.form.userId)
+          }
+        });
+      }
+    },
+     /** 查询部门下拉树结构 */
+     getTreeselect() {
+      treeselect().then((response) => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 筛选节点
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.label.indexOf(value) !== -1;
+    },
+    // 节点单击事件
+    handleNodeClick(data) {
+      this.queryParams.deptId = data.id;
+      this.getList();
+    },
+    handleGenPayUrl(row){
+      this.payQr.open=true;
+      setTimeout(() => {
+        var qrcode = new QRCode(this.$refs.qrCodeUrl, {
+            text: config.payQRUrl+row.id, // 需要转换为二维码的内容
+            width: 200,
+            height: 200,
+            colorDark: '#000000',
+            colorLight: '#ffffff',
+            correctLevel: QRCode.CorrectLevel.H
+        })
+      }, 200);
+
+
+    },
+    handleAddUser(){
+      this.user.open=true;
+    },
+    handleAddUserAddress(){
+      if(this.form.userId==null){
+        this.msgError("请选择会员");
+        return;
+      }
+      this.userAddress.open=true;
+      setTimeout(() => {
+        this.$refs.addUserAddress.init(this.form.userId);
+      }, 500);
+    },
+    addUserAddress(){
+      this.userAddress.open=false;
+      //获取地址
+      this.getAddressList(this.form.userId);
+    },
+    addUser(){
+      this.user.open=false;
+    },
+
+    compute(){
+      this.totalMoney=0;
+      var that=this;
+      this.products.forEach (function (value) {
+          that.totalMoney += value.money;
+      });
+      console.log(that.totalMoney)
+    },
+    handleProductCountChange(row){
+      this.tablekey = !this.tablekey
+      console.log(row)
+      row.money=row.count*row.price;
+      this.$forceUpdate();
+      this.compute();
+    },
+    selectProduct(row){
+      console.log(row);
+      for(var i=0;i<this.products.length;i++){
+        if(this.products[i].id==row.id){
+          return;
+        }
+      }
+      row.count=1;
+      row.money=row.count*row.price;
+      this.products.push(row);
+      this.$message.success("商品"+ row.productName + "添加成功")
+      this.compute();
+    },
+    handleAddProduct(){
+      this.product.open=true;
+    },
+    searchUser(){
+      if(this.phone==null||this.phone==""){
+        return;
+      }
+      var data={phone:this.phone}
+      this.userloading = true;
+      this.users=[];
+      this.address=[];
+      getUserList(data).then(response => {
+        this.users = response.data;
+        this.userloading = false;
+        if(this.users!=null&&this.users.length==1){
+          this.form.userId=this.users[0].userId;
+          this.getAddressList(this.form.userId)
+        }
+      });
+    },
+    getAddressList(userId){
+      var data={userId:userId}
+      this.addressloading = true;
+      this.address=[];
+      getAddressList(data).then(response => {
+        this.address = response.data;
+        this.addressloading = false;
+      });
+    },
+    handleDetails(row){
+      this.show.open=true;
+      const orderId = row.id ;
+      setTimeout(() => {
+        this.$refs.order.getOrder(orderId);
+      }, 500);
+    },
+    handleClick(tab, event) {
+       if(tab.name=="all"){
+        this.queryParams.status==null;
+      }
+      else{
+         this.queryParams.status=tab.name;
+      }
+      this.getList();
+    },
+    /** 查询订单列表 */
+    getList() {
+      if(this.queryParams.status=='00'){
+        this.queryParams.status=null;
+      }
+      if(this.createTimeRange!=null&&this.createTimeRange.length==2){
+        this.queryParams.createTimeRange=this.createTimeRange[0]+"--"+this.createTimeRange[1]
+      }
+      else{
+        this.queryParams.createTimeRange=null;
+      }
+      if(this.payTimeRange!=null&&this.payTimeRange.length==2){
+        this.queryParams.payTimeRange=this.payTimeRange[0]+"--"+this.payTimeRange[1]
+      }
+      else{
+        this.queryParams.payTimeRange=null;
+      }
+      if(this.deliveryImportTimeRange!=null&&this.deliveryImportTimeRange.length==2){
+        this.queryParams.deliveryImportTimeRange=this.deliveryImportTimeRange[0]+"--"+this.deliveryImportTimeRange[1]
+      }
+      else{
+        this.queryParams.deliveryImportTimeRange=null;
+      }
+      this.loading = true;
+      listStoreOrder(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+        this.storeOrderList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+      this.$emit("closePackage")
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        addressId:null,
+        userId:null,
+        products: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
+      getStoreOrder(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改订单";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if(this.products.length==0){
+          this.msgError("请选择商品");
+          return;
+        }
+        this.form.products=this.products;
+        if (valid) {
+          console.log(this.form);
+          this.form.customerId = this.customerId;
+          createUserOrder(this.form).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("创建成功");
+
+              this.$emit("closePackage")
+            }
+          });
+
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+       this.products.splice(this.products.findIndex(item => item.id === row.id), 1)
+       this.compute();
+
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+
+      if(this.queryParams.status=='00'){
+        this.queryParams.status=null;
+      }
+      if(this.createTimeRange!=null&&this.createTimeRange.length==2){
+        this.queryParams.createTimeRange=this.createTimeRange[0]+"--"+this.createTimeRange[1]
+      }
+      else{
+        this.queryParams.createTimeRange=null;
+      }
+      if(this.payTimeRange!=null&&this.payTimeRange.length==2){
+        this.queryParams.payTimeRange=this.payTimeRange[0]+"--"+this.payTimeRange[1]
+      }
+      else{
+        this.queryParams.payTimeRange=null;
+      }
+      if(this.deliveryImportTimeRange!=null&&this.deliveryImportTimeRange.length==2){
+        this.queryParams.deliveryImportTimeRange=this.deliveryImportTimeRange[0]+"--"+this.deliveryImportTimeRange[1]
+      }
+      else{
+        this.queryParams.deliveryImportTimeRange=null;
+      }
+
+      const queryParams = this.addDateRange(this.queryParams, this.dateRange);
+      this.$confirm('是否确认导出所有订单数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportStoreOrder(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    },
+    handleExportItems() {
+      if(this.queryParams.status=='00'){
+        this.queryParams.status=null;
+      }
+      if(this.createTimeRange!=null&&this.createTimeRange.length==2){
+        this.queryParams.createTimeRange=this.createTimeRange[0]+"--"+this.createTimeRange[1]
+      }
+      else{
+        this.queryParams.createTimeRange=null;
+      }
+      if(this.payTimeRange!=null&&this.payTimeRange.length==2){
+        this.queryParams.payTimeRange=this.payTimeRange[0]+"--"+this.payTimeRange[1]
+      }
+      else{
+        this.queryParams.payTimeRange=null;
+      }
+      if(this.deliveryImportTimeRange!=null&&this.deliveryImportTimeRange.length==2){
+        this.queryParams.deliveryImportTimeRange=this.deliveryImportTimeRange[0]+"--"+this.deliveryImportTimeRange[1]
+      }
+      else{
+        this.queryParams.deliveryImportTimeRange=null;
+      }
+      const queryParams = this.addDateRange(this.queryParams, this.dateRange);
+      this.$confirm('是否确认导出所有订单明细数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportStoreOrderItems(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+.items{
+  margin: 5px 0px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-start;
+  .pic{
+    width:60px;
+    height:60px;
+  }
+  .goods-content{
+    margin-left: 10px;
+    max-width: 200px;
+    text-align: left;
+    .goods-title{
+
+      overflow:hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      -o-text-overflow:ellipsis;
+    }
+  }
+}
+.el-message-box__message p{
+  max-height: 400px;
+  overflow:scroll;
+}
+.import-msg{
+  height: 500px;
+  overflow: auto;
+}
+</style>
+<style>
+  .el-descriptions-item__label.is-bordered-label{
+    font-weight: normal;
+  }
+
+</style>

+ 313 - 0
src/views/store/components/addOrderOffline.vue

@@ -0,0 +1,313 @@
+<template>
+  <div class="app-container">
+        <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+           <el-form-item label="客户信息" prop="crmId">
+                <el-row  >
+                  <el-col >
+                    <el-input placeholder="请输入客户手机号" clearable style="width:240px;cursor:pointer" v-model="phone">
+                    </el-input>
+                    <el-button plain style="margin-left:10px;"    @click="searchUser()">查询</el-button>
+                  </el-col>
+                </el-row>
+                <el-table border style="margin-top:5px;"  v-loading="userloading" :data="users">
+                  <el-table-column label="ID" align="center" prop="customerId" />
+                  <el-table-column label="客户编码" align="center" prop="customerCode" />
+                  <el-table-column label="客户名称" align="center" prop="customerName" />
+                  <el-table-column label="手机号" align="center" prop="mobile" />
+                  <el-table-column  label="客户来源" align="center" prop="source">
+                    <template slot-scope="scope">
+                      <el-tag prop="status" v-for="(item, index) in sourceOptions"    v-if="scope.row.source==item.dictValue">{{item.dictLabel}}</el-tag>
+                    </template>
+                  </el-table-column>
+                </el-table>
+            </el-form-item>
+            <el-form-item label="商品列表" >
+              <el-row  >
+                <el-col >
+                      <el-button plain  type="primary" icon="el-icon-plus" @click="handleAddProduct">添加商品</el-button>
+                </el-col>
+              </el-row>
+              <el-table border :key = "tablekey" width="100%" style="margin-top:5px;"  :data="products">
+                <el-table-column label="商品编号" align="center" prop="barCode" />
+                <el-table-column label="商品图片" align="center" width="100">
+                  <template slot-scope="scope">
+                    <el-popover
+                      placement="right"
+                      title=""
+                      trigger="hover"
+                    >
+                      <img slot="reference" :src="scope.row.image" width="50">
+                      <img :src="scope.row.image" style="max-width: 50px;">
+                    </el-popover>
+                  </template>
+                </el-table-column>
+                <el-table-column label="商品名称" show-overflow-tooltip align="center" prop="productName" />
+                <el-table-column label="商品规格" align="center" prop="sku" />
+                <el-table-column label="单价" align="center" prop="price" />
+                <el-table-column label="数量" align="center"  prop="count" width="200px" :key="tablekey">
+                   <template slot-scope="scope">
+                    <div>
+                        <el-input-number v-model="scope.row.count"  @change="handleProductCountChange(scope.row)"  size="mini" :min="1"   ></el-input-number>
+                    </div>
+                  </template>
+                </el-table-column>
+                <el-table-column label="小计" align="center" prop="money"   />
+                <el-table-column label="操作" align="center" width="100px" >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="mini"
+                      type="text"
+                      icon="el-icon-delete"
+                      @click="handleDelete(scope.row)"
+                    >删除</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+              <el-row>
+                <el-col>
+                      <span>商品合计:{{products.length}}</span><span style="margin-left:10px;">商品总价:{{totalMoney.toFixed(2)}}</span>
+                </el-col>
+              </el-row>
+            </el-form-item>
+            <el-form-item label="核实业务员" prop="uploadUserId">
+              <el-select style="width:220px" v-model="form.uploadUserId" placeholder="请选择" clearable size="small" >
+                <el-option
+                  v-for="item in salesmanList"
+                  :key="item.dictValue"
+                  :label="item.dictLabel"
+                  :value="item.dictValue"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="价格" prop="payPrice">
+              <el-input-number v-model="form.payPrice"  size="mini"    ></el-input-number>
+            </el-form-item>
+            <el-form-item label="订单备注" prop="remark">
+              <el-input  type="textarea" rows="2" v-model="form.remark" placeholder="" />
+            </el-form-item>
+        </el-form>
+      <div slot="footer" class="dialog-footer" style="float: right; margin-bottom: 20px;">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    <el-dialog :title="product.title" v-if="product.open"  :visible.sync="product.open" width="1000px" append-to-body>
+        <product-select  @selectProduct="selectProduct" />
+    </el-dialog>
+
+
+  </div>
+</template>
+
+<script>
+import { getMyCustomerList,recover,exportCustomer  } from "@/api/crm/customer";
+import {createOrder} from "@/api/store/storeOrderOffline";
+import { getSalesman } from "@/api/company/companyUser";
+
+
+import productSelect from "@/views/store/components/productSelect";
+
+export default {
+  components: { productSelect },
+  name: "AddOrderOffline",
+  data() {
+    return {
+      salesmanList:[],
+      tablekey:false,
+      totalMoney:0.00,
+      products:[],
+      product:{
+        open:false,
+        title:"商品选择"
+      },
+      phone:null,
+
+      userloading: false,
+      users:[],
+      sourceOptions:[],
+      userStatusOptions:[],
+      statusOptions:[],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 订单表格数据
+      storeOrderList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+
+
+      // 表单参数
+      form: {
+        crmId:null,
+        uploadUserId:null,
+        products:[],
+      },
+      // 表单校验
+      rules: {
+        crmId: [
+          { required: true, message: "客户信息不能为空", trigger: "submit" }
+        ],
+        uploadUserId: [
+          { required: true, message: "核实业务员不能为空", trigger: "blur" }
+        ],
+
+        products: [
+          { required: true, message: "商品不能为空", trigger: "submit" }
+        ],
+
+      }
+    };
+  },
+  created() {
+    this.getDicts("crm_customer_source").then((response) => {
+      this.sourceOptions = response.data;
+    });
+    getSalesman().then((response) => {
+      this.salesmanList = response.data;
+    });
+  },
+  methods: {
+    handleAddProduct(){
+      this.product.open=true;
+    },
+    compute(){
+      this.totalMoney=0;
+      var that=this;
+      this.products.forEach (function (value) {
+          that.totalMoney += value.money;
+      });
+      console.log(that.totalMoney)
+    },
+    handleProductCountChange(row){
+      this.tablekey = !this.tablekey
+      console.log(row)
+      row.money=row.count*row.price;
+      this.$forceUpdate();
+      this.compute();
+    },
+    selectProduct(row){
+      console.log(row);
+      for(var i=0;i<this.products.length;i++){
+        if(this.products[i].id===row.id){
+          this.$message.warning("商品已存在")
+          return;
+        }
+      }
+      row.count=1;
+      row.money=row.count*row.price;
+      this.products.push(row);
+      this.compute();
+      this.$message.success("商品添加成功")
+    },
+
+    searchUser(crmId){
+      if(this.phone==null||this.phone===""){
+        return;
+      }
+      var data={mobile:this.phone}
+      this.userloading = true;
+      this.users=[];
+      getMyCustomerList(data).then(response => {
+        this.users = response.rows;
+        this.userloading = false;
+        if(this.users!=null&&this.users.length===1){
+          this.form.crmId=this.users[0].customerId;
+        }
+      });
+    },
+
+    // 取消按钮
+    cancel() {
+      this.$emit("closeOrderOffline")
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+
+        userId:null,
+        products:null,
+
+      };
+      this.resetForm("form");
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if(this.products.length==0){
+          this.msgError("请选择商品");
+          return;
+        }
+        this.form.products=this.products;
+        if (valid) {
+          console.log(this.form);
+          createOrder(this.form).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("创建成功");
+              this.$emit("closeOrderOffline")
+            }
+          });
+
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+       this.products.splice(this.products.findIndex(item => item.id === row.id), 1)
+       this.compute();
+
+    },
+
+  }
+};
+</script>
+<style scoped lang="scss">
+.items{
+  margin: 5px 0px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-start;
+  .pic{
+    width:60px;
+    height:60px;
+  }
+  .goods-content{
+    margin-left: 10px;
+    max-width: 200px;
+    text-align: left;
+    .goods-title{
+
+      overflow:hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      -o-text-overflow:ellipsis;
+    }
+  }
+}
+.el-message-box__message p{
+  max-height: 400px;
+  overflow:scroll;
+}
+.import-msg{
+  height: 500px;
+  overflow: auto;
+}
+</style>
+<style>
+  .el-descriptions-item__label.is-bordered-label{
+    font-weight: normal;
+  }
+
+</style>

+ 152 - 0
src/views/store/components/couponDetails.vue

@@ -0,0 +1,152 @@
+<template>
+    <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>
+        <el-descriptions title="" :column="3" border>
+          <el-descriptions-item label="标题"><span v-if="item!=null">{{item.title}}</span></el-descriptions-item>
+          <el-descriptions-item label="面额"><span v-if="item!=null">{{item.price}}</span></el-descriptions-item>
+          <el-descriptions-item label="数量"><span v-if="item!=null">{{item.number}}</span></el-descriptions-item>
+           <el-descriptions-item label="卷类型"><span v-if="item!=null">{{item.couponType}}</span></el-descriptions-item>
+          <el-descriptions-item label="最低消费金额可用"><span v-if="item!=null">{{item.minPrice}}</span></el-descriptions-item>
+          <el-descriptions-item label="剩余数量"><span v-if="item!=null">{{item.remainNumber}}</span></el-descriptions-item>
+          <el-descriptions-item label="有效期"><span v-if="item!=null">{{item.limitTime}}</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"> <dict-tag :options="couponTypeOptions" :value="item.couponType"/></span></el-descriptions-item>
+        </el-descriptions>
+    </div>
+    <div class="contentx" v-if="item!=null">
+            <div class="desct"> 优惠劵领取信息</div>
+            <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
+              <el-tab-pane label="全部" name="10"></el-tab-pane>
+              <el-tab-pane v-for="(item,index) in couponStatusOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+            </el-tabs>
+            <el-table v-loading="loading" :data="userCouponList">
+              <el-table-column label="券号" align="center" prop="couponCode" />
+              <el-table-column label="会员昵称" align="center" prop="nickName" />
+             <!-- <el-table-column label="会员电话" align="center" prop="phone" /> -->
+              <el-table-column label="关联订单ID" align="center" prop="businessId" />
+              <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="status">
+                <template slot-scope="scope">
+                  <dict-tag :options="couponStatusOptions" :value="scope.row.status"/>
+                </template>
+              </el-table-column>
+              <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+              <el-table-column label="使用时间" align="center" prop="useTime" width="180"/>
+            </el-table>
+
+            <pagination
+              v-show="total>0"
+              :total="total"
+              :page.sync="queryParams.pageNum"
+              :limit.sync="queryParams.pageSize"
+              @pagination="getList"
+            />
+        </div>
+
+    </div>
+</template>
+
+<script>
+import { listCoupon, getCoupon, delCoupon, addCoupon, updateCoupon, exportCoupon } from "@/api/store/coupon";
+import { getListUserCoupon } from "@/api/store/userCoupon";
+  export default {
+    name: "coupon",
+    props:["data"],
+    data() {
+      return {
+        actName:"10",
+        couponId:null,
+        item:null,
+        statusOptions: [],
+        couponTypeOptions: [],
+        businessTypeOptions:[],
+        couponStatusOptions:[],
+        total: 0,
+        loading: true,
+        // 会员优惠券表格数据
+        userCouponList: [],
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          couponId: null,
+        },
+      }
+    },
+    created() {
+      this.getDicts("sys_coupon_type").then(response => {
+        this.couponTypeOptions = response.data;
+      });
+      this.getDicts("sys_coupon_business_type").then(response => {
+        this.businessTypeOptions = response.data;
+      });
+      this.getDicts("sys_company_status").then(response => {
+        this.statusOptions = response.data;
+      });
+      this.getDicts("sys_coupon_status").then(response => {
+        this.couponStatusOptions = response.data;
+      });
+    },
+    methods: {
+      getList() {
+        this.loading = true;
+        getListUserCoupon(this.queryParams).then(response => {
+          this.userCouponList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        });
+      },
+      handleClickX(tab, event) {
+       if(tab.name=="10"){
+         this.queryParams.status=null;
+       }else{
+         this.queryParams.status=tab.name;
+       }
+          this.queryParams.pageNum = 1;
+          this.couponId = this.queryParams.couponId;
+          this.getList();
+
+      },
+      getDetails(orderId) {
+        this.item=null;
+        this.couponId = orderId;
+        getCoupon(orderId).then(response => {
+            this.item = response.data;
+            this.queryParams.couponId = orderId;
+            this.getList();
+        });
+      },
+    }
+  }
+</script>
+<style>
+  .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;
+    }
+
+</style>

+ 117 - 28
src/views/store/components/storeOrderDetails.vue

@@ -319,8 +319,16 @@
         <el-form-item label="备注" prop="remark"  >
           <el-input v-model="editForm.remark" placeholder="请输入备注" />
         </el-form-item>
-        <el-form-item label="详情地址" prop="userAddress"  >
-          <el-input v-model="editForm.userAddress" placeholder="请输入" />
+        <el-form-item label="详情地址" prop="userAddress">
+          <el-cascader
+            ref="citySelect"
+            v-model="cityIds"
+            :options="citys"
+            :props="{ checkStrictly: true }"
+            @change="handleCityChange"
+            clearable
+          />
+          <el-input v-model="editForm.userAddress" placeholder="请输入详细地址(不含省/市/区)" />
         </el-form-item>
         <el-form-item label="收货人电话" prop="userPhone"  >
           <el-input v-model="editForm.userPhone" placeholder="请输入" />
@@ -409,6 +417,7 @@ import {getCustomerListBySearch } from "@/api/crm/customer";
 import { getTcmScheduleList } from "@/api/company/tcmScheduleReport";
 import addSms from '../../crm/components/addSms.vue';
 import msgDetails from '../../store/components/followMsgDetails.vue';
+import {getCitys} from "@/api/store/city";
   export default {
     name: "orderDe",
     props:["data"],
@@ -512,6 +521,8 @@ import msgDetails from '../../store/components/followMsgDetails.vue';
           qwSubject:null,
           remark:"",
           isFirst:null,
+          userAddress: "",
+          userPhone: ""
         },
         editDyRules:{
           deliverySn: [
@@ -538,7 +549,12 @@ import msgDetails from '../../store/components/followMsgDetails.vue';
           deliveryName:null,
           deliverySn:null,
           orderId:null,
-        }
+        },
+        cityIds:[],
+        citys:[],
+        userAddress:null,
+        originalAddress: null,
+        originalDetail: "",
       }
     },
     computed: {
@@ -619,6 +635,30 @@ import msgDetails from '../../store/components/followMsgDetails.vue';
 
     },
     methods: {
+      getCitys() {
+        return getCitys().then(res => {
+          this.citys = res.data || [];
+          return this.citys;
+        });
+      },
+      // 新增:切换省市区
+      handleCityChange(val) {
+        this.cityIds = Array.isArray(val) ? val : [];
+      },
+
+      getCityLabelsByIds() {
+        if (!this.cityIds || this.cityIds.length === 0) return [];
+        const [pVal, cVal, aVal] = this.cityIds;
+        const p = this.citys.find(p => p.value === pVal);
+        const c = p?.children?.find(c => c.value === cVal);
+        const a = c?.children?.find(a => a.value === aVal);
+        return [p?.label, c?.label, a?.label].filter(Boolean);
+      },
+      buildFullAddress() {
+        const region = this.getCityLabelsByIds().join(' ');
+        const detail = (this.editForm.userAddress || '').trim();
+        return region && detail ? `${region} ${detail}` : (region || detail || '');
+      },
       followMsg(row){
          const userId = this.item.userId;
          const followDoctorId =this.item.followDoctorId;
@@ -716,35 +756,84 @@ import msgDetails from '../../store/components/followMsgDetails.vue';
       });
     },
     //修改订单状态
-    submitEditForm(){
-        this.$refs["editForm"].validate(valid => {
-        if (valid) {
-          updateStoreOrder(this.editForm).then(response => {
-            if (response.code === 200) {
-              this.msgSuccess("操作成功");
-               this.edit.open = false;
-              getOrder(this.item.orderId).then(response => {
-                this.item=response.data
-                that.getlogList(this.item.orderId);
-                that.$parent.$parent.getList();
-              });
-            }
-          });
+    submitEditForm() {
+      this.$refs["editForm"].validate(valid => {
+        if (!valid) return;
+
+        // 判断是否修改了地址:选了更深层级 或 详细地址有改动
+        const regionChanged = Array.isArray(this.cityIds) && this.cityIds.length > 1;
+        const detailChanged = (this.editForm.userAddress || '').trim() !== (this.originalDetail || '');
+        const addressModified = regionChanged || detailChanged;
+
+        // 若修改了地址,要求省市区都选到(3级)
+        if (addressModified) {
+          if (!this.cityIds || this.cityIds.length < 3) {
+            this.msgError("请完整选择省/市/区");
+            return;
+          }
         }
+
+        const payload = {
+          ...this.editForm,
+          userAddress: addressModified ? this.buildFullAddress() : (this.originalAddress || this.item.userAddress || ''),
+        };
+
+        updateStoreOrder(payload).then(response => {
+          if (response.code === 200) {
+            this.msgSuccess("操作成功");
+            this.edit.open = false;
+            getOrder(this.item.orderId).then(response => {
+              this.item = response.data;
+              this.getlogList(this.item.orderId);
+              this.$parent.$parent.getList();
+            });
+          }
+        });
       });
     },
-    editOrder(){
-        this.edit.open=true;
-        this.editForm.orderId=this.item.orderId;
-        this.editForm.remark=this.item.remark;
-        this.editForm.userAddress = this.item.userAddress.toString();
-        this.editForm.userPhone = this.item.userPhone.toString();
-        if(this.item.orderBuyType!=null){
-          this.editForm.orderBuyType=this.item.orderBuyType.toString();
+    editOrder() {
+      this.edit.open = true;
+      this.editForm.orderId = this.item.orderId;
+      this.editForm.remark = this.item.remark;
+      this.editForm.userPhone = this.item.userPhone != null ? this.item.userPhone.toString() : "";
+      if (this.item.orderBuyType != null) {
+        this.editForm.orderBuyType = this.item.orderBuyType.toString();
+      }
+      this.editForm.orderChannel = this.item.orderChannel;
+      this.editForm.qwSubject = this.item.qwSubject;
+      this.editForm.scheduleId = this.item.scheduleId;
+
+      const currentAddress = (this.item.userAddress || "").toString().trim();
+      // 记录原始完整地址
+      this.originalAddress = currentAddress;
+
+      this.getCitys().then(() => {
+        if (!currentAddress) {
+          this.cityIds = [];
+          this.editForm.userAddress = "";
+          this.originalDetail = "";
+          return;
+        }
+        // 按“省 市 区 详细地址(空格分隔)”进行拆分。若无区或无市也不报错。
+        const parts = currentAddress.split(/\s+/);
+        const detail = parts.pop() || "";           // 末尾作为详细地址
+        const provLabel = parts[0];
+        const cityLabel = parts[1];
+        const areaLabel = parts[2];
+
+        const province = this.citys.find(p => p.label === provLabel);
+        if (province) {
+          // 只回显省,不预选市/区
+          this.cityIds = [province.value];
+        } else {
+          console.warn("未匹配到省:", { provLabel });
+          this.cityIds = [];
         }
-        this.editForm.orderChannel = this.item.orderChannel;
-        this.editForm.qwSubject = this.item.qwSubject;
-        this.editForm.scheduleId=this.item.scheduleId;
+        // 输入框只放“详细地址(不含省市区)”
+        this.editForm.userAddress = detail;
+        // 记录原始详细地址(用于判断有无修改)
+        this.originalDetail = detail;
+      });
     },
     updateExpress(){
       var that=this;

+ 568 - 0
src/views/store/coupon/index.vue

@@ -0,0 +1,568 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <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 label="有效期" prop="limitTime">
+                 <el-date-picker v-model="limitTime" 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="couponType">
+        <el-select v-model="queryParams.couponType" placeholder="请选择券类型" clearable size="small">
+          <el-option
+            v-for="dict in couponTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="面额" prop="price">
+        <el-input
+          v-model="queryParams.price"
+          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:coupon: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:coupon: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:coupon: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:coupon:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" border :data="couponList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="优惠券名称" align="center" prop="title" width="120px"/>
+      <el-table-column label="面额" align="center" prop="price" />
+      <el-table-column label="折扣" align="center" prop="rate" />
+      <el-table-column label="数量" align="center" prop="number" />
+      <el-table-column label="卷类型 " align="center" prop="couponType" width="120px">
+        <template slot-scope="scope">
+          <dict-tag :options="couponTypeOptions" :value="scope.row.couponType"/>
+        </template>
+      </el-table-column>
+     <el-table-column label="状态" align="center" prop="status">
+       <template slot-scope="scope">
+         <dict-tag :options="statusOptions" :value="scope.row.status"/>
+       </template>
+     </el-table-column>
+      <el-table-column label="最低消费金额可用" align="center" prop="minPrice" />
+      <el-table-column label="剩余数量" align="center" prop="remainNumber" />
+      <el-table-column label="有效期" align="center" prop="limitTime" width="180"/>
+      <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">
+        <template slot-scope="scope">
+          <!-- <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['his:coupon:edit']"
+          >修改</el-button> -->
+          <el-button
+               size="mini"
+               type="text"
+               @click="handledetails(scope.row)"
+           >详情
+           
+          </el-button>
+          <!-- <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:coupon:remove']"
+          >删除</el-button> -->
+
+         <el-button
+               size="mini"
+               type="text"
+               @click="send(scope.row)"
+               v-hasPermi="['his:userCoupon:send']"
+           >发送优惠劵
+          </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="openSend" width="500px" append-to-body>
+      <el-form ref="formSend"  label-width="100px">
+
+        <el-form-item label="优惠券名称" prop="title">
+          <div style="margin-left: 20px;font-weight: bold;">    {{sendForm.title}}</div>
+
+        </el-form-item>
+        <el-form-item label="面额" prop="price" v-if="form.couponType==1">
+          <div style="margin-left: 20px;font-weight: bold;">   {{sendForm.price}}</div>
+        </el-form-item>
+        <el-form-item label="搜索用户" >
+          <el-input placeholder="输入电话号码查询用户" v-model="phone" class="input-with-select">
+              <el-button slot="append" icon="el-icon-search" @click="selectPhone"></el-button>
+            </el-input>
+        </el-form-item>
+       <el-form-item label="用户" >
+         <el-select v-model="sendForm.userId">
+              <el-option
+                v-for="item in userList"
+                :key="item.name"
+                :label="item.name"
+                :value="item.id">
+              </el-option>
+            </el-select>
+       </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitSendForm">发 送</el-button>
+        <el-button @click="cancelSend">取 消</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="120px">
+        <el-form-item label="优惠券名称" prop="title">
+          <el-input v-model="form.title" placeholder="请输入优惠券名称" />
+        </el-form-item>
+
+        <el-form-item label="过期时间" prop="limitTime">
+          <el-date-picker clearable size="small"
+            v-model="form.limitTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择过期时间">
+          </el-date-picker>
+        </el-form-item>
+
+
+        <el-form-item label="用户可领取数量" prop="limitCount" >
+          <el-input-number v-model="form.limitCount"  :min="1"  label="请输入用户可领取数量"></el-input-number>
+        </el-form-item>
+        <el-form-item label="卷类型" prop="couponType">
+          <el-select v-model="form.couponType" placeholder="请选择卷类型" @change="isShowChange">
+            <el-option
+              v-for="dict in couponTypeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="可用分类" prop="cateIds" v-show="form.couponType==5||form.couponType==6">
+          <el-select v-model="form.cateIds" multiple placeholder="请选择可用分类">
+            <el-option
+              v-for="dict in cateIdsOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="面额" prop="price" v-if="form.couponType==1||form.couponType==5||form.couponType==6">
+          <el-input-number v-model="form.price"  :min="0"  label="请输入面额"></el-input-number>
+        </el-form-item>
+        <el-form-item label="最低消费" prop="minPrice" v-if="form.couponType==1||form.couponType==5||form.couponType==6">
+           <el-input-number v-model="form.minPrice"  :min="0"  label="请输入最低消费金额可用"></el-input-number>
+        </el-form-item>
+        <el-form-item label="打折百分比" prop="rate" v-if="form.couponType==4">
+          <el-input-number v-model="form.rate"  :min="1" :max="100"  label="请输入折扣百分比"></el-input-number>
+        </el-form-item>
+
+        <el-form-item label="有效期类型" prop="limitType">
+          <el-select v-model="form.limitType" placeholder="请选择有效期类型">
+            <el-option
+              v-for="dict in limitTypeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="领取后有效期(天)" prop="limitDay" >
+          <el-input-number v-model="form.limitDay"  :min="1"  label="请输入领取后有效期"></el-input-number>
+        </el-form-item>
+        <el-form-item label="数量" prop="number">
+            <el-input-number v-model="form.number"  :min="0"  label="请输入数量"></el-input-number>
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+                   <el-radio :label="item.dictValue" v-for="item in statusOptions" >{{item.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-drawer
+    	:with-header="false"
+            size="75%"
+             :title="show.title" :visible.sync="show.open">
+         <couponDetails  ref="Details" />
+       </el-drawer>
+  </div>
+</template>
+
+<script>
+import { listCoupon, getCoupon, delCoupon, addCoupon, updateCoupon, exportCoupon } from "@/api/store/coupon";
+import { sendCoupon } from "@/api/store/userCoupon";
+import couponDetails from '@/views/store/components/couponDetails.vue';
+import {selectUser} from "@/api/store/user";
+import {getAllCateList} from "@/api/store/packageCate";
+export default {
+  name: "Coupon",
+  components: { couponDetails },
+  data() {
+    return {
+      show:{
+              open:false,
+            },
+      limitTime:[],
+      userList:[],
+      userName: null,
+      // 遮罩层
+      loading: true,
+      phone:null,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 优惠券表格数据
+      couponList: [],
+      statusOptions: [],
+      limitTypeOptions: [],
+      privateTypeOptions: [],
+      diseaseTypeOptions: [],
+      orOptions: [],
+      cateIdsOptions: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      openSend:false,
+      // 卷类型 1代金券 字典
+      couponTypeOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: null,
+        limitTime: null,
+        price: null,
+        number: null,
+        couponType: null,
+        minPrice: null,
+        remainNumber: null,
+        sTime:null,
+        eTime:null
+      },
+      sendForm:{
+        title: null,
+        price: null,
+        couponId:null,
+        couponType:null,
+        userId:null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        title: [
+          { required: true, message: "标题不能为空", trigger: "blur" }
+        ],
+        limitTime: [
+          { required: true, message: "有效期不能为空", trigger: "blur" }
+        ],
+        couponType: [
+          { required: true, message: "券类型不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+    getAllCateList().then(response => {
+      this.diseaseTypeOptions = response.data.diseaseType;
+      this.privateTypeOptions = response.data.privateType;
+    });
+    this.getDicts("sys_coupon_type").then(response => {
+      this.couponTypeOptions = response.data;
+    });
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_coupon_limit_type").then(response => {
+      this.limitTypeOptions = response.data;
+    });
+    this.getDicts("sys_company_or").then(response => {
+      this.orOptions = response.data;
+    });
+
+  },
+  methods: {
+    send(row){
+      this.openSend=true;
+      this.sendForm.userId=null;
+      this.sendForm.couponId=row.couponId;
+      this.sendForm.title=row.title;
+      this.sendForm.price=row.price;
+      this.sendForm.couponType=row.couponType;
+    },
+    selectPhone(){
+        selectUser(this.phone).then(response => {
+          this.userList=response.rows;
+          if(this.userList!=null){
+              this.sendForm.userId=this.userList[0].id;
+          }
+        });
+    },
+    cancelSend(){
+      this.openSend=false;
+    },
+    submitSendForm(row){
+      if(this.sendForm.userId==null){
+        return this.$message('未选择用户');
+      }
+      sendCoupon(this.sendForm).then(response => {
+        this.msgSuccess("发送成功");
+        this.openSend=false;
+        this.getList();
+      });
+
+    },
+    /** 查询优惠券列表 */
+    getList() {
+      this.loading = true;
+      listCoupon(this.queryParams).then(response => {
+        this.couponList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        couponId: null,
+        title: null,
+        createTime: null,
+        limitTime: null,
+        price: null,
+        number: null,
+        couponType: null,
+        minPrice: null,
+        remainNumber: null,
+        status:"1",
+        rate:0,
+        limitDay:1,
+        limitCount:1,
+        limitType:null,
+        cateIds:null,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+       this.limitTime=null;
+      this.queryParams.sTime=null;
+      this.queryParams.eTime=null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.couponId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    handledetails(row){
+            this.show.open=true;
+            setTimeout(() => {
+                 this.$refs.Details.getDetails(row.couponId);
+            }, 1);
+     },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加优惠券";
+    },
+    isShowChange(){
+      this.form.cateIds=null
+      if(this.form.couponType==5){
+        this.cateIdsOptions=this.privateTypeOptions;
+      }else{
+        this.cateIdsOptions=this.diseaseTypeOptions;
+      }
+
+    },
+
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const couponId = row.couponId || this.ids
+      getCoupon(couponId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改优惠券";
+        this.form.status=String(this.form.status)
+        this.form.isShow=String(this.form.isShow)
+
+          if(this.form.couponType==5){
+            this.cateIdsOptions=this.privateTypeOptions;
+          }else{
+            this.cateIdsOptions=this.diseaseTypeOptions;
+          }
+          if(this.form.cateIds!=null){
+           this.form.cateIds= JSON.parse(this.form.cateIds)
+          }
+
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if(this.form.cateIds!=null){
+           this.form.cateIds= JSON.stringify(this.form.cateIds)
+          }
+
+          if (this.form.couponId != null) {
+            updateCoupon(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCoupon(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    change(){
+          if(this.limitTime!=null){
+            this.queryParams.sTime=this.limitTime[0];
+            this.queryParams.eTime=this.limitTime[1];
+          }else{
+            this.queryParams.sTime=null;
+            this.queryParams.eTime=null;
+          }
+
+        },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const couponIds = row.couponId || this.ids;
+      this.$confirm('是否确认删除优惠券编号为"' + couponIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delCoupon(couponIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有优惠券数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportCoupon(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 38 - 32
src/views/store/package/index.vue

@@ -178,8 +178,13 @@
           <el-input v-model="form.secondName" placeholder="请输入套餐包别名" />
         </el-form-item>
         <el-form-item label="封面图" prop="imgUrl">
-          <el-upload v-model="form.imgUrl" class="avatar-uploader" :action="uploadUrl" :show-file-list="false"
-            :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
+          <el-upload
+            v-model="form.imgUrl"
+            class="avatar-uploader"
+            :action="uploadUrl"
+            :show-file-list="false"
+            :on-success="handleAvatarSuccess"
+            :before-upload="beforeAvatarUpload">
             <img v-if="form.imgUrl" :src="form.imgUrl" class="avatar" width="300px">
             <i v-else class="el-icon-plus avatar-uploader-icon"></i>
           </el-upload>
@@ -473,6 +478,7 @@ import Editor from '@/components/Editor/wang';
 import Material from '@/components/Material';
 import { listStore } from "@/api/store/storeProduct";
 import { getAllCateList } from "@/api/store/packageCate";
+import { Loading } from 'element-ui';
 export default {
   name: "Package",
   components: { packageDetails, Editor, productAttrValueSelect, Material },
@@ -680,37 +686,37 @@ export default {
       }
     },
     beforeAvatarUpload(file) {
-      return new Promise((resolve, reject) => {
-        if (file.size / 1024 / 1024 > 3) {
-          this.$message.error('上传的图片不能超过3MB');
-          reject();
-          return;
-        }
-        if (file.size / 1024 > 500) {
-          const loadingInstance = Loading.service({ text: '图片内存过大正在压缩图片...' });
-          // 文件大于1MB时进行压缩
-          this.compressImage(file).then((compressedFile) => {
-            loadingInstance.close();
-            if (compressedFile.size / 1024 > 500) {
-              this.$message.error('图片压缩后仍大于500KB');
-              reject();
-            } else {
-              // this.$message.success(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
-              console.log(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
-              console.log(`最终内存大小为: ${(compressedFile.size / 1024).toFixed(2)}KB`);
-              resolve(compressedFile);
-            }
-          }).catch((err) => {
-            loadingInstance.close();
-            console.error(err);
+        return new Promise((resolve, reject) => {
+          if (file.size / 1024 / 1024 > 3) {
+            this.$message.error('上传的图片不能超过3MB');
             reject();
-          });
-        } else {
-          resolve(file);
-        }
-      });
-    },
-    compressImage(file) {
+            return;
+          }
+          if (file.size / 1024 > 500) {
+            const loadingInstance = Loading.service({ text: '图片内存过大正在压缩图片...' });
+            // 文件大于1MB时进行压缩
+            this.compressImage(file).then((compressedFile) => {
+              loadingInstance.close();
+              if (compressedFile.size / 1024 > 500) {
+                this.$message.error('图片压缩后仍大于500KB');
+                reject();
+              } else {
+                // this.$message.success(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
+                console.log(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
+                console.log(`最终内存大小为: ${(compressedFile.size/1024).toFixed(2)}KB`);
+                resolve(compressedFile);
+              }
+            }).catch((err) => {
+              loadingInstance.close();
+              console.error(err);
+              reject();
+            });
+          } else {
+            resolve(file);
+          }
+        });
+      },
+      compressImage(file) {
       return new Promise((resolve, reject) => {
         const reader = new FileReader();
         reader.readAsDataURL(file);

+ 432 - 0
src/views/store/userCoupon/index.vue

@@ -0,0 +1,432 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
+      <el-form-item label="券号" prop="couponCode">
+        <el-input
+          v-model="queryParams.couponCode"
+          placeholder="请输入券号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="券标题" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="请输入券标题"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item 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="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="useTime">
+                 <el-date-picker v-model="useTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="changeUse"></el-date-picker>
+              </el-form-item>
+      
+
+      <el-form-item label="关联订单" prop="businessId">
+        <el-input
+          v-model="queryParams.businessId"
+          placeholder="请输入关联订单ID"
+          clearable
+          size="small"
+          @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>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['his:userCoupon:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+    <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
+      <el-tab-pane label="全部" name="10"></el-tab-pane>
+      <el-tab-pane v-for="(item,index) in statusOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+    </el-tabs>
+    <el-table v-loading="loading" border :data="userCouponList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="优惠劵标题" align="center" prop="title" />
+      <el-table-column label="券号" align="center" prop="couponCode" />
+      <el-table-column label="会员昵称" align="center" prop="nickName" />
+      <el-table-column label="会员电话" align="center" prop="phone" />
+      <el-table-column label="面额" align="center" prop="price" />
+      <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="couponType" width="120px">
+        <template slot-scope="scope">
+          <dict-tag :options="couponTypeOptions" :value="scope.row.couponType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+       <el-table-column label="发送人" align="center" prop="sendUserName"/>
+       <el-table-column label="公司" align="center" prop="companyName"/>
+       <el-table-column label="销售" align="center" prop="companyUserName"/>
+      <el-table-column label="领取时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="使用时间" align="center" prop="useTime" width="180"/>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right">
+        <template slot-scope="scope">
+          <el-button v-if="scope.row.businessType!=null"
+            size="mini"
+            type="text"
+            @click="handledetails(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="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="优惠劵id" prop="couponId">
+          <el-input v-model="form.couponId" placeholder="请输入优惠劵id" />
+        </el-form-item>
+        <el-form-item label="券号" prop="couponCode">
+          <el-input v-model="form.couponCode" placeholder="请输入券号" />
+        </el-form-item>
+        <el-form-item label="会员ID" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入会员ID" />
+        </el-form-item>
+        <el-form-item label="使用时间" prop="useTime">
+          <el-date-picker clearable size="small"
+            v-model="form.useTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择使用时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="关联订单ID" prop="businessId">
+          <el-input v-model="form.businessId" placeholder="请输入关联订单ID" />
+        </el-form-item>
+        <el-form-item label="订单类型" prop="businessType">
+          <el-select v-model="form.businessType" placeholder="请选择订单类型">
+            <el-option
+              v-for="dict in businessTypeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="form.status" placeholder="请选择状态 0未使用 1已使用 2已过期">
+            <el-option
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <el-drawer
+         :with-header="false"
+         size="75%"
+          :title="show.title" :visible.sync="show.open">
+      <inquiryOrderDetails  ref="Details" />
+    </el-drawer>
+    <el-drawer
+         :with-header="false"
+         size="75%"
+          :title="show.title" :visible.sync="storeOpen">
+      <storeOrderDetails  ref="storeDetails" />
+    </el-drawer>
+  </div>
+</template>
+<script>
+import { listUserCoupon, getUserCoupon, delUserCoupon, addUserCoupon, updateUserCoupon, exportUserCoupon } from "@/api/store/userCoupon";
+import inquiryOrderDetails from '@/views/store/components/inquiryOrderDetails.vue';
+import storeOrderDetails from '@/views/store/components/storeOrderDetails.vue';
+export default {
+  name: "UserCoupon",
+  components: { inquiryOrderDetails,storeOrderDetails },
+  data() {
+    return {
+      show:{
+        open:false,
+        },
+      storeOpen:false,
+      // 遮罩层
+      createTime:[],
+      useTime:[],
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 会员优惠券表格数据
+      userCouponList: [],
+      // 卷类型 1代金券 字典
+      couponTypeOptions: [],
+      // 弹出层标题
+      title: "",
+      actName:"10",
+      // 是否显示弹出层
+      open: false,
+      // 订单类型 1问诊 2商城字典
+      businessTypeOptions: [],
+      // 状态 0未使用 1已使用 2已过期字典
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        couponId: null,
+        couponCode: null,
+        userId: null,
+        createTime: null,
+        updateTime: null,
+        useTime: null,
+        businessId: null,
+        businessType: null,
+        status: null,
+        sUseTime:null,
+        eUseTime:null,
+        sTime:null,
+        eTime:null,
+        phone:null,
+        title:null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_coupon_business_type").then(response => {
+      this.businessTypeOptions = response.data;
+    });
+    this.getDicts("sys_coupon_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_coupon_type").then(response => {
+      this.couponTypeOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询会员优惠券列表 */
+    getList() {
+      this.loading = true;
+      listUserCoupon(this.queryParams).then(response => {
+        this.userCouponList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    handledetails(row){
+            if(row.businessType==1){
+              this.show.open=true;
+              setTimeout(() => {
+                   this.$refs.Details.getDetails(row.businessId);
+              }, 1);
+            }else if(row.businessType==2){
+              this.storeOpen=true;
+              setTimeout(() => {
+                   this.$refs.storeDetails.getDetails(row.businessId);
+              }, 1);
+            }
+        },
+    handleClickX(tab, event) {
+     if(tab.name=="10"){
+       this.queryParams.status=null;
+     }else{
+       this.queryParams.status=tab.name;
+     }
+      this.handleQuery();
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        couponId: null,
+        couponCode: null,
+        userId: null,
+        createTime: null,
+        updateTime: null,
+        useTime: null,
+        businessId: null,
+        businessType: null,
+        status: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      console.log(this.queryParams)
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+       this.createTime=null;
+      this.queryParams.sTime=null;
+      this.queryParams.eTime=null;
+       this.useTime=null;
+      this.queryParams.sUseTime=null;
+      this.queryParams.eUseTime=null;
+      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 = "添加会员优惠券";
+    },
+    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;
+          }
+        },
+    changeUse(){
+          if(this.useTime!=null){
+            this.queryParams.sUseTime=this.useTime[0];
+            this.queryParams.eUseTime=this.useTime[1];
+          }else{
+            this.queryParams.sUseTime=null;
+            this.queryParams.eUseTime=null;
+          }
+        },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getUserCoupon(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) {
+            updateUserCoupon(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUserCoupon(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 delUserCoupon(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有会员优惠券数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportUserCoupon(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>