Browse Source

Merge remote-tracking branch 'origin/master'

yuhongqi 4 days ago
parent
commit
a1e7afad7c
34 changed files with 1839 additions and 157 deletions
  1. 3 0
      .env.prod-gzzdy
  2. 6 6
      .env.prod-hnyth
  3. 1 1
      .env.prod-sxjz
  4. 1 1
      package.json
  5. 7 0
      src/api/company/companyVoiceRobotic.js
  6. 76 0
      src/api/hisStore/store.js
  7. 7 0
      src/api/hisStore/storeOrder.js
  8. 62 0
      src/api/hisStore/storeOrderItem.js
  9. BIN
      src/assets/logo/yth.png
  10. 4 1
      src/views/company/companyRecharge/index.vue
  11. 31 4
      src/views/company/companyVoiceRobotic/index.vue
  12. 42 4
      src/views/course/courseAnswerlogs/index.vue
  13. 44 5
      src/views/course/courseAnswerlogs/myCourseAnswerlogs.vue
  14. 42 1
      src/views/course/courseUserStatistics/qw/index.vue
  15. 64 16
      src/views/course/courseWatchLog/deptWatchLog.vue
  16. 58 11
      src/views/course/courseWatchLog/index.vue
  17. 2 2
      src/views/course/courseWatchLog/qw/statistics.vue
  18. 104 9
      src/views/course/courseWatchLog/watchLog.vue
  19. 97 0
      src/views/crm/components/aiCallVoiceLog.vue
  20. 25 3
      src/views/crm/components/customerDetails.vue
  21. 15 15
      src/views/crm/components/duplicateCustomer.vue
  22. 19 19
      src/views/crm/components/lineCustomerDetails.vue
  23. 732 5
      src/views/hisStore/components/productOrder.vue
  24. 20 8
      src/views/hisStore/storeOrder/list.vue
  25. 4 4
      src/views/qw/friendWelcome/deptFriendWelcome.vue
  26. 4 4
      src/views/qw/friendWelcome/indexNew.vue
  27. 4 4
      src/views/qw/friendWelcome/myIndexNew.vue
  28. 4 4
      src/views/qw/friendWelcome/myWelcome.vue
  29. 62 24
      src/views/qw/sop/updateSop.vue
  30. 19 4
      src/views/store/components/userDetailsTemp.vue
  31. 1 0
      src/views/store/components/userStaticAll.vue
  32. 275 0
      src/views/store/components/userStoreOrderList.vue
  33. 2 1
      src/views/store/user/list.vue
  34. 2 1
      src/views/store/user/myList.vue

+ 3 - 0
.env.prod-gzzdy

@@ -23,3 +23,6 @@ VUE_APP_PROJECT_FROM=gzzdy
 
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+# 郑多燕
+VUE_APP_FS_USER_INFO = 'gzzdy'

+ 6 - 6
.env.prod-knt2 → .env.prod-hnyth

@@ -1,13 +1,13 @@
 # 页面标题
-VUE_APP_TITLE = 康年堂SCRM销售端
+VUE_APP_TITLE = 养天和SCRM销售端
 # 公司名称
-VUE_APP_COMPANY_NAME = 陕西康年堂医药连锁有限公司
+VUE_APP_COMPANY_NAME = 湖南养天和中医馆有限公司
 # ICP备案号
-VUE_APP_ICP_RECORD = 陕ICP备2023011686号-5
+VUE_APP_ICP_RECORD = 湘ICP备18014714号-16
 # ICP网站访问地址
 VUE_APP_ICP_URL =https://beian.miit.gov.cn
 # 网站LOG
-VUE_APP_LOG_URL =@/assets/logo/knt.jpg
+VUE_APP_LOG_URL =@/assets/logo/yth.png
 
 # 生产环境配置
 ENV = 'production'
@@ -20,7 +20,7 @@ VUE_CLI_BABEL_TRANSPILE_MODULES = true
 
 
 #项目所属
-VUE_APP_PROJECT_FROM=knt
+VUE_APP_PROJECT_FROM=hnyth
 
 #默认 1、会员 2、企微
-VUE_APP_COURSE_DEFAULT = 1
+VUE_APP_COURSE_DEFAULT = 2

+ 1 - 1
.env.prod-sxjz

@@ -16,7 +16,7 @@ ENV = 'production'
 VUE_APP_BASE_API = '/prod-api'
 
 #默认 1、会员 2、企微
-VUE_APP_COURSE_DEFAULT = 1
+VUE_APP_COURSE_DEFAULT = 2
 
 #项目所属
 VUE_APP_PROJECT_FROM=sxjz

+ 1 - 1
package.json

@@ -19,7 +19,7 @@
     "build:prod-sxjz": "vue-cli-service build --mode prod-sxjz",
     "build:prod-jnmy": "vue-cli-service build --mode prod-jnmy",
     "build:prod-knt": "vue-cli-service build --mode prod-knt",
-    "build:prod-knt2": "vue-cli-service build --mode prod-knt2",
+    "build:prod-hnyth": "vue-cli-service build --mode prod-hnyth",
     "build:prod-hdt": "vue-cli-service build --mode prod-hdt",
     "build:prod-yzt": "vue-cli-service build --mode prod-yzt",
     "build:prod-xfk": "vue-cli-service build --mode prod-xfk",

+ 7 - 0
src/api/company/companyVoiceRobotic.js

@@ -125,3 +125,10 @@ export function taskRun(params) {
     params
   })
 }
+
+export function getSmsTempList() {
+  return request({
+    url: '/company/companySmsTemp/getSmsTempList',
+    method: 'get'
+  })
+}

+ 76 - 0
src/api/hisStore/store.js

@@ -0,0 +1,76 @@
+import request from '@/utils/request'
+
+// 查询店铺管理列表
+export function listStore(query) {
+  return request({
+    url: '/store/his/store/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询店铺管理详细
+export function getStore(storeId) {
+  return request({
+    url: '/store/his/store/' + storeId,
+    method: 'get'
+  })
+}
+
+
+// 新增店铺管理
+export function addStore(data) {
+  return request({
+    url: '/store/his/store',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改店铺管理
+export function updateStore(data) {
+  return request({
+    url: '/store/his/store',
+    method: 'put',
+    data: data
+  })
+}
+// 修改店铺管理
+export function audit(data) {
+  return request({
+    url: '/store/his/store/audit',
+    method: 'put',
+    data: data
+  })
+}
+// 删除店铺管理
+export function delStore(storeId) {
+  return request({
+    url: '/store/his/store/' + storeId,
+    method: 'delete'
+  })
+}
+
+export function refreshPasWod(storeId) {
+  return request({
+    url: '/store/his/store/refresh/'+ storeId,
+    method: 'put'
+  })
+}
+
+// 导出店铺管理
+export function exportStore(query) {
+  return request({
+    url: '/store/his/store/export',
+    method: 'get',
+    params: query
+  })
+}
+
+//getStoreAuditLog
+export function getStoreAuditLog(storeId) {
+  return request({
+    url: '/store/his/store/auditLog/'+ storeId,
+    method: 'get'
+  })
+}

+ 7 - 0
src/api/hisStore/storeOrder.js

@@ -161,4 +161,11 @@ export function auditStoreOrder(data) {
     data: data
   })
 }
+// 修改订单ItemJson
+export function updateStoreOrderItemJson(id,backendEditProductType) {
+  return request({
+    url: '/store/store/storeOrder/updateStoreOrderItemJson/'+id + "/" + backendEditProductType,
+    method: 'get'
+  })
+}
 

+ 62 - 0
src/api/hisStore/storeOrderItem.js

@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 查询订单详情列表
+export function listStoreOrderItem(query) {
+  return request({
+    url: '/store/store/storeOrderItem/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询订单详情详细
+export function getStoreOrderItem(itemId) {
+  return request({
+    url: '/store/store/storeOrderItem/' + itemId,
+    method: 'get'
+  })
+}
+
+// 新增订单详情
+export function addStoreOrderItem(data) {
+  return request({
+    url: '/store/store/storeOrderItem',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改订单详情
+export function updateStoreOrderItem(data) {
+  return request({
+    url: '/store/store/storeOrderItem',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除订单详情
+export function delStoreOrderItem(itemId) {
+  return request({
+    url: '/store/store/storeOrderItem/' + itemId,
+    method: 'delete'
+  })
+}
+
+// 导出订单详情
+export function exportStoreOrderItem(query) {
+  return request({
+    url: '/store/store/storeOrderItem/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 修改订单数量
+export function updateNumStoreOrderItem(data) {
+  return request({
+    url: '/store/store/storeOrderItem/updateNum',
+    method: 'put',
+    data: data
+  })
+}

BIN
src/assets/logo/yth.png


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

@@ -83,7 +83,7 @@
           <dict-tag :options="businessTypeOptions" :value="scope.row.businessType"/>
         </template>
       </el-table-column>
-      <el-table-column label="凭证照片" align="center" prop="images" >
+      <el-table-column label="凭证照片" align="center" prop="imgs" >
         <template slot-scope="scope">
           <div v-if="scope.row.imgs != null && scope.row.imgs != undefined && scope.row.imgs != ''">
             <el-image
@@ -195,6 +195,9 @@
         <el-form-item label="充值金额" prop="money">
           <el-input-number v-model="redRechargeForm.money" :min="0.01" placeholder="请输入充值金额"/>
         </el-form-item>
+        <el-form-item label="凭证" prop="imgs">
+          <image-upload v-model="redRechargeForm.imgs" :limit="9" />
+        </el-form-item>
         <el-form-item label="备注" prop="remark">
           <el-input v-model="redRechargeForm.remark" placeholder="请输入备注"/>
         </el-form-item>

+ 31 - 4
src/views/company/companyVoiceRobotic/index.vue

@@ -217,10 +217,13 @@
             <el-radio v-model="form.addType" :label="0">平均</el-radio>
             <el-radio v-model="form.addType" :label="1">意向</el-radio>
           </el-form-item>
+          <el-form-item label="加微等待时间" prop="addWxTime" >
+              <el-input style="width:240px"  v-model="form.addWxTime" placeholder="加微等待时间"/>
+          </el-form-item>
           <el-form-item label="分配账号">
             <el-button @click="addQwUser">添加</el-button>
             <el-row :gutter="24" v-for="(item, index) in form.qwUser" style="margin-top: 5px">
-              <el-col :span="5">
+              <el-col :span="5" v-if="form.addType == 1">
                 <el-select v-model="item.intention" placeholder="意向等级" filterable clearable>
                   <el-option v-for="item in levelList" :label="item.dictLabel" :value="item.dictValue"/>
                 </el-select>
@@ -233,6 +236,11 @@
                   <el-option v-for="item in wxDialogList" :label="item.name" :value="item.id"/>
                 </el-select>
               </el-col>
+              <el-col :span="5">
+                <el-select v-model="item.smsTempId" placeholder="短信模板" filterable>
+                  <el-option v-for="item in smsTempList" :label="item.title" :value="item.tempId"/>
+                </el-select>
+              </el-col>
               <el-col :span="3">
                 <el-button type="danger" icon="el-icon-delete" circle @click="removeQwUser(index)"></el-button>
               </el-col>
@@ -346,7 +354,8 @@ import {
   companyUserList,
   wxList,
   taskRun,
-  getTypes
+  getTypes,
+  getSmsTempList
 } from "@/api/company/companyVoiceRobotic";
 import draggable from 'vuedraggable'
 import { listAll } from '@/api/company/wxDialog';
@@ -452,7 +461,8 @@ export default {
         },
       },
       // 表单校验
-      rules: {}
+      rules: {},
+      smsTempList:[]
     };
   },
   created() {
@@ -470,8 +480,17 @@ export default {
       this.levelList = e.data;
     })
     this.getList();
+    this.getSmsTempDropList();
   },
   methods: {
+    getSmsTempDropList(){
+      getSmsTempList().then(res=>{
+        this.smsTempList = res.data;
+        console.log(this.smsTempList);
+      }).catch(res=>{
+        console.log(res);
+      })
+    },
     /** 查询机器人外呼任务列表 */
     getList() {
       this.loading = true;
@@ -570,9 +589,17 @@ export default {
           }
           let list = [];
           this.form.qwUser.forEach(l => {
-            list = list.concat(l.companyUserId.map(e => {return {intention: l.intention, companyUserId: e,wxDialogId: l.wxDialogId}}))
+            list = list.concat(l.companyUserId.map(e => {return {intention: l.intention, companyUserId: e,wxDialogId: l.wxDialogId,smsTempId:l.smsTempId}}))
           })
           this.form.qwUserList = list;
+          console.log(this.form);
+          if(this.form.addType != 0 ){
+           let firstTask = taskFlowList[0];
+            if(firstTask.key != "cellPhone"){
+              this.msgError("【意向】加微方式下,任务流程第一步必须为外呼!");
+              return;
+            }
+          }
           if(!this.form.qwUserList || this.form.qwUserList.length == 0){
             this.msgError("请选者加微方案");
             return;

+ 42 - 4
src/views/course/courseAnswerlogs/index.vue

@@ -134,7 +134,10 @@
       <el-table-column label="小节名称" align="center" prop="videoName" />
       <el-table-column label="是否全部正确" align="center" prop="isRight" >
         <template slot-scope="scope">
-          <dict-tag :options="sysCompanyOr" :value="scope.row.isRight"></dict-tag>
+            <dict-tag :options="sysCompanyOr" :value="scope.row.isRight" style="margin-bottom: 5px;"></dict-tag>
+            <el-button type="text" size="mini" @click="showContentDialog(scope.row.questionJson)">
+              查看详情
+            </el-button>
         </template>
       </el-table-column>
       <el-table-column label="销售名称" align="center" prop="companyUserName" />
@@ -151,13 +154,32 @@
       @pagination="getList"
     />
 
+    <el-dialog :visible.sync="contentDialog.isDialogVisible" title="消息详情" width="30%" append-to-body>
+      <div>
+        <div v-for="(item, index) in contentDialog.json || []" :key="index">
+          <el-card class="box-card" style="margin-top: 2%">
+            <div>题目:<span style="color: #0464f4">{{item.title}}</span></div>
+            <div>答题:<span style="color: #000000">{{item.answer}}</span></div>
+            <div>是否答题正确:
+              <span :style="{color: item.status === 1 ? 'green' : 'red'}">
+                {{ item.status === 1 ? '正确' : '错误' }}
+            </span>
+            </div>
+          </el-card>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="contentDialog.isDialogVisible = false">关闭</el-button>
+      </span>
+    </el-dialog>
+
   </div>
 </template>
 
 <script>
-import { listLogs, getLogs, delLogs, addLogs, updateLogs, exportLogs } from "@/api/course/courseAnswerlogs";
-import { courseList, videoList } from '@/api/course/courseRedPacketLog'
-import { getCompanyList } from '@/api/company/company'
+import {addLogs, delLogs, exportLogs, getLogs, listLogs, updateLogs} from "@/api/course/courseAnswerlogs";
+import {courseList, videoList} from '@/api/course/courseRedPacketLog'
+import {getCompanyList} from '@/api/company/company'
 
 export default {
   name: "Logs",
@@ -190,6 +212,13 @@ export default {
 
       // 答题日志表格数据
       logsList: [],
+
+      //发送的消息
+      contentDialog:{
+        isDialogVisible:false,
+        json: [],
+      },
+
       // 弹出层标题
       title: "",
       // 是否显示弹出层
@@ -258,6 +287,15 @@ export default {
       });
     },
 
+    showContentDialog(questionJson){
+      // 解析 JSON 字符串为 JavaScript 对象
+      // 替换非法换行符等控制字符
+      const sanitizedJson = questionJson.replace(/[\u0000-\u001F\u007F]/g, '');
+      this.contentDialog.json = JSON.parse(sanitizedJson);
+
+      this.contentDialog.isDialogVisible = true;
+    },
+
     timeChange(){
       if(this.createTime!=null){
         this.queryParams.sTime=this.createTime[0];

+ 44 - 5
src/views/course/courseAnswerlogs/myCourseAnswerlogs.vue

@@ -125,7 +125,10 @@
       <el-table-column label="小节名称" align="center" prop="videoName" />
       <el-table-column label="是否全部正确" align="center" prop="isRight" >
         <template slot-scope="scope">
-          <dict-tag :options="sysCompanyOr" :value="scope.row.isRight"></dict-tag>
+            <dict-tag :options="sysCompanyOr" :value="scope.row.isRight" style="margin-bottom: 5px;"></dict-tag>
+            <el-button type="text" size="mini" @click="showContentDialog(scope.row.questionJson)">
+              查看详情
+            </el-button>
         </template>
       </el-table-column>
       <el-table-column label="销售名称" align="center" prop="companyUserName" />
@@ -142,14 +145,32 @@
       @pagination="getList"
     />
 
+    <el-dialog :visible.sync="contentDialog.isDialogVisible" title="消息详情" width="30%" append-to-body>
+      <div>
+        <div v-for="(item, index) in contentDialog.json || []" :key="index">
+          <el-card class="box-card" style="margin-top: 2%">
+            <div>题目:<span style="color: #0464f4">{{item.title}}</span></div>
+            <div>答题:<span style="color: #000000">{{item.answer}}</span></div>
+            <div>是否答题正确:
+              <span :style="{color: item.status === 1 ? 'green' : 'red'}">
+                {{ item.status === 1 ? '正确' : '错误' }}
+            </span>
+            </div>
+          </el-card>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="contentDialog.isDialogVisible = false">关闭</el-button>
+      </span>
+    </el-dialog>
+
+
   </div>
 </template>
 
 <script>
-import { myListLogs, getLogs, delLogs, addLogs, updateLogs, exportLogs, exportMyLogs } from "@/api/course/courseAnswerlogs";
-import { courseList, videoList } from '@/api/course/courseRedPacketLog'
-import {allListTagGroup} from "@/api/qw/tagGroup";
-import {listTag} from "@/api/qw/tag";
+import {addLogs, delLogs, exportMyLogs, getLogs, myListLogs, updateLogs} from "@/api/course/courseAnswerlogs";
+import {courseList, videoList} from '@/api/course/courseRedPacketLog'
 import {getMyQwUserList} from "@/api/qw/user";
 
 export default {
@@ -206,6 +227,13 @@ export default {
       createTime:null,
       // 表单参数
       form: {},
+
+      //发送的消息
+      contentDialog:{
+        isDialogVisible:false,
+        json: [],
+      },
+
       // 表单校验
       rules: {
       }
@@ -308,6 +336,17 @@ export default {
       this.queryParams.eTime=null;
       this.handleQuery();
     },
+
+    showContentDialog(questionJson){
+      // 解析 JSON 字符串为 JavaScript 对象
+      // 替换非法换行符等控制字符
+      const sanitizedJson = questionJson.replace(/[\u0000-\u001F\u007F]/g, '');
+      this.contentDialog.json = JSON.parse(sanitizedJson);
+
+      this.contentDialog.isDialogVisible = true;
+    },
+
+
     // 多选框选中数据
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.logId)

+ 42 - 1
src/views/course/courseUserStatistics/qw/index.vue

@@ -49,6 +49,18 @@
         />
       </el-form-item>
 
+      <!--企微主体选择框 -->
+      <el-form-item label="企微主体" prop="corpId">
+        <el-select v-model="queryParams.corpId" placeholder="企微主体" size="small" @change="updateCorpId()" clearable>
+          <el-option
+            v-for="dict in myQwCompanyList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
       <el-form-item label="添加时间" prop="createTime">
         <el-date-picker
           v-model="createTime"
@@ -346,6 +358,22 @@
           </span>
         </template>
       </el-table-column>
+
+      <!-- 重粉数 -->
+      <el-table-column label="重粉数" align="center" prop="repeatCount">
+        <template slot-scope="scope">
+          <span>{{ scope.row.repeatCount }}</span>
+          <span
+            :style="{
+              'font-size': '12px',
+              'margin-left': '5px',
+              color: getPercentageColor((scope.row.repeatCount / scope.row.line) * 100),
+            }"
+          >
+            ({{ ((scope.row.repeatCount / scope.row.line) * 100).toFixed(2) }}%)
+          </span>
+        </template>
+      </el-table-column>
     </el-table>
 
     <pagination-more
@@ -375,10 +403,12 @@ import { treeselect } from "@/api/company/companyDept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { getCompanyUserListLikeName } from "@/api/company/companyUser";
+import { getMyQwCompanyList } from '@/api/qw/user';
 import { getTask } from "@/api/common";
+import PaginationMore from "@/components/PaginationMore/index.vue";
 export default {
   name: "CourseWatchLog",
-  components: { Treeselect },
+  components: {PaginationMore, Treeselect },
   data() {
     return {
       activeName: "00",
@@ -433,12 +463,14 @@ export default {
         eTime: null,
         scheduleStartTime: null,
         scheduleEndTime: null,
+        corpId: null, // 企微主体ID
       },
       // 表单参数
       form: {},
       // 表单校验
       rules: {},
       scheduleTime: null,
+      myQwCompanyList: [], // 存储企微主体选项列表
     };
   },
   created() {
@@ -451,8 +483,16 @@ export default {
     });
     this.getTreeselect();
     this.getList();
+    // --- 获取企微主体列表 ---
+    getMyQwCompanyList().then(response => {
+      this.myQwCompanyList = response.data;
+    });
   },
   methods: {
+    updateCorpId() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
     getSummaries(param) {
       let totalNum = 0;
       const { columns, data } = param;
@@ -639,6 +679,7 @@ export default {
       this.queryParams.eTime = null;
       this.queryParams.scheduleStartTime = null;
       this.queryParams.scheduleEndTime = null;
+      this.queryParams.corpId = null; // 重置企微主体选择
       this.handleQuery();
     },
     // 多选框选中数据

+ 64 - 16
src/views/course/courseWatchLog/deptWatchLog.vue

@@ -215,16 +215,16 @@
         />
       </el-form-item> -->
        <el-form-item label="最新更新时间" prop="updateTime">
-        <el-date-picker
-          v-model="updateTimeText"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-          value-format="yyyy-MM-dd"
-          style="width: 240px"
+         <el-date-picker
+           v-model="updateTimeText"
+           type="datetimerange"
+           range-separator="至"
+           start-placeholder="开始日期"
+           end-placeholder="结束日期"
+           value-format="yyyy-MM-dd HH:mm:ss"
            @change="updateChange"
-        />
+           :default-time="['00:00:00', '23:59:59']"
+         />
       </el-form-item>
       <!-- 进线时间 -->
       <!-- <el-form-item label="进线时间" prop="qecCreateTime">
@@ -411,11 +411,12 @@
         <el-table-column label="课程名称" align="center" prop="courseName"/>
         <el-table-column label="小节名称" align="center" prop="videoName"/>
         <el-table-column label="是否全部正确" align="center" prop="isRightText"/>
-<!--        <el-table-column label="是否全部正确" align="center" prop="isRight">-->
-<!--          <template slot-scope="scope">-->
-<!--            <dict-tag :options="sysCompanyOr" :value="scope.row.isRight"></dict-tag>-->
-<!--          </template>-->
-<!--        </el-table-column>-->
+        <template slot-scope="scope">
+          <dict-tag :options="sysCompanyOr" :value="scope.row.isRight" style="margin-bottom: 5px;"></dict-tag>
+          <el-button type="text" size="mini" @click="showContentDialog(scope.row.questionJson)">
+            查看详情
+          </el-button>
+        </template>
         <el-table-column label="销售名称" align="center" prop="companyUserName"/>
         <el-table-column label="企微员工名称" align="center" prop="qwUserName"/>
         <el-table-column label="公司名称" align="center" prop="companyName"/>
@@ -487,14 +488,42 @@
       />
     </el-drawer>
 
+
+    <el-dialog :visible.sync="contentDialog.isDialogVisible" title="消息详情" width="30%" append-to-body>
+      <div>
+        <div v-for="(item, index) in contentDialog.json || []" :key="index">
+          <el-card class="box-card" style="margin-top: 2%">
+            <div>题目:<span style="color: #0464f4">{{item.title}}</span></div>
+            <div>答题:<span style="color: #000000">{{item.answer}}</span></div>
+            <div>是否答题正确:
+              <span :style="{color: item.status === 1 ? 'green' : 'red'}">
+                {{ item.status === 1 ? '正确' : '错误' }}
+            </span>
+            </div>
+          </el-card>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="contentDialog.isDialogVisible = false">关闭</el-button>
+      </span>
+    </el-dialog>
+
+
   </div>
 </template>
 
 <script>
-import { deptListCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog } from "@/api/course/courseWatchLog";
+import {
+  addCourseWatchLog,
+  delCourseWatchLog,
+  deptListCourseWatchLog,
+  exportCourseWatchLog,
+  getCourseWatchLog,
+  updateCourseWatchLog
+} from "@/api/course/courseWatchLog";
 import {courseList, myListCourseRedPacketLog, videoList} from '@/api/course/courseRedPacketLog'
 import {myListLogs} from "@/api/course/courseAnswerlogs";
-import { getCompanyUserListLikeName } from "@/api/company/companyUser";
+import {getCompanyUserListLikeName} from "@/api/company/companyUser";
 import {getTask} from "@/api/common";
 import Vue from 'vue'
 import Calendar from 'vue-mobile-calendar'
@@ -502,6 +531,7 @@ import {infoSop} from "@/api/qw/sop";
 import {myDeptTreeselect} from "../../../api/company/companyDept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
 Vue.use(Calendar)
 
 
@@ -550,6 +580,13 @@ export default {
       courseLists:[],
       videoList:[],
       logTypeOptions:[],
+
+      //发送的消息
+      contentDialog:{
+        isDialogVisible:false,
+        json: [],
+      },
+
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -674,6 +711,17 @@ export default {
     this.loading=false;
   },
   methods: {
+
+    showContentDialog(questionJson){
+      // 解析 JSON 字符串为 JavaScript 对象
+      // 替换非法换行符等控制字符
+      const sanitizedJson = questionJson.replace(/[\u0000-\u001F\u007F]/g, '');
+      this.contentDialog.json = JSON.parse(sanitizedJson);
+
+      this.contentDialog.isDialogVisible = true;
+    },
+
+
     setToday(){
       const today = new Date();
       const todayStart = new Date(today);

+ 58 - 11
src/views/course/courseWatchLog/index.vue

@@ -245,16 +245,16 @@
         />
       </el-form-item> -->
        <el-form-item label="最新更新时间" prop="updateTime">
-        <el-date-picker
-          v-model="updateTimeText"
-          type="daterange"
-          range-separator="至"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-          value-format="yyyy-MM-dd"
-          style="width: 240px"
+         <el-date-picker
+           v-model="updateTimeText"
+           type="datetimerange"
+           range-separator="至"
+           start-placeholder="开始日期"
+           end-placeholder="结束日期"
+           value-format="yyyy-MM-dd HH:mm:ss"
            @change="updateChange"
-        />
+           :default-time="['00:00:00', '23:59:59']"
+         />
       </el-form-item>
       <!-- 进线时间 -->
       <!-- <el-form-item label="进线时间" prop="qecCreateTime">
@@ -481,7 +481,10 @@
         <el-table-column label="小节名称" align="center" prop="videoName"/>
         <el-table-column label="是否全部正确" align="center" prop="isRight">
           <template slot-scope="scope">
-            <dict-tag :options="sysCompanyOr" :value="scope.row.isRight"></dict-tag>
+            <dict-tag :options="sysCompanyOr" :value="scope.row.isRight" style="margin-bottom: 5px;"></dict-tag>
+            <el-button type="text" size="mini" @click="showContentDialog(scope.row.questionJson)">
+              查看详情
+            </el-button>
           </template>
         </el-table-column>
         <el-table-column label="销售名称" align="center" prop="companyUserName"/>
@@ -655,12 +658,37 @@
         <el-button @click="resultDialogVisible = false">关闭</el-button>
       </span>
     </el-dialog>
+    <el-dialog :visible.sync="contentDialog.isDialogVisible" title="消息详情" width="30%" append-to-body>
+      <div>
+        <div v-for="(item, index) in contentDialog.json || []" :key="index">
+          <el-card class="box-card" style="margin-top: 2%">
+            <div>题目:<span style="color: #0464f4">{{item.title}}</span></div>
+            <div>答题:<span style="color: #000000">{{item.answer}}</span></div>
+            <div>是否答题正确:
+              <span :style="{color: item.status === 1 ? 'green' : 'red'}">
+                {{ item.status === 1 ? '正确' : '错误' }}
+            </span>
+            </div>
+          </el-card>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="contentDialog.isDialogVisible = false">关闭</el-button>
+      </span>
+    </el-dialog>
 
   </div>
 </template>
 
 <script>
-import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog } from "@/api/course/courseWatchLog";
+import {
+  addCourseWatchLog,
+  delCourseWatchLog,
+  exportCourseWatchLog,
+  getCourseWatchLog,
+  listCourseWatchLog,
+  updateCourseWatchLog
+} from "@/api/course/courseWatchLog";
 import {listPeriodLabel} from "@/api/course/userCoursePeriod";
 import {courseList, listCourseRedPacketLog, videoList} from '@/api/course/courseRedPacketLog'
 import {listLogs} from "@/api/course/courseAnswerlogs";
@@ -675,6 +703,7 @@ import {getQwList} from "@/api/qw/qwUser";
 import {treeselect} from "@/api/company/companyDept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
 Vue.use(Calendar)
 
 export default {
@@ -862,6 +891,13 @@ export default {
       // 表单校验
       rules: {
       },
+
+      //发送的消息
+      contentDialog:{
+        isDialogVisible:false,
+        json: [],
+      },
+
       // 员工选项列表
       companyUserOptionsParams: {
         name: undefined,
@@ -909,6 +945,17 @@ export default {
     this.loading=false;
   },
   methods: {
+
+    showContentDialog(questionJson){
+      // 解析 JSON 字符串为 JavaScript 对象
+      // 替换非法换行符等控制字符
+      const sanitizedJson = questionJson.replace(/[\u0000-\u001F\u007F]/g, '');
+      this.contentDialog.json = JSON.parse(sanitizedJson);
+
+      this.contentDialog.isDialogVisible = true;
+    },
+
+
     getTreeselect() {
       treeselect().then((response) => {
         this.deptOptions = response.data;

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

@@ -196,7 +196,7 @@ export default {
             column.property === "noUserWaitNumber" ||
             column.property === "onLineRate" ||
             column.property === "finishedRate" ||
-            column.property === "redAmount" 
+            column.property === "redAmount"
           ) {
           }
         } else {
@@ -213,7 +213,7 @@ export default {
             } else if(index === 13 && !!sums[9]){
               sums[index] =  (sums[7] * 100 / sums[9]).toFixed(2) + '%';
             }
-          } 
+          }
         }
       });
       console.log(sums);

+ 104 - 9
src/views/course/courseWatchLog/watchLog.vue

@@ -218,13 +218,13 @@
         <el-form-item label="最新更新时间" prop="updateTime">
         <el-date-picker
           v-model="updateTimeText"
-          type="daterange"
+          type="datetimerange"
           range-separator="至"
           start-placeholder="开始日期"
           end-placeholder="结束日期"
-          value-format="yyyy-MM-dd"
-          style="width: 240px"
+          value-format="yyyy-MM-dd HH:mm:ss"
            @change="updateChange"
+          :default-time="['00:00:00', '23:59:59']"
         />
       </el-form-item>
       <!-- 进线时间 -->
@@ -302,6 +302,21 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="会员状态" prop="externalStatus">
+        <el-select
+          v-model="queryParams.externalStatus"
+          placeholder="请选择会员状态"
+          clearable
+          size="small"
+          filterable>
+          <el-option
+            v-for="dict in externalStatusOptions"
+            :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>
@@ -377,7 +392,19 @@
       :key="tableKey">
       <el-table-column type="selection" width="55" align="center"/>
       <el-table-column label="记录编号" align="center" prop="logId"/>
-     <el-table-column label="客户昵称" align="center" prop="externalUserName" v-if="queryParams.sendType == 2"/>
+      <el-table-column label="客户昵称" align="center" prop="externalUserName" v-if="queryParams.sendType == 2">
+        <template slot-scope="scope">
+          <span>{{ scope.row.externalUserName }}</span>
+          <i
+            ref="copyIcon"
+            class="el-icon-document-copy"
+            style="margin-left: 5px; cursor: pointer; color: #409EFF;"
+            @click="copyText(scope.row.externalUserName, $event)"
+            title="点击复制"
+          ></i>
+        </template>
+
+      </el-table-column>
 
       &lt;!&ndash;
       <el-table-column label="会员ID" align="center" prop="userId" v-if="queryParams.sendType == 1"/>
@@ -458,6 +485,11 @@
           </el-tag>
         </template>
       </el-table-column>
+      <el-table-column label="会员状态" align="center" prop="externalStatus">
+        <template slot-scope="scope">
+          <dict-tag :options="externalStatusOptions" :value="scope.row.externalStatus"/>
+        </template>
+      </el-table-column>
       <el-table-column
         fixed="right"
         label="操作"
@@ -500,7 +532,10 @@
         <el-table-column label="小节名称" align="center" prop="videoName"/>
         <el-table-column label="是否全部正确" align="center" prop="isRight">
           <template slot-scope="scope">
-            <dict-tag :options="sysCompanyOr" :value="scope.row.isRight"></dict-tag>
+            <dict-tag :options="sysCompanyOr" :value="scope.row.isRight" style="margin-bottom: 5px;"></dict-tag>
+            <el-button type="text" size="mini" @click="showContentDialog(scope.row.questionJson)">
+              查看详情
+            </el-button>
           </template>
         </el-table-column>
         <el-table-column label="销售名称" align="center" prop="companyUserName"/>
@@ -712,15 +747,36 @@
       </div>
     </el-dialog>
 
+    <el-dialog :visible.sync="contentDialog.isDialogVisible" title="消息详情" width="30%" append-to-body>
+      <div>
+        <div v-for="(item, index) in contentDialog.json || []" :key="index">
+          <el-card class="box-card" style="margin-top: 2%">
+            <div>题目:<span style="color: #0464f4">{{item.title}}</span></div>
+            <div>答题:<span style="color: #000000">{{item.answer}}</span></div>
+            <div>是否答题正确:
+              <span :style="{color: item.status === 1 ? 'green' : 'red'}">
+                {{ item.status === 1 ? '正确' : '错误' }}
+            </span>
+            </div>
+          </el-card>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="contentDialog.isDialogVisible = false">关闭</el-button>
+      </span>
+    </el-dialog>
+
+
   </div>
 </template>
 
 <script>
+import ClipboardJS from 'clipboard';
 import {
   addCourseWatchLog,
   delCourseWatchLog,
-  exportCourseWatchLog,
-  getCourseWatchLog, myExportCourseWatchLog,
+  getCourseWatchLog,
+  myExportCourseWatchLog,
   myListCourseWatchLog,
   updateCourseWatchLog
 } from "@/api/course/courseWatchLog";
@@ -729,11 +785,12 @@ import {listPeriodLabel} from "@/api/course/userCoursePeriod";
 import {myListLogs} from "@/api/course/courseAnswerlogs";
 import {getMyQwUserList} from "@/api/qw/user";
 import {searchTags} from "../../../api/qw/tag";
-import {addTagByWatch, delTagByWatch,batchUpdateExternalContactNotes,batchUpdateExternalContactNotesByWatchLog} from "../../../api/qw/externalContact";
+import {addTagByWatch, batchUpdateExternalContactNotesByWatchLog, delTagByWatch} from "../../../api/qw/externalContact";
 import {allListTagGroup} from "../../../api/qw/tagGroup";
 import Vue from 'vue'
 import Calendar from 'vue-mobile-calendar'
 import {infoSop} from "@/api/qw/sop";
+
 Vue.use(Calendar)
 
 export default {
@@ -773,7 +830,11 @@ export default {
       resultDialogVisible: false,
       resultMessage: '',
       resultTitle:'',
-
+      //发送的消息
+      contentDialog:{
+        isDialogVisible:false,
+        json: [],
+      },
       activeName:"2",
       pickerOptions: {
         disabledDate(time) {
@@ -795,6 +856,7 @@ export default {
       videoList: [],
       myQwUserList: [],
       logTypeOptions: [],
+      externalStatusOptions:[],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -886,6 +948,7 @@ export default {
         videoId: null,
         nickName: null,
         logType: 2,
+        externalStatus:null,
         qwExternalContactId: null,
         externalUserName:null,
         duration: null,
@@ -937,6 +1000,9 @@ export default {
     });
     this.getDicts("sys_course_project").then(response => {
       this.projectOptions = response.data;
+    });
+    this.getDicts("sys_qw_external_contact_status").then(response => {
+      this.externalStatusOptions = response.data;
     });
        // 查询营期名称
     listPeriodLabel().then(response => {
@@ -952,6 +1018,21 @@ export default {
 
   },
   methods: {
+    copyText(text, event) {
+      const clipboard = new ClipboardJS(event.currentTarget, {
+        text: () => text,
+      });
+
+      clipboard.on('success', (e) => {
+        this.$message.success('复制成功');
+        clipboard.destroy();
+      });
+
+      clipboard.on('error', (e) => {
+        this.$message.error('复制失败,请手动复制');
+        clipboard.destroy();
+      });
+    },
     setToday(){
       const today = new Date();
       const todayStart = new Date(today - 60*60*24*7*1000) ;
@@ -963,6 +1044,14 @@ export default {
       this.queryParams.sTime = this.formatDate(todayStart);
       this.queryParams.eTime = this.formatDate(todayEnd);
     },
+    showContentDialog(questionJson){
+      // 解析 JSON 字符串为 JavaScript 对象
+      // 替换非法换行符等控制字符
+      const sanitizedJson = questionJson.replace(/[\u0000-\u001F\u007F]/g, '');
+      this.contentDialog.json = JSON.parse(sanitizedJson);
+
+      this.contentDialog.isDialogVisible = true;
+    },
 
     handleSendTypeChange() {
       // 重置相关参数
@@ -1260,6 +1349,7 @@ export default {
         userId: null,
         videoId: null,
         logType: null,
+        externalStatus:null,
         createTime: null,
         updateTime: null,
         qwExternalContactId: null,
@@ -1818,3 +1908,8 @@ export default {
   color: #606266;
 }
 </style>
+<style scoped>
+.el-icon-document-copy:hover {
+  color: #66b1ff; /* 悬停时的颜色 */
+}
+</style>

+ 97 - 0
src/views/crm/components/aiCallVoiceLog.vue

@@ -0,0 +1,97 @@
+<template>
+    <div>
+        <el-table border v-loading="loading" :data="list" >
+            <el-table-column label="ID" align="center" prop="voiceId" />
+            <el-table-column label="公司名" align="center" prop="companyName" />
+            <el-table-column label="员工姓名" align="center" prop="userNickName" />
+            <el-table-column label="录制地址" align="center"  show-overflow-tooltip prop="voiceUrl" width="350">
+                <template slot-scope="scope">
+                    <audio  v-if="scope.row.voiceUrl!=null"   controls :src="scope.row.voiceUrl"></audio>
+                </template>
+            </el-table-column>
+            <el-table-column label="开始时间" align="center" prop="startTime" width="180">
+                <template slot-scope="scope">
+                <span>{{ parseTime(scope.row.startTime) }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="结束时间" align="center" prop="finishTime" width="180">
+                <template slot-scope="scope">
+                <span>{{ parseTime(scope.row.finishTime) }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="主叫" align="center" prop="callerPhone" />
+            <el-table-column label="被叫" align="center" prop="calleePhone" />
+            <el-table-column label="时长(秒)" align="center" prop="times" width="180">
+                <template slot-scope="scope">
+                <span v-if="scope.row.voiceUrl!=null">{{ scope.row.times}}秒 </span>
+                </template>
+            </el-table-column>
+            <el-table-column label="计费时长(分)" align="center" prop="billingTime" width="180">
+            </el-table-column>
+            <el-table-column label="主叫显示号" align="center" prop="displayCallerNumber" />
+            <el-table-column label="被叫显示号" align="center" prop="displayCalleeNumber" />
+            <el-table-column label="状态" align="center" prop="status" >
+                <template slot-scope="scope">
+                    <el-tag prop="status" v-for="(item, index) in statusOptions"    v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column label="备注" align="center" prop="remark" />
+        </el-table>
+        <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+        />
+
+    </div>
+</template>
+  
+<script>
+import { listCompanyVoiceLogs, getCompanyVoiceLogs, delCompanyVoiceLogs, addCompanyVoiceLogs, updateCompanyVoiceLogs, exportCompanyVoiceLogs } from "@/api/company/companyVoiceLogs";
+export default {
+        name: "customerVisit",
+        data() {
+            return {
+                 
+                statusOptions:[],
+                // 遮罩层
+                loading: true,
+                // 总条数
+                total: 0,
+                list: [],
+                // 查询参数
+                queryParams: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    customerId: null,
+                },
+            };
+        },
+        created() {
+            this.getDicts("company_voice_logs_status").then((response) => {
+                this.statusOptions = response.data;
+            });
+          
+        },
+        methods: {
+            getData(customerId){
+                this.queryParams.customerId=customerId;
+                this.queryParams.pageNum=1;
+                this.getList();
+            },
+            getList() {
+                this.loading = true;
+                listCompanyVoiceLogs(this.queryParams).then(response => {
+                    this.list = response.rows;
+                    this.total = response.total;
+                    this.loading = false;
+                });
+            },
+        }
+    };
+</script>
+<style lang="scss" scoped> 
+</style>
+ 

+ 25 - 3
src/views/crm/components/customerDetails.vue

@@ -72,8 +72,8 @@
             </el-descriptions-item>
 
             <el-descriptions-item label="标签" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.tags}}
+                <span v-if="item!=null && item.tags != null">
+                    <el-tag v-for="tag in item.tags.split(',')" size="mini">{{ tag }}</el-tag>
                 </span>
                 <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
             </el-descriptions-item>
@@ -108,6 +108,24 @@
                 </span>
                 <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
             </el-descriptions-item>
+          <el-descriptions-item label="购买渠道" label-class-name="my-label">
+                <span v-if="item!=null">
+                    {{item.platformName || ''}}
+                </span>
+
+          </el-descriptions-item>
+          <el-descriptions-item label="购买商品" label-class-name="my-label">
+                <span v-if="item!=null">
+                    {{item.goodsName || ''}} - {{item.goodsSpecification || ''}}
+                </span>
+
+          </el-descriptions-item>
+          <el-descriptions-item label="购买店铺" label-class-name="my-label">
+                <span v-if="item!=null">
+                    {{item.shopName || ''}}
+                </span>
+
+          </el-descriptions-item>
             <el-descriptions-item label="消费金额" label-class-name="my-label">
                 <span v-if="item!=null">
                     {{item.payMoney}}
@@ -176,6 +194,9 @@
             <el-tab-pane label="历史订单" name="hisOrder">
                 <customer-his-order-list ref="hisOrder"></customer-his-order-list>
             </el-tab-pane>
+            <el-tab-pane label="AI通话记录" name="aiVoiceLogs">
+                <ai-call-voice-log ref="aiVoiceRef"></ai-call-voice-log>
+            </el-tab-pane>
         </el-tabs>
 
         <el-dialog :title="addTag.title" :visible.sync="addTag.open" width="600px" append-to-body>
@@ -213,6 +234,7 @@
     import duplicateCustomer from '../components/duplicateCustomer.vue';
     import customerContacts from './customerContacts.vue';
     import customerHisOrderList from '../components/customerHisOrderList.vue';
+    import aiCallVoiceLog from './aiCallVoiceLog';
     import { getCustomerDetails1,updateCustomer,getCustomer1 } from "@/api/crm/customer";
     import addTag from './addTag.vue';
     import addRemark from './addRemark.vue';
@@ -220,7 +242,7 @@
     import addOrEditCustomer from '../components/addOrEditCustomer.vue';
     export default {
         name: "customer",
-        components: {customerHisOrderList,addOrEditCustomer,addSms,addTag,addRemark, customerContacts,customerVisitList,customerLogsList,customerVoiceLogsList,customerStoreOrderList,customerSmsLogsList,duplicateCustomer },
+        components: {customerHisOrderList,addOrEditCustomer,addSms,addTag,addRemark, customerContacts,customerVisitList,customerLogsList,customerVoiceLogsList,customerStoreOrderList,customerSmsLogsList,duplicateCustomer,aiCallVoiceLog },
         data() {
             return {
                 customer:{

+ 15 - 15
src/views/crm/components/duplicateCustomer.vue

@@ -74,7 +74,7 @@
                 </span>
                 <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
             </el-descriptions-item>
-           
+
             <el-descriptions-item label="进线日期" label-class-name="my-label">
                 <span v-if="item!=null">
                     {{item.registerDate}}
@@ -147,7 +147,7 @@
                 </span>
                 <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
             </el-descriptions-item>
-           
+
         </el-descriptions>
 
         <el-tabs style="margin-top:15px;"  z-index = "99" type="border-card" v-model="activeName" @tab-click="handleClick">
@@ -160,7 +160,7 @@
             <el-tab-pane label="订单记录" name="storeOrder">
                 <customer-store-order-list ref="storeOrder"></customer-store-order-list>
             </el-tab-pane>
-           
+
             <el-tab-pane label="通话记录" name="voiceLogs">
                 <customer-voice-logs-list ref="voiceLogs"></customer-voice-logs-list>
             </el-tab-pane>
@@ -171,7 +171,7 @@
                 <customer-logs-list ref="logs"></customer-logs-list>
             </el-tab-pane>
         </el-tabs>
-       
+
         <el-dialog :title="addTag.title" :visible.sync="addTag.open" width="600px" append-to-body>
             <add-tag ref="tag" @close="closeTag()"></add-tag>
         </el-dialog>
@@ -192,7 +192,7 @@
 
     </div>
 </template>
-  
+
 <script>
     import { listCustomerExt } from "@/api/crm/customerExt";
     import customerVisitList from '../components/customerVisitList.vue';
@@ -255,7 +255,7 @@
                 item:null,
                 showDuplicate:false,
                 dCustomerId:null,
-                 
+
             };
         },
         created() {
@@ -277,10 +277,10 @@
             this.getDicts("crm_customer_is_receive").then((response) => {
                 this.receiveOptions = response.data;
             });
-            
+
         },
         mounted(){
-           
+
         },
         methods: {
             handleEdit() {
@@ -310,7 +310,7 @@
                 setTimeout(() => {
                     that.$refs.sms.reset(this.item.customerId,mobile);
                 }, 500);
-                
+
             },
             closeRemark(){
                 this.addRemark.open=false;
@@ -333,7 +333,7 @@
                 setTimeout(() => {
                     that.$refs.tag.reset(this.item);
                 }, 500);
-                
+
             },
             handleClick(tab, event) {
                 if(tab.name=="contacts"){
@@ -378,14 +378,14 @@
                                     item.value=element.value
                                 }
                             });
-                           
+
                         });
                     }
                     this.activeName="visit"
                     setTimeout(() => {
                         that.$refs.visit.getData(customerId);
                     }, 500);
-                    
+
                 });
             },
         }
@@ -396,7 +396,7 @@
     height: 100%;
     background-color: #fff;
     padding: 0px 20px;
-        
+
 }
 .customer-title{
     margin-bottom: 15px;
@@ -412,5 +412,5 @@
   .el-descriptions-item__label.is-bordered-label{
     font-weight: normal;
   }
-  
-</style>
+
+</style>

+ 19 - 19
src/views/crm/components/lineCustomerDetails.vue

@@ -80,7 +80,7 @@
                 </span>
                 <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
             </el-descriptions-item>
-           
+
             <el-descriptions-item label="进线日期" label-class-name="my-label">
                 <span v-if="item!=null">
                     {{item.registerDate}}
@@ -153,7 +153,7 @@
                 </span>
                 <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
             </el-descriptions-item>
-           
+
         </el-descriptions>
 
         <el-tabs style="margin-top:15px;"  z-index = "99" type="border-card" v-model="activeName" @tab-click="handleClick">
@@ -166,7 +166,7 @@
             <el-tab-pane label="订单记录" name="storeOrder">
                 <customer-store-order-list ref="storeOrder"></customer-store-order-list>
             </el-tab-pane>
-           
+
             <el-tab-pane label="通话记录" name="voiceLogs">
                 <customer-voice-logs-list ref="voiceLogs"></customer-voice-logs-list>
             </el-tab-pane>
@@ -180,7 +180,7 @@
                 <customer-his-order-list ref="hisOrder"></customer-his-order-list>
             </el-tab-pane>
         </el-tabs>
-       
+
         <el-dialog :title="addTag.title" :visible.sync="addTag.open" width="600px" append-to-body>
             <add-tag ref="tag" @close="closeTag()"></add-tag>
         </el-dialog>
@@ -205,7 +205,7 @@
 
     </div>
 </template>
-  
+
 <script>
     import { listCustomerExt } from "@/api/crm/customerExt";
     import customerVisitList from '../components/customerVisitList.vue';
@@ -270,7 +270,7 @@
                 repetition:null,
                 showDuplicate:false,
                 dCustomerId:null,
-                 
+
             };
         },
         created() {
@@ -292,10 +292,10 @@
             this.getDicts("crm_customer_is_receive").then((response) => {
                 this.receiveOptions = response.data;
             });
-            
+
         },
         mounted(){
-           
+
         },
         methods: {
             handleShow(repetition){
@@ -328,7 +328,7 @@
                 setTimeout(() => {
                     that.$refs.sms.reset(this.item.customerId,mobile);
                 }, 500);
-                
+
             },
             closeRemark(){
                 this.addRemark.open=false;
@@ -351,7 +351,7 @@
                 setTimeout(() => {
                     that.$refs.tag.reset(this.item);
                 }, 500);
-                
+
             },
             handleClick(tab, event) {
                 if(tab.name=="contacts"){
@@ -371,7 +371,7 @@
                 }
                 if(tab.name=="smsLogs"){
                     this.$refs.smsLogs.getData(this.item.customerId);
-                }  
+                }
                 if(tab.name=="hisOrder"){
                     this.$refs.hisOrder.getData(this.item.customerId);
                 }
@@ -400,25 +400,25 @@
                                     item.value=element.value
                                 }
                             });
-                           
+
                         });
                     }
                     this.activeName="visit"
                     setTimeout(() => {
                         that.$refs.visit.getData(customerId);
                     }, 500);
-                    
+
                 });
             },
             initDuplicate(isDuplicate,dCustomerId){
-                 
+
                 this.showDuplicate=isDuplicate;
                 this.dCustomerId=dCustomerId;
             },
             handleDuplicate(){
                 this.duplicate.open=true;
                 var that=this;
-               
+
                 setTimeout(() => {
                     that.$refs.duplicateCustomer.getDetails(that.dCustomerId);
                 }, 200);
@@ -427,7 +427,7 @@
                 this.duplicate.open=false;
                 this.getDetails(this.customerId)
             }
-        
+
         }
     };
 </script>
@@ -436,7 +436,7 @@
     height: 100%;
     background-color: #fff;
     padding: 0px 20px;
-        
+
 }
 .customer-title{
     margin-bottom: 15px;
@@ -452,5 +452,5 @@
   .el-descriptions-item__label.is-bordered-label{
     font-weight: normal;
   }
-  
-</style>
+
+</style>

+ 732 - 5
src/views/hisStore/components/productOrder.vue

@@ -156,13 +156,34 @@
 
       <div style="margin-top: 20px">
         <span class="font-small">商品信息</span>
+        <el-button
+          class="select-product-btn"
+          @click="openProductSelection"
+          icon="el-icon-shopping-cart-2"
+          size="small"
+          type="primary"
+          v-hasPermi="['store:storeOrderItem:add']" >
+          新增商品
+        </el-button>
+        <el-button
+          class="remove-product-btn"
+          @click="removeSelectedProduct"
+          icon="el-icon-delete"
+          size="small"
+          type="danger"
+          v-hasPermi="['store:storeOrderItem:remove']">
+          移除商品
+        </el-button>
       </div>
       <el-table
+        ref="itemsTable"
         border
         v-if="items!=null"
         :data="items"
         size="small"
-        style="width: 100%;margin-top: 20px" >
+        style="width: 100%;margin-top: 20px"
+        @selection-change="handleItemsSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="商品图片" width="150" align="center">
           <template slot-scope="scope">
             <img :src="JSON.parse(scope.row.jsonInfo).image" style="height: 80px">
@@ -185,7 +206,20 @@
         </el-table-column>
         <el-table-column label="数量" width="180" align="center">
           <template slot-scope="scope">
-            {{scope.row.num}}
+            <div class="quantity-cell">
+              <div class="quantity-display">
+                <span class="quantity-value">{{scope.row.num}}</span>
+              </div>
+              <el-button
+                size="mini"
+                type="default"
+                icon="el-icon-edit"
+                class="edit-quantity-btn"
+                @click="showQuantityEdit(scope)"
+                v-hasPermi="['store:storeOrderItem:updateNum']">
+                修改数量
+              </el-button>
+            </div>
           </template>
         </el-table-column>
         <el-table-column label="小计"  align="center">
@@ -485,25 +519,297 @@
     <el-dialog :title="addSms.title" :visible.sync="addSms.open" width="800px" append-to-body>
         <add-sms ref="sms" @close="closeSms()"></add-sms>
     </el-dialog>
+
+    <!-- 数量修改弹窗 -->
+    <el-dialog :title="quantityDialog.title" :visible.sync="quantityDialog.open" width="500px" append-to-body>
+      <el-form ref="quantityForm" :model="quantityForm" :rules="quantityRules" label-width="100px">
+        <el-form-item label="商品名称">
+          <span class="dialog-product-name">{{quantityForm.productName}}</span>
+        </el-form-item>
+
+        <el-form-item label="当前单价">
+          <el-tag type="info" size="medium">¥{{ quantityForm.price ? quantityForm.price.toFixed(2) : '0.00' }}</el-tag>
+        </el-form-item>
+
+        <el-form-item label="当前数量">
+          <el-tag type="info" size="medium">{{ quantityForm.originalNum }}</el-tag>
+        </el-form-item>
+
+        <el-form-item label="新数量" prop="newNum">
+          <el-input-number
+            v-model="quantityForm.newNum"
+            :min="1"
+            :max="999999"
+            controls-position="right"
+            style="width: 200px">
+          </el-input-number>
+        </el-form-item>
+
+        <el-form-item label="总金额">
+          <el-tag type="danger" size="medium">
+            ¥{{ (quantityForm.newNum * quantityForm.price).toFixed(2) }}
+          </el-tag>
+        </el-form-item>
+      </el-form>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="quantityDialog.open = false">取 消</el-button>
+        <el-button type="primary" @click="submitQuantityForm">确 定</el-button>
+      </div>
+    </el-dialog>
+    <!-- 新增商品弹窗 -->
+    <el-dialog :title="productOrderDialog.title" :visible.sync="productOrderDialog.open" width="1800px" append-to-body>
+      <div class="app-container">
+        <el-form :model="productOrderQueryParams" ref="productOrderQueryForm" :inline="true" label-width="68px">
+          <el-form-item label="商品分类" prop="cateId">
+            <treeselect  v-model="productOrderQueryParams.cateId"  style="width:205.4px" :options="categoryOptions" :normalizer="normalizer" placeholder="请选择分类" />
+          </el-form-item>
+          <el-form-item label="商品名称" prop="productName">
+            <el-input
+              v-model="productOrderQueryParams.productName"
+              placeholder="请输入商品名称"
+              clearable
+              size="small"
+              @keyup.enter.native="productOrderHandleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="商品编号" prop="barCode">
+            <el-input
+              v-model="productOrderQueryParams.barCode"
+              placeholder="请输入商品编号"
+              clearable
+              size="small"
+              @keyup.enter.native="productOrderHandleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="商品类型" prop="productType">
+            <el-select   v-model="productOrderQueryParams.productType" placeholder="请选择商品类型" clearable size="small" >
+              <el-option
+                v-for="item in productTypeOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="所属公司">
+            <el-select style="width: 240px" v-model="companyId" multiple placeholder="请选择企业" clearable size="small" >
+              <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="所属店铺" v-if="this.isStores">
+            <el-select style="width: 240px" v-model="productOrderQueryParams.storeIds" placeholder="请选择店铺" clearable size="small" >
+              <el-option
+                v-for="item in storeOptions"
+                :key="item.storeId"
+                :label="item.storeName"
+                :value="item.storeId"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="cyan" icon="el-icon-search" size="mini" @click="productOrderHandleQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="productOrderResetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table
+          ref="productOrderTable"
+          height="500"
+          border
+          v-loading="productOrderLoading"
+          :data="storeProductList"
+          @selection-change="handleProductSelectionChange">
+          <el-table-column type="selection" width="55" align="center" />
+          <el-table-column label="ID" align="center" prop="productId" />
+          <el-table-column label="商品图片" align="center" width="120">
+            <template slot-scope="scope">
+              <el-popover
+                placement="right"
+                title=""
+                trigger="hover">
+                <img slot="reference" :src="scope.row.image" width="100">
+                <img :src="scope.row.image" style="max-width: 150px;">
+              </el-popover>
+            </template>
+          </el-table-column>
+          <el-table-column label="商品名称" show-overflow-tooltip align="center" prop="productName" />
+          <el-table-column label="分类" align="center" prop="cateName" />
+          <el-table-column label="所属公司" align="center" prop="companyName" />
+          <el-table-column label="所属店铺" align="center" prop="storeName" v-if="this.isStores"/>
+          <el-table-column label="售价" align="center" prop="price" >
+            <template slot-scope="scope" >
+              <span v-if="scope.row.price!=null">{{scope.row.price.toFixed(2)}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="原价" align="center" prop="otPrice" >
+            <template slot-scope="scope" >
+              <span v-if="scope.row.otPrice!=null">{{scope.row.otPrice.toFixed(2)}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="销量" align="center" prop="sales" />
+          <el-table-column label="库存" align="center" prop="stock" />
+          <el-table-column label="类型" align="center" prop="productType" >
+            <template slot-scope="scope">
+              <el-tag prop="productType" v-for="(item, index) in productTypeOptions"    v-if="scope.row.productType==item.dictValue">{{item.dictLabel}}</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="状态" align="center" prop="isShow" >
+            <template slot-scope="scope">
+              <el-tag :type="getStatusType(scope.row)" prop="status">
+                {{ getStatusText(scope.row) }}
+              </el-tag>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination
+          v-show="total>0"
+          :total="total"
+          :page.sync="productOrderQueryParams.pageNum"
+          :limit.sync="productOrderQueryParams.pageSize"
+          @pagination="productOrderGetList"
+        />
+
+        <div style="text-align: center; margin-top: 20px;">
+          <el-button
+            type="primary"
+            size="medium"
+            icon="el-icon-plus"
+            @click="handleBatchAdd"
+            v-hasPermi="['store:storeOrderItem:add']"
+            :disabled="!ids || ids.length === 0">
+            批量添加商品
+          </el-button>
+        </div>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script>
+import {
+  getExpress,
+  getStoreOrder,
+  getStoreOrderAddress,
+  updateStoreOrder,
+  updateStoreOrderItemJson,
+  bindCustomer,
+  uploadCredentials,
+  getUserPhone
+} from "@/api/hisStore/storeOrder";
+import {listStoreProduct} from "@/api/hisStore/storeProduct";
 import {updateUser,getUser } from "@/api/users/user";
 import { getTcmScheduleList } from "@/api/company/tcmScheduleReport";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import {getAllStoreProductCategory} from "@/api/hisStore/storeProductCategory";
+import Editor from '@/components/Editor/wang';
+import singleImg from '@/components/Material/single'
+import {getCompanyList} from "@/api/company/company";
+import {listStore} from '@/api/hisStore/store';
+import {addStoreOrderItem, delStoreOrderItem, updateNumStoreOrderItem} from "../../../api/hisStore/storeOrderItem";
 import {getCustomerListBySearch } from "@/api/crm/customer";
 import ImageUpload from '@/components/ImageUpload'
 import Material from '@/components/Material'
-import {bindCustomer,getExpress, listStoreOrder, getStoreOrder, delStoreOrder, addStoreOrder, updateStoreOrder, exportStoreOrder,uploadCredentials, getStoreOrderAddress,getUserPhone} from "@/api/hisStore/storeOrder";
 import {getCitys} from "@/api/hisStore/city";
 import customerDetails from '../../crm/components/customerDetails.vue';
 import addSms from '../../crm/components/addSms.vue';
 export default {
   name: "order",
-  components: {customerDetails,
-    ImageUpload,Material ,addSms},
+  components: {customerDetails,ImageUpload,Material ,addSms,Treeselect,Editor,singleImg},
   data() {
     return {
+      // 遮罩层
+      productOrderLoading: true,
+      isStores: true,
+      companyId: null,
+      storeId: null,
+      isAudit: null,
+      storeForm: {isAudit:1,status:1},
+      // 总条数
+      total: 0,
+      // 商品表格数据
+      storeProductList: [],
+      productTypeOptions:[],
+      productTuiCateOptions:[],
+      isDisplayOptions:[],
+      isGoodOptions:[],
+      isNewOptions:[],
+      isBestOptions:[],
+      isHotOptions:[],
+      isShowOptions:[],
+      categoryOptions:[],
+      // 企业列表
+      companyOptions:[],
+      storeOptions:[],
+      // 选中的商品列表
+      selectedItems: [],
+      // 批量添加时选中的商品ID列表
+      ids: [],
+      // 是否单选
+      single: true,
+      // 是否多选
+      multiple: true,
+      // 查询参数
+      productOrderQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        productName: null,
+        productType: null,
+        isShow: "1",
+        barCode:null,
+        companyIds: null,
+        storeIds: null,
+        drugRegCertNo: null,
+        commonName: null,
+        dosageForm: null,
+        unitPrice: null,
+        batchNumber: null,
+        mah: null,
+        mahAddress: null,
+        manufacturer: null,
+        manufacturerAddress: null,
+        indications: null,
+        dosage: null,
+        adverseReactions: null,
+        contraindications: null,
+        precautions: null,
+        excludeProductIds:[],
+      },
+      productOrderDialog:{
+        title:"商品选择",
+        open:false,
+      },
+      // 数量修改弹窗相关数据
+      quantityDialog: {
+        title: "修改商品数量",
+        open: false,
+      },
+      quantityForm: {
+        itemId: null,
+        productName: null,
+        price: null,
+        //新数量
+        newNum: null,
+        //原始数量
+        originalNum: null
+      },
+      quantityRules: {
+        newNum: [
+          { required: true, message: "数量不能为空", trigger: "blur" },
+          { type: 'number', min: 1, message: "数量至少为1", trigger: "blur" },
+          { type: 'number', max: 999999, message: "数量不能超过999999", trigger: "blur" }
+        ]
+      },
+      // 删除商品相关
+      removeProductLoading: false,
+
       customerUserStatusOptions:[],
       scheduleOptions:[],
       dialogVisibleImage: false,
@@ -631,6 +937,283 @@ export default {
     }
   },
   methods: {
+    // 显示修改数量弹窗
+    showQuantityEdit(scope) {
+      this.quantityForm.itemId = scope.row.itemId;
+      // 解析商品信息并处理可能的错误
+      let parsedJsonInfo;
+      try {
+        parsedJsonInfo = JSON.parse(scope.row.jsonInfo);
+      } catch (error) {
+        console.error('解析商品信息失败:', error);
+        parsedJsonInfo = {};
+      }
+
+      this.quantityForm.productName = parsedJsonInfo.productName || '';
+      this.quantityForm.originalNum = scope.row.num || 0;
+      this.quantityForm.newNum = scope.row.num || 0;
+
+      // 处理价格,确保不会为null
+      const price = parsedJsonInfo.price || 0;
+      this.quantityForm.price = parseFloat(price) || 0;
+      this.quantityDialog.open = true;
+    },
+
+    // 提交数量修改
+    submitQuantityForm() {
+      this.$refs["quantityForm"].validate(valid => {
+        if (valid) {
+          // 验证数量是否发生变化
+          if (this.quantityForm.newNum === this.quantityForm.originalNum) {
+            this.msgInfo("数量未发生变化,无需修改");
+            return;
+          }
+
+          updateNumStoreOrderItem(this.quantityForm).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("数量修改成功");
+              updateStoreOrderItemJson(this.order.id,1);
+              this.quantityDialog.open = false;
+              this.getOrder(this.order.id);
+            }else{
+              this.msgError(response.message);
+            }
+          }).catch(error => {
+            this.$message.error('请求失败: ' + error.message)
+          });
+        }
+      });
+    },
+
+    openProductSelection(){
+      this.productOrderDialog.open=true;
+
+      // 将已有的productId存入查询参数,用于后端过滤 (返回数组格式)
+      this.productOrderQueryParams.excludeProductIds = this.items.map(item => item.productId).filter(productId => productId);
+
+      // 加载字典和其他数据
+      this.getDicts("store_product_tui_cate").then((response) => {
+        this.productTuiCateOptions = response.data;
+      });
+      this.getDicts("store_product_enable").then((response) => {
+        this.isNewOptions = response.data;
+        this.isBestOptions = response.data;
+        this.isHotOptions = response.data;
+        this.isGoodOptions=response.data;
+        this.isDisplayOptions=response.data;
+      });
+      this.getDicts("store_product_type").then((response) => {
+        this.productTypeOptions = response.data;
+        if(!this.isMedicalMall &&
+          this.productTypeOptions.length === 4){
+          //删除后两项
+          this.productTypeOptions.splice(2,2);
+        }
+      });
+      this.getDicts("store_product_is_show").then((response) => {
+        this.isShowOptions = response.data;
+      });
+      getCompanyList().then(response => {
+        this.companyOptions = response.data;
+      });
+
+      listStore(this.storeForm).then(response => {
+        this.storeOptions = response.rows;
+      });
+      this.getTreeselect();
+      this.productOrderGetList();
+    },
+
+    /** 商品表格选择变化 */
+    handleItemsSelectionChange(selection) {
+      this.selectedItems = selection;
+    },
+
+    /** 移除选中的商品 */
+    removeSelectedProduct() {
+      if (this.selectedItems.length === 0) {
+        this.msgInfo("请先选择要移除的商品");
+        return;
+      }
+
+      const that = this;
+      this.$confirm('确定要移除选中的 ' + this.selectedItems.length + ' 个商品吗?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        that.removeProductLoading = true;
+        // 收集所有要删除的商品ID
+        const deletePromises = that.selectedItems.map(item => {
+          return delStoreOrderItem(item.itemId);
+        });
+
+        // 并行删除所有选中的商品
+        Promise.all(deletePromises).then(responses => {
+          // 检查所有删除操作是否成功
+          const allSuccess = responses.every(response => response.code === 200);
+          if (allSuccess) {
+            that.msgSuccess("商品移除成功");
+            // 清除选择并刷新订单数据
+            that.selectedItems = [];
+            updateStoreOrderItemJson(this.order.id,1);
+            that.getOrder(that.order.id);
+          } else {
+            that.msgError("商品移除失败: " + (responses.message));
+          }
+        }).catch(error => {
+          that.msgError("移除商品失败: " + (error.message || "网络错误"));
+        })
+      }).catch(() => {
+        // 用户取消操作
+      });
+    },
+
+    /** 查询商品列表 */
+    productOrderGetList() {
+      this.productOrderLoading = true;
+      listStoreProduct(this.productOrderQueryParams).then(response => {
+        this.storeProductList = response.rows;
+        this.total = response.total;
+        this.productOrderLoading = false;
+      }).catch(error => {
+        console.error('获取商品列表失败:', error);
+        this.productOrderLoading = false;
+        this.storeProductList = [];
+        this.total = 0;
+      });
+    },
+
+    /** 批量添加商品到订单 */
+    handleBatchAdd() {
+      if (!this.order || !this.order.id) {
+        this.msgInfo("请先选择订单");
+        return;
+      }
+
+      if (!this.ids || this.ids.length === 0) {
+        this.msgInfo("请先选择要添加的商品");
+        return;
+      }
+
+      const that = this;
+      this.$confirm(`确定要将选中的 ${this.ids.length} 个商品添加到订单中吗?`, "确认添加", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "info"
+      }).then(() => {
+        // 获取选中的商品列表
+        const selectedProducts = this.storeProductList.filter(product =>
+          this.ids.includes(product.productId)
+        );
+
+        // 创建批量添加的订单项数据
+        const batchAddPromises = selectedProducts.map(product => {
+          const orderItemData = {
+            orderId: this.order.id,
+            orderCode: this.order.orderCode,
+            cartId: null,
+            productId: product.productId,
+            num: 1, // 默认数量为1
+            jsonInfo: JSON.stringify({
+              image: product.image,
+              productId: product.productId,
+              num: 1, // 默认数量为1
+              productName: product.productName,
+              barCode: product.barCode,
+              price: product.price,
+              sku: product.sku || '默认'
+            })
+          };
+          return addStoreOrderItem(orderItemData);
+        });
+
+        // 并行添加所有选中的商品
+        Promise.all(batchAddPromises)
+          .then(responses => {
+            // 检查所有添加操作是否成功
+            const allSuccess = responses.every(response => response.code === 200);
+            if (allSuccess) {
+              that.msgSuccess(`成功添加 ${responses.length} 个商品`);
+
+              // 更新过滤列表,包含新添加的商品ID
+              const newIds = selectedProducts.map(p => p.productId);
+              const currentIds = this.productOrderQueryParams.excludeProductIds || [];
+              const updatedIds = [...new Set([...currentIds, ...newIds])]; // 去重
+              this.productOrderQueryParams.excludeProductIds = updatedIds;
+              updateStoreOrderItemJson(this.order.id,1);
+              this.productOrderDialog.open = false;
+              that.getOrder(that.order.id);
+            } else {
+              const failedCount = responses.filter(r => r.code !== 200).length;
+              that.msgError(`添加失败 ${failedCount} 个商品`);
+            }
+          })
+          .catch(error => {
+            that.msgError("批量添加商品失败: " + (error.message || "网络错误"));
+          });
+      }).catch(() => {
+        // 用户取消操作
+      });
+    },
+
+    // 多选框选中数据
+    handleProductSelectionChange(selection) {
+      this.ids = selection.map(item => item.productId).filter(id => id); // 过滤空值
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length
+    },
+    /** 搜索按钮操作 */
+    productOrderHandleQuery() {
+      this.productOrderQueryParams.pageNum = 1;
+      this.productOrderQueryParams.isShow = 1;
+      this.productOrderQueryParams.companyIds = this.companyId +''
+      this.productOrderGetList();
+    },
+    /** 重置按钮操作 */
+    productOrderResetQuery() {
+      this.resetForm("productOrderQueryForm");
+      // 重置所属公司
+      this.companyId = null;
+      // 重置所属店铺
+      this.productOrderQueryParams.storeIds = null;
+      this.productOrderQueryParams.isShow = 1;
+      this.productOrderQueryParams.companyIds = null;
+      this.productOrderGetList();
+    },
+
+    /** 转换商品分类数据结构 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.cateId,
+        label: node.cateName,
+        children: node.children
+      };
+    },
+    getStatusType(row) {
+      if (row.isAudit == 0) {
+        return 'warning';
+      }
+      // 根据你的业务逻辑返回不同的类型,如:success, danger, info等
+      return row.isShow == 1 ? 'success' : 'info';
+    },
+    getStatusText(row) {
+      if (row.isAudit == 0) {
+        return '待审核';
+      }
+      const option = this.isShowOptions.find(item => item.dictValue == row.isShow);
+      return option ? option.dictLabel : '未知状态';
+    },
+    getTreeselect() {
+      getAllStoreProductCategory().then(response => {
+        this.categoryOptions = [];
+        this.categoryOptions=this.handleTree(response.data, "cateId", "pid");
+      });
+    },
+
     closeSms(){
       this.addSms.open=false;
     },
@@ -715,6 +1298,7 @@ export default {
     },
     showExpress(){
       this.expressDialog.open=true;
+      this.traces = [];
       getExpress(this.orderId).then(response => {
           this.express = response.data;
           if(this.express!=null&&this.express.Traces!=null){
@@ -973,4 +1557,147 @@ export default {
   font-size: 14px;
   color: #303133;
 }
+.container {
+  position: relative;
+}
+.select-product-btn {
+  float: right;
+  margin-top: -5px;
+  margin-right: 15px;
+  background: linear-gradient(135deg, #409EFF, #337AB7);
+  border: none;
+  color: white;
+  border-radius: 6px;
+  padding: 8px 16px;
+  font-weight: 500;
+  box-shadow: 0 3px 6px rgba(64, 158, 255, 0.2);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.select-product-btn:hover {
+  background: linear-gradient(135deg, #66b1ff, #409EFF);
+  transform: translateY(-2px);
+  box-shadow: 0 5px 12px rgba(64, 158, 255, 0.35);
+}
+
+.select-product-btn:active {
+  transform: translateY(0);
+  box-shadow: 0 2px 4px rgba(64, 158, 255, 0.2);
+}
+
+.select-product-btn:focus {
+  outline: none;
+  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.3);
+}
+
+.select-product-btn:disabled {
+  background: linear-gradient(135deg, #a0cfff, #b3d8ff);
+  cursor: not-allowed;
+  transform: none;
+  box-shadow: none;
+}
+
+.remove-product-btn {
+  float: right;
+  margin-top: -5px;
+  margin-right: 15px;
+  background: linear-gradient(135deg, #ff6b6b, #ee5a52);
+  border: none;
+  color: white;
+  border-radius: 6px;
+  padding: 8px 16px;
+  font-weight: 500;
+  box-shadow: 0 3px 6px rgba(255, 107, 107, 0.15);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.remove-product-btn:hover {
+  background: linear-gradient(135deg, #ff5252, #e74c3c);
+  transform: translateY(-2px);
+  box-shadow: 0 5px 12px rgba(255, 107, 107, 0.25);
+}
+
+.remove-product-btn:active {
+  transform: translateY(0);
+  box-shadow: 0 2px 4px rgba(255, 107, 107, 0.2);
+}
+
+.remove-product-btn:focus {
+  outline: none;
+  box-shadow: 0 0 0 3px rgba(255, 107, 107, 0.3);
+}
+
+.remove-product-btn:disabled {
+  background: linear-gradient(135deg, #ffcccc, #f8d7da);
+  cursor: not-allowed;
+  transform: none;
+  box-shadow: none;
+}
+
+.quantity-cell {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  padding: 0 5px;
+}
+
+.quantity-display {
+  display: flex;
+  align-items: center;
+  gap: 4px; /* 缩小数量与按钮之间的间距 */
+}
+
+.quantity-value {
+  font-weight: 600;
+  color: #606266;
+  background-color: #f5f7fa;
+  padding: 4px 8px;
+  border-radius: 4px;
+  min-width: 40px;
+  text-align: center;
+}
+
+.edit-quantity-btn {
+  margin-left: 4px; /* 缩小左边距 */
+  padding: 4px 8px;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  color: #409eff;
+  background: transparent;
+  cursor: pointer;
+  transition: all 0.2s ease;
+}
+
+.edit-quantity-btn:hover {
+  background-color: #ecf5ff;
+  border-color: #b3d8ff;
+  color: #66b1ff;
+  transform: translateY(-1px);
+}
+
+.edit-quantity-btn i {
+  margin-right: 2px;
+  font-size: 12px;
+}
+
+.edit-quantity-btn:hover {
+  background-color: #ecf5ff;
+  border-color: #b3d8ff;
+  color: #66b1ff;
+  transform: translateY(-1px);
+}
+
+.edit-quantity-btn i {
+  margin-right: 2px;
+  font-size: 12px;
+}
+.dialog-product-name {
+  font-weight: 500;
+  color: #303133;
+  word-break: break-all;
+  max-width: 350px;
+  display: inline-block;
+  vertical-align: middle;
+}
 </style>

+ 20 - 8
src/views/hisStore/storeOrder/list.vue

@@ -192,7 +192,7 @@
               v-hasPermi="['store:storeOrder:exportItems']"
             >导出订单明细</el-button>
           </el-col>
-          <el-col :span="1.5">
+          <!-- <el-col :span="1.5">
             <el-button
               type="success"
               icon="el-icon-s-check"
@@ -202,7 +202,7 @@
               v-hasPermi="['store:storeOrder:batchAudit']"
             >确认审核
             </el-button>
-          </el-col>
+          </el-col> -->
         <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
         </el-row>
         <el-tabs type="card" v-model="activeName" @tab-click="handleClick">
@@ -253,6 +253,11 @@
                   <span v-if="scope.row.payPrice!=null">{{scope.row.payPrice.toFixed(2)}}</span>
               </template>
           </el-table-column>
+          <el-table-column label="代收金额" align="center" prop="payDelivery" >
+            <template slot-scope="scope">
+              <span v-if="scope.row.payDelivery!=null">{{scope.row.payDelivery.toFixed(2)}}</span>
+            </template>
+          </el-table-column>
           <el-table-column label="下单时间" align="center" prop="createTime" />
           <!-- <el-table-column label="支付状态" align="center" prop="paid" /> -->
           <el-table-column label="支付时间" align="center" prop="payTime" width="180">
@@ -319,6 +324,12 @@
                 @click="handleDetails(scope.row)"
                 v-hasPermi="['store:storeOrder:query']"
               >查看</el-button>
+              <el-button
+                size="mini"
+                type="text"
+                @click="handleOrderAudit(scope.row)"
+                v-hasPermi="['store:storeOrder:batchAudit']"
+              >确认审核</el-button>
            <!--    <el-button
                 size="mini"
                 type="text"
@@ -992,17 +1003,18 @@ export default {
     },
 
     /** 订单确认审核 */
-    handleOrderAudit(){
-      if (this.ids.length === 0) {
-        this.$message.warning('请至少勾选一条订单进行审核');
-        return;
-      }
+    handleOrderAudit(row){
+      // if (this.ids.length === 0) {
+      //   this.$message.warning('请至少勾选一条订单进行审核');
+      //   return;
+      // }
+      const ids = [row.id];
       this.$confirm('是否确认审核选中的订单?', "提示", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning"
       }).then(() => {
-        return auditStoreOrder({ orderIds: this.ids, isAudit: 1 });
+        return auditStoreOrder({ orderIds: ids, isAudit: 1 });
       }).then((response) => {
         this.getList();
         this.msgSuccess(response.msg || "审核成功");

+ 4 - 4
src/views/qw/friendWelcome/deptFriendWelcome.vue

@@ -410,7 +410,7 @@
         <div v-if="welcomeItem.type==='link'">
 
           <el-form-item label="选择课程">
-            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
               <el-option
                 v-for="dict in courseList"
                 :key="dict.dictValue"
@@ -418,7 +418,7 @@
                 :value="parseInt(dict.dictValue)"
               />
             </el-select>
-            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
               <el-option
                 v-for="dict in videoList"
                 :key="dict.dictValue"
@@ -465,7 +465,7 @@
         <div v-if="welcomeItem.type==='miniprogram'">
 
           <el-form-item label="选择课程">
-            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
               <el-option
                 v-for="dict in courseList"
                 :key="dict.dictValue"
@@ -473,7 +473,7 @@
                 :value="parseInt(dict.dictValue)"
               />
             </el-select>
-            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
               <el-option
                 v-for="dict in videoList"
                 :key="dict.dictValue"

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

@@ -438,7 +438,7 @@
         <div v-if="welcomeItem.type==='link'">
 
           <el-form-item label="选择课程">
-            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
               <el-option
                 v-for="dict in courseList"
                 :key="dict.dictValue"
@@ -446,7 +446,7 @@
                 :value="parseInt(dict.dictValue)"
               />
             </el-select>
-            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
               <el-option
                 v-for="dict in videoList"
                 :key="dict.dictValue"
@@ -493,7 +493,7 @@
         <div v-if="welcomeItem.type==='miniprogram'">
 
           <el-form-item label="选择课程" prop="miniprogramCourseId">
-            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
               <el-option
                 v-for="dict in courseList"
                 :key="dict.dictValue"
@@ -501,7 +501,7 @@
                 :value="parseInt(dict.dictValue)"
               />
             </el-select>
-            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
               <el-option
                 v-for="dict in videoList"
                 :key="dict.dictValue"

+ 4 - 4
src/views/qw/friendWelcome/myIndexNew.vue

@@ -430,7 +430,7 @@
         <div v-if="welcomeItem.type==='link'">
 
           <el-form-item label="选择课程">
-            <el-select v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"
+            <el-select v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable
                        @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
               <el-option
                 v-for="dict in courseList"
@@ -439,7 +439,7 @@
                 :value="parseInt(dict.dictValue)"
               />
             </el-select>
-            <el-select v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;"
+            <el-select v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable
                        @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)">
               <el-option
                 v-for="dict in videoList"
@@ -489,7 +489,7 @@
         <div v-if="welcomeItem.type==='miniprogram'">
 
           <el-form-item label="选择课程">
-            <el-select v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"
+            <el-select v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable
                        @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
               <el-option
                 v-for="dict in courseList"
@@ -498,7 +498,7 @@
                 :value="parseInt(dict.dictValue)"
               />
             </el-select>
-            <el-select v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;"
+            <el-select v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable
                        @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)">
               <el-option
                 v-for="dict in videoList"

+ 4 - 4
src/views/qw/friendWelcome/myWelcome.vue

@@ -435,7 +435,7 @@
         <div v-if="welcomeItem.type==='link'">
 
           <el-form-item label="选择课程">
-            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
               <el-option
                 v-for="dict in courseList"
                 :key="dict.dictValue"
@@ -443,7 +443,7 @@
                 :value="parseInt(dict.dictValue)"
               />
             </el-select>
-            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
               <el-option
                 v-for="dict in videoList"
                 :key="dict.dictValue"
@@ -490,7 +490,7 @@
         <div v-if="welcomeItem.type==='miniprogram'">
 
           <el-form-item label="选择课程" prop="miniprogramCourseId">
-            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
               <el-option
                 v-for="dict in courseList"
                 :key="dict.dictValue"
@@ -498,7 +498,7 @@
                 :value="parseInt(dict.dictValue)"
               />
             </el-select>
-            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
               <el-option
                 v-for="dict in videoList"
                 :key="dict.dictValue"

+ 62 - 24
src/views/qw/sop/updateSop.vue

@@ -365,7 +365,19 @@
                 closable
                 :disable-transitions="false"
                 @close="handleClosegroupUser(id)">
-                <span v-for="list in companyUserList" :key="list.qwUserId" v-if="list.id==id">{{list.qwUserName}}</span>
+                <template>
+                  <!-- 匹配到对应项:展示用户名 -->
+                  <span
+                    v-for="list in companyUserList"
+                    :key="list.qwUserId"
+                    v-if="list.id == id">
+                      {{ list.qwUserName }}
+                  </span>
+                  <!-- 未匹配到任何项:直接展示userSelectList里的id(因为list无id,无法展示list.id) -->
+                  <span v-if="!companyUserList.some(list => list.qwUserId == id)">
+                    {{ id }}
+                  </span>
+                </template>
               </el-tag>
             </div>
           </el-form-item>
@@ -651,32 +663,58 @@ export default {
       // }
       // 找到对应的员工信息
       const user = this.companyUserList.find((list) => list.id == id);
-      console.log(user)
-      if (!user) return;
-      // 确认删除提醒
-      this.$confirm('确定要删除员工"'+user.qwUserName+'"吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning',
-      })
-        .then(() => {
-          // 用户点击确定
-          const index = this.userSelectList.findIndex((t) => t === id);
-          if (index !== -1) {
-            this.userSelectList.splice(index, 1);
-          }
-          this.$message({
-            type: 'success',
-            message: '删除成功',
+
+      if (!user){
+        const qwUser = this.companyQwUserList.find((list) => list.id == id);
+        // 确认删除提醒
+        this.$confirm('确定要删除未绑定公司的企微员工"'+qwUser.qwUserName+'"吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        }).then(() => {
+            // 用户点击确定
+            const index = this.userSelectList.findIndex((t) => t === id);
+            if (index !== -1) {
+              this.userSelectList.splice(index, 1);
+            }
+            this.$message({
+              type: 'success',
+              message: '删除成功',
+            });
+          })
+          .catch(() => {
+            // 用户点击取消
+            this.$message({
+              type: 'info',
+              message: '已取消删除',
+            });
           });
+      }else{
+        // 确认删除提醒
+        this.$confirm('确定要删除员工"'+user.qwUserName+'"吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
         })
-        .catch(() => {
-          // 用户点击取消
-          this.$message({
-            type: 'info',
-            message: '已取消删除',
+          .then(() => {
+            // 用户点击确定
+            const index = this.userSelectList.findIndex((t) => t === id);
+            if (index !== -1) {
+              this.userSelectList.splice(index, 1);
+            }
+            this.$message({
+              type: 'success',
+              message: '删除成功',
+            });
+          })
+          .catch(() => {
+            // 用户点击取消
+            this.$message({
+              type: 'info',
+              message: '已取消删除',
+            });
           });
-        });
+      }
     },
     // 取消按钮
     cancel() {

+ 19 - 4
src/views/store/components/userDetailsTemp.vue

@@ -100,7 +100,7 @@
       />
     </div>
 
-    <div class="contentx" v-if="item!=null">
+    <div class="contentx" v-if="item!=null && fsUserInfo !== 'gzzdy'">
       <div class="desct">
               <span v-if="patientInfo">
                 {{ patientInfo }}
@@ -120,19 +120,26 @@
       <userAddDetails  ref="userAddDetail" />
 
     </div>
-    <div class="contentx" v-if="item!=null" >
+    <div class="contentx" v-if="item!=null && fsUserInfo !== 'gzzdy'" >
       <div class="desct">
         用户药品订单
       </div>
       <userStorerDetails  ref="userDetails" />
     </div>
-    <div class="contentx" v-if="item!=null" >
+    <div class="contentx" v-if="item!=null && fsUserInfo !== 'gzzdy'" >
       <div class="desct">
         用户问诊订单
       </div>
       <userInquiryOrderDetails  ref="InquiryDetails" />
     </div>
 
+    <div class="contentx" v-if="item != null && fsUserInfo === 'gzzdy'" >
+      <div class="desct">
+        商城订单
+      </div>
+      <userStoreOrderList  ref="userStoreOrderList" />
+    </div>
+
     <!-- 积分购弹窗 -->
     <el-dialog
       title="积分购"
@@ -162,6 +169,7 @@ import userInquiryOrderDetails from "../components/userInquiryOrderDetails.vue";
 import userAddDetails from "../components/userAddDetails.vue";
 import userIntegralDetails from "../components/userIntegralDetails.vue";
 import AddOrderDialog from "../../hisStore/integralOrder/addOrder.vue"; // 导入积分购组件
+import userStoreOrderList from "../components/userStoreOrderList.vue"; //商城订单
 
 export default {
   name: "storedet",
@@ -172,7 +180,8 @@ export default {
     userPatietDetails,
     userAddDetails,
     userIntegralDetails,
-    AddOrderDialog // 注册积分购组件
+    AddOrderDialog, // 注册积分购组件
+    userStoreOrderList
   },
   data() {
     return {
@@ -201,6 +210,7 @@ export default {
       actName:"10",
       businessTypeOptions:[],
       couponStatusOptions:[],
+      fsUserInfo: process.env.VUE_APP_FS_USER_INFO
     }
   },
   created() {
@@ -279,6 +289,11 @@ export default {
         setTimeout(() => {
           this.$refs.userIntegralDetail.getIntegralLogs(orderId);
         }, 1);
+        setTimeout(() => {
+          if (this.$refs.userStoreOrderList) {
+            this.$refs.userStoreOrderList.getUserOrderDetails(orderId);
+          }
+        }, 1);
       });
 
       this.patient=null;

+ 1 - 0
src/views/store/components/userStaticAll.vue

@@ -50,6 +50,7 @@
         </el-table-column>
         <el-table-column prop="duration" label="播放时长" align="center" min-width="100"/>
         <el-table-column prop="finishTime" label="完课时间" align="center" min-width="120"/>
+        <el-table-column prop="companyUserName" label="所属销售" align="center" min-width="100"/>
       </el-table>
 
       <!-- 分页 -->

+ 275 - 0
src/views/store/components/userStoreOrderList.vue

@@ -0,0 +1,275 @@
+<template>
+  <div class="aacontainer">
+    <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 orderOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+    </el-tabs>
+    <el-table v-loading="loading" :data="storeOrderList">
+      <el-table-column label="订单号" align="center" prop="orderCode" width="180px"/>
+<!--      <el-table-column label="所属店铺" align="center" prop="storeName" width="180px"/>-->
+      <el-table-column label="所属公司" align="center" prop="companyName" width="180px"/>
+      <el-table-column label="所属员工" align="center" prop="companyUserNickName" width="180px"/>
+      <el-table-column label="用户昵称" align="center" prop="userPhone" show-overflow-tooltip width="100px"/>
+      <el-table-column label="收件人" align="center" prop="realName" />
+      <el-table-column label="订单总价" align="center" prop="totalPrice" />
+<!--      <el-table-column label="商品分类" align="center" prop="totalPrice" />-->
+      <el-table-column label="实付金额" align="center" prop="payPrice" />
+      <el-table-column label="代收金额" align="center" prop="payDelivery" />
+      <el-table-column label="订单状态" align="center" prop="status" >
+        <template slot-scope="scope">
+              <dict-tag :options="orderOptions" :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="isPay" >-->
+<!--        <template slot-scope="scope">-->
+<!--              <dict-tag :options="payStatusOptions" :value="scope.row.isPay"/>-->
+<!--            </template>-->
+<!--      </el-table-column>-->
+      <el-table-column label="支付时间" align="center" prop="payTime" width="180" />
+      <el-table-column label="支付方式" align="center" prop="payType" >
+        <template slot-scope="scope">
+              <dict-tag :options="PayOptions" :value="scope.row.payType"/>
+         </template>
+      </el-table-column>
+      <el-table-column label="发货时间" align="center" prop="deliverySendTime" width="180" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+import {listStoreOrder} from "@/api/hisStore/storeOrder";
+export default {
+  name: "userInquir",
+  props:["data"],
+  data() {
+    return {
+      actName:"10",
+      show:{
+              title:"订单详情",
+              open:false,
+            },
+      upload: {
+        // 是否显示弹出层
+        open: false,
+        // 弹出层标题
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        // url: process.env.VUE_APP_BASE_API + "/his/order/importData"
+      },
+      // 遮罩层
+      loading: true,
+      // // 导出遮罩层
+      // exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 订单表格数据
+      storeOrderList: [],
+      // 弹出层标题
+      title: "",
+      createTime:null,
+      payTime:null,
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        storeId: null,
+        orderCode: null,
+        userId: null,
+        userName: null,
+        userPhone: null,
+        userAddress: null,
+        cartId: null,
+        totalNum: null,
+        totalPrice: null,
+        payPrice: null,
+        payMoney: null,
+        isPay: null,
+        payTime: null,
+        payType: null,
+        status: null,
+        refundStatus: null,
+        refundImg: null,
+        refundExplain: null,
+        refundTime: null,
+        refundReason: null,
+        refundMoney: null,
+        deliveryCode: null,
+        deliveryName: null,
+        deliverySn: null,
+        isDel: null,
+        costPrice: null,
+        verifyCode: null,
+        shippingType: null,
+        isChannel: null,
+        isPrescribe: null,
+        prescribeId: null,
+        finishTime: null,
+        patientName: null,
+        doctorName: null,
+        sTime:null,
+        eTime:null,
+        paysTime:null,
+        payeTime:null,
+        deliveryTime: null,
+        tuiMoney: null,
+        tuiMoneyStatus: null,
+        tuiUserId: null,
+        orderCreateType: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+       PayOptions:[],
+       orderOptions:[],
+       payStatusOptions:[],
+       refundOptions:[],
+       channelOptions:[],
+       orderTypeOptions:[],
+       tuiOptions:[],
+       orOptions:[],
+       storeOPtions:[],
+    };
+  },
+  created() {
+    this.getDicts("store_pay_type").then(response => {
+        this.PayOptions = response.data;
+      });
+    this.getDicts("store_order_type").then(response => {
+        this.orderTypeOptions = response.data;
+      });
+    this.getDicts("store_order_status").then(response => {
+        this.orderOptions = response.data;
+      });
+
+    this.getDicts("sys_store_payment_status").then(response => {
+        this.payStatusOptions = response.data;
+      });
+    this.getDicts("sys_refund_status").then(response => {
+        this.refundOptions = response.data;
+      });
+    this.getDicts("sys_channel").then(response => {
+        this.channelOptions = response.data;
+      });
+  },
+  methods: {
+    getUserOrderDetails(id){
+      this.queryParams.userId=id
+      this.getList();
+    },
+
+    /** 查询订单列表 */
+    getList() {
+      this.loading = true;
+      listStoreOrder(this.queryParams).then(response => {
+        this.storeOrderList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        orderId: null,
+        storeId: null,
+        orderCode: null,
+        userId: null,
+        userName: null,
+        userPhone: null,
+        userAddress: null,
+        cartId: null,
+        totalNum: null,
+        totalPrice: null,
+        payPrice: null,
+        payMoney: null,
+        isPay: null,
+        payTime: null,
+        payType: null,
+        createTime: null,
+        updateTime: null,
+        status: null,
+        refundStatus: "0",
+        refundImg: null,
+        refundExplain: null,
+        refundTime: null,
+        refundReason: null,
+        refundMoney: null,
+        deliveryCode: null,
+        deliveryName: null,
+        deliverySn: null,
+        remark: null,
+        isDel: null,
+        costPrice: null,
+        verifyCode: null,
+        shippingType: null,
+        isChannel: null,
+        isPrescribe: null,
+        prescribeId: null,
+        finishTime: null,
+        deliveryTime: null,
+        tuiMoney: null,
+        tuiMoneyStatus: 0,
+        tuiUserId: null,
+        orderCreateType: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+   handleClickX(tab, event) {
+    if(tab.name=="10"){
+      this.queryParams.status=null;
+    }else{
+      this.queryParams.status=tab.name;
+    }
+     this.handleQuery();
+   },
+  changeTime(){
+        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;
+        }
+      },
+  }
+};
+</script>

+ 2 - 1
src/views/store/user/list.vue

@@ -114,6 +114,7 @@
             size="mini"
             type="text"
             @click="handleNickName(scope.row)"
+            v-hasPermi="['his:user:edit']"
           >修改昵称</el-button>
         </template>
       </el-table-column>
@@ -148,7 +149,7 @@
         </el-form-item> -->
       </el-form>
       <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button type="primary" @click="submitForm" v-hasPermi="['his:user:edit']">确 定</el-button>
         <el-button @click="cancel">取 消</el-button>
       </div>
     </el-dialog>

+ 2 - 1
src/views/store/user/myList.vue

@@ -114,6 +114,7 @@
             size="mini"
             type="text"
             @click="handleNickName(scope.row)"
+            v-hasPermi="['his:user:edit']"
           >修改昵称</el-button>
         </template>
       </el-table-column>
@@ -148,7 +149,7 @@
         </el-form-item> -->
       </el-form>
       <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button type="primary" @click="submitForm" v-hasPermi="['his:user:edit']">确 定</el-button>
         <el-button @click="cancel">取 消</el-button>
       </div>
     </el-dialog>