Browse Source

Merge branch 'master' into 康年堂

ct 4 days ago
parent
commit
1bd5d038f2

+ 1 - 1
.env.prod-bjzm

@@ -23,7 +23,7 @@ VUE_APP_COS_BUCKET = bjzmky-1323137866
 # 存储桶配置
 VUE_APP_COS_REGION = ap-chongqing
 # 线路一地址
-VUE_APP_VIDEO_LINE_1 = https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com
+VUE_APP_VIDEO_LINE_1 = https://bjzmkytcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://bjzmobs.ylrztop.com
 

+ 16 - 0
src/api/course/coursePlaySourceConfig.js

@@ -31,6 +31,22 @@ export function update(data) {
   })
 }
 
+export function updateBindConfig(data) {
+  return request({
+    url: '/course/playSourceConfig/updateBindConfig',
+    method: 'put',
+    data: data
+  })
+}
+
+export function updateUnbindConfig(data) {
+  return request({
+    url: '/course/playSourceConfig/updateUnbindConfig',
+    method: 'put',
+    data: data
+  })
+}
+
 export function del(id) {
   return request({
     url: '/course/playSourceConfig/' + id,

+ 11 - 2
src/api/course/courseRedPacketLog.js

@@ -9,6 +9,15 @@ export function listCourseRedPacketLog(query) {
   })
 }
 
+// 查询短链课程看课记录列表
+export function listCourseRedPacketLogPage(data) {
+  return request({
+    url: '/course/courseRedPacketLog/pageList',
+    method: 'post',
+    data: data
+  })
+}
+
 // 查询短链课程看课记录详细
 export function getCourseRedPacketLog(logId) {
   return request({
@@ -55,10 +64,10 @@ export function delCourseRedPacketLog(logId) {
 }
 
 // 导出短链课程看课记录
-export function exportCourseRedPacketLog(query) {
+export function exportCourseRedPacketLog(data) {
   return request({
     url: '/course/courseRedPacketLog/export',
     method: 'post',
-    data: query
+    data: data
   })
 }

+ 10 - 1
src/api/course/courseWatchLog.js

@@ -9,6 +9,15 @@ export function listCourseWatchLog(query) {
   })
 }
 
+// 查询短链课程看课记录列表
+export function listCourseWatchLogPage(query) {
+  return request({
+    url: '/course/courseWatchLog/pageList',
+    method: 'post',
+    data: query
+  })
+}
+
 // 查询短链课程看课记录详细
 export function getCourseWatchLog(logId) {
   return request({
@@ -47,7 +56,7 @@ export function delCourseWatchLog(logId) {
 export function exportCourseWatchLog(query) {
   return request({
     url: '/course/courseWatchLog/export',
-    method: 'POST',
+    method: 'post',
     data: query
   })
 }

+ 53 - 0
src/api/merchantAppConfig/merchantAppConfig.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询商户应用配置列表
+export function listMerchantAppConfig(query) {
+  return request({
+    url: '/his/merchantAppConfig/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询商户应用配置详细
+export function getMerchantAppConfig(id) {
+  return request({
+    url: '/his/merchantAppConfig/' + id,
+    method: 'get'
+  })
+}
+
+// 新增商户应用配置
+export function addMerchantAppConfig(data) {
+  return request({
+    url: '/his/merchantAppConfig',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改商户应用配置
+export function updateMerchantAppConfig(data) {
+  return request({
+    url: '/his/merchantAppConfig',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除商户应用配置
+export function delMerchantAppConfig(id) {
+  return request({
+    url: '/his/merchantAppConfig/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出商户应用配置
+export function exportMerchantAppConfig(query) {
+  return request({
+    url: '/his/merchantAppConfig/export',
+    method: 'get',
+    params: query
+  })
+}

+ 3 - 1
src/views/course/courseAnswerlogs/index.vue

@@ -389,7 +389,9 @@ export default {
         }).then(response => {
           this.download(response.msg);
           this.exportLoading = false;
-        }).catch(() => {});
+        }).catch(() => {}).finally(res=>{
+          this.exportLoading = false;
+      });
     }
   }
 };

+ 161 - 3
src/views/course/coursePlaySourceConfig/index.vue

@@ -166,6 +166,7 @@
           </el-tag>
         </template>
       </el-table-column>
+      <el-table-column label="配置绑定Id" align="center" prop="merchantConfigId" />
       <el-table-column label="创建时间" align="center" prop="createTime" />
       <el-table-column label="修改时间" align="center" prop="updateTime" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@@ -190,6 +191,22 @@
             icon="el-icon-setting"
             @click="handleSwitchConfig(scope.row)"
           >是否展示销售</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleBind(scope.row)"
+            v-hasPermi="['course:playSourceConfig:bind']"
+            v-if="!scope.row.merchantConfigId"
+          >绑定</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUnbind(scope.row)"
+            v-hasPermi="['course:playSourceConfig:unbind']"
+            v-if="scope.row.merchantConfigId"
+          >解绑</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -322,19 +339,67 @@
       </div>
     </el-dialog>
 
+    <!-- 绑定  -->
+    <el-dialog :title="bindForm.bindTitle" :visible.sync="bindForm.bindShow" width="800px" append-to-body :before-close="handleBindClose">
+      <el-form ref="bindForm" :model="bindForm" :rules="bindRules" label-width="130px">
+        <el-form-item label="商户类型" prop="merchantType">
+          <el-select v-model="bindForm.merchantType" placeholder="请选择商户类型" clearable size="small" @change="changeSysPayModes">
+            <el-option
+              v-for="dict in sysPayModes"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="商户号" prop="merchantId">
+          <el-select v-model="bindForm.id" placeholder="请选择商户号" clearable size="small">
+            <el-option
+              v-for="dict in merchantAppConfigList"
+              :key="dict.id"
+              :label="dict.merchantId"
+              :value="dict.id"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFormBind(bindCurrentRow)" >确 定</el-button>
+        <el-button @click="cancelBind">取 消</el-button>
+      </div>
+    </el-dialog>
+
   </div>
 </template>
 
 <script>
-import {list, get, update, add, del} from '@/api/course/coursePlaySourceConfig'
+import {
+  list,
+  get,
+  update,
+  add,
+  del,
+  updateBindConfig,
+  updateUnbindConfig
+} from '@/api/course/coursePlaySourceConfig'
 import {updateIsTownOn} from "@/api/system/config";
 import { allList } from '@/api/company/company'
 import { resetForm } from '@/utils/common'
+import { listMerchantAppConfig } from "@/api/merchantAppConfig/merchantAppConfig";
 
 export default {
   name: 'CoursePlaySourceConfig',
   data() {
     return {
+      sysPayModes: [],
+      bindCurrentRow: {},
+      bindForm:{
+        bindTitle: '绑定支付配置',
+        bindShow: false,
+        merchantType: null,
+        id:null,
+      },
+      merchantAppConfigList:[],
       switchDialogVisible: false,
       // 公司搜索相关
       companySearchLoading: false,
@@ -388,6 +453,14 @@ export default {
       form: {
         setCompanyIdList: []
       },
+      bindRules:{
+        merchantType: [
+          { required: true, message: "商户类型不能为空", trigger: "blur" }
+        ],
+        id: [
+          { required: true, message: "商户号不能为空", trigger: "blur" }
+        ]
+      },
       rules: {
         name: [
           { required: true, message: "名称不能为空", trigger: "blur" }
@@ -423,6 +496,9 @@ export default {
     }
   },
   created() {
+    this.getDicts("sys_pay_mode").then(response => {
+      this.sysPayModes = response.data;
+    });
     this.getDicts("play_source_type").then(response => {
       this.typesOptions = response.data.map(item =>  {
         return {
@@ -443,7 +519,89 @@ export default {
       this.companyOptions = [];
       this.open = false;
     },
+    handleUnbind(row) {
+      this.$confirm('是否确认解绑该配置?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        const params = {
+          id: row.id
+        };
+        updateUnbindConfig(params).then(response => {
+          if (response.code === 200) {
+            this.msgSuccess("解绑成功");
+            this.getList();
+          } else {
+            this.msgError("解绑失败: " + response.msg);
+          }
+        }).catch(error => {
+          this.msgError("请求失败: " + error.message);
+        });
+      }).catch(() => {
+        // 用户取消操作
+      });
+    }
+    ,
+    submitFormBind(row) {
+      this.$refs["bindForm"].validate(valid => {
+        if (valid) {
+          // 构造请求参数
+          const params = {
+            id: row.id,  // 使用传入行数据的ID
+            merchantType: this.bindForm.merchantType,
+            merchantConfigId: this.bindForm.id
+          };
 
+          // 调用API更新绑定关系
+          updateBindConfig(params).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("绑定配置更新成功");
+              this.bindForm.bindShow = false;
+              this.getList(); // 刷新列表数据
+              this.resetForm("bindForm");
+            } else {
+              this.msgError("更新失败: " + response.msg);
+            }
+          }).catch(error => {
+            this.msgError("请求失败: " + error.message);
+          });
+        }
+      });
+    },
+    handleBindClose(done) {
+      this.resetForm("bindForm");
+      this.bindForm.bindShow = false;
+      this.bindForm.id = null;
+      done();
+    },
+    cancelBind(){
+      this.resetForm("bindForm");
+
+      this.bindForm.bindShow = false;  // 关闭对话框
+
+    },
+    // 绑定支付配置
+    handleBind(row) {
+      this.merchantAppConfigList= [];
+      this.bindForm.merchantType = null;
+      this.bindForm.id = null;
+      this.bindCurrentRow = row;  // 保存当前行数据
+      this.bindForm.bindShow = true;
+    },
+    changeSysPayModes(value){
+      console.log(value)
+      const query = {
+        pageNum: 1,
+        pageSize: 100,
+        merchantType: value,
+        isDeleted: 0
+      }
+      listMerchantAppConfig(query).then( response => {
+          this.merchantAppConfigList = response.rows;
+        }
+      )
+    },
 
     // 处理开关配置
     handleSwitchConfig(row) {
@@ -541,8 +699,8 @@ export default {
         }
         if(!!this.form.setCompanyIds){
            this.$set(
-            this.form, 
-            "setCompanyIdList", 
+            this.form,
+            "setCompanyIdList",
             this.form.setCompanyIds.split(",").map(str => parseInt(str, 10))
           );
           // this.form.setCompanyIdList = this.form.setCompanyIds.split(",").map(str => parseInt(str, 10));

+ 109 - 43
src/views/course/courseRedPacketLog/index.vue

@@ -38,17 +38,16 @@
 		<el-form-item label="员工" prop="companyUserName">
 		  <el-input
 		    v-model="queryParams.companyUserName"
-		    placeholder="员工"
+		    placeholder="所属员工"
 		    clearable
 		    size="small"
 		    @keyup.enter.native="handleQuery"
 		  />
 		</el-form-item>
-
-      <el-form-item label="用户ID" prop="userId">
+      <el-form-item label="会员ID" prop="userId">
         <el-input
           v-model="queryParams.userId"
-          placeholder="请输入用户ID"
+          placeholder="请输入会员ID"
           clearable
           size="small"
           @keyup.enter.native="handleQuery"
@@ -73,6 +72,28 @@
 	      @keyup.enter.native="handleQuery"
 	    />
 	  </el-form-item>
+
+      <el-form-item label="营期" prop="courseId">
+        <el-select
+          v-model="queryParams.periodId"
+          placeholder="请选择课程"
+          filterable
+          clearable
+          size="small"
+          remote
+          :remote-method="remoteMethod"
+          :loading="loadingPeriod"
+          @focus="handleFocus"
+        >
+          <el-option
+            v-for="dict in periodLists"
+            :key="dict.periodId"
+            :label="dict.periodName"
+            :value="parseInt(dict.periodId)"
+          />
+        </el-select>
+      </el-form-item>
+
 		<el-form-item label="课程" prop="courseId">
 		     <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" @change="courseChange(queryParams.courseId)">
 		         <el-option
@@ -94,7 +115,7 @@
      </el-select>
 	</el-form-item>
 	 <el-form-item label="创建时间" prop="createTime">
-	           <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange"
+	           <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
                              range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
 	 </el-form-item>
 
@@ -134,9 +155,11 @@
       </el-table-column>
       <el-table-column label="小节名称" align="center" prop="title" />
       <el-table-column label="会员id" align="center" prop="userId" />
+      <el-table-column label="会员名称" align="center" prop="fsNickName" />
       <el-table-column label="会员电话" align="center" prop="phone" />
-      <el-table-column label="所属销售" align="center" prop="companyUserName" />
+      <el-table-column label="所属员工" align="center" prop="companyUserName" />
       <el-table-column label="所属公司" align="center" prop="companyName" />
+      <el-table-column label="员工部门" align="center" prop="deptName" />
       <el-table-column label="转帐金额" align="center" prop="amount" />
       <el-table-column label="状态" align="center" prop="status" >
         <template slot-scope="scope">
@@ -162,14 +185,14 @@
         <el-form-item label="课程id" prop="courseId">
           <el-input v-model="form.courseId" placeholder="请输入课程id" />
         </el-form-item>
-        <el-form-item label="用户id" prop="userId">
-          <el-input v-model="form.userId" placeholder="请输入用户id" />
+        <el-form-item label="会员id" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入会员id" />
         </el-form-item>
         <el-form-item label="小节id" prop="videoId">
           <el-input v-model="form.videoId" placeholder="请输入小节id" />
         </el-form-item>
-        <el-form-item label="公司员工id" prop="companyUserId">
-          <el-input v-model="form.companyUserId" placeholder="请输入公司员工id" />
+        <el-form-item label="员工id" prop="companyUserId">
+          <el-input v-model="form.companyUserId" placeholder="请输入员工id" />
         </el-form-item>
         <el-form-item label="公司id" prop="companyId">
           <el-input v-model="form.companyId" placeholder="请输入公司id" />
@@ -190,22 +213,22 @@
 </template>
 
 <script>
-import { courseList,videoList,listCourseRedPacketLog, getCourseRedPacketLog, delCourseRedPacketLog, addCourseRedPacketLog, updateCourseRedPacketLog, exportCourseRedPacketLog } from "@/api/course/courseRedPacketLog";
+import { courseList,videoList,getCourseRedPacketLog, delCourseRedPacketLog, addCourseRedPacketLog, updateCourseRedPacketLog, exportCourseRedPacketLog,listCourseRedPacketLogPage } from "@/api/course/courseRedPacketLog";
 import { getCompanyList } from "@/api/company/company";
-import {treeselect} from "../../../api/company/companyDept";
 import SelectTree from '@/components/TreeSelect/index.vue'
 import { getDeptData } from '@/api/system/employeeStats'
 
 export default {
   name: "CourseRedPacketLog",
-  components: { SelectTree },
+  components: {SelectTree},
   data() {
     return {
-    selectedCompanyList: [],
 	  companys:[],
+    selectedCompanyList: [],
     deptList: [],
       // 遮罩层
-      loading: false,
+      loading: true,
+      loadingPeriod: false,
       // 导出遮罩层
       exportLoading: false,
       // 选中数组
@@ -218,6 +241,7 @@ export default {
       showSearch: true,
       activeName:"00",
       courseLists:[],
+      periodLists:[],
       videoList:[],
       // 总条数
       total: 0,
@@ -227,6 +251,10 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
+      queryPeriod: {
+        pageNum: 1,
+        pageSize: 20
+      },
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -243,6 +271,7 @@ export default {
         phoneMk: null,
         sTime:null,
         eTime:null,
+        userIds: null
       },
 	   createTime:null,
       // 表单参数
@@ -253,43 +282,82 @@ export default {
     };
   },
   created() {
-
-    getDeptData().then(response => {
-      this.deptList = response.data;
-    })
-
-    getCompanyList().then(response => {
+    this.getList();
+	    getCompanyList().then(response => {
 	    this.companys = response.data;
 	  });
 	  courseList().then(response => {
 	    this.courseLists = response.list;
 	  });
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    })
+    periodList(this.queryPeriod).then(response => {
+	    this.periodLists = response.data;
+	  });
 
     // this.getList();
   },
   methods: {
-	  handleClick(tab, event) {
+    // 远程搜索方法
+    async remoteMethod(query) {
+      this.searchKeyword = query
+      if (query !== '') {
+        this.loadingPeriod = true
+        await this.getPeriodList(query)
+        this.loadingPeriod = false
+      } else {
+        // 如果输入为空,可以清空列表或加载默认数据
+        this.periodLists = []
+      }
+    },
+
+    // 获取营期列表
+    async getPeriodList(keyword = '') {
+      try {
+        const params = {
+          periodName: keyword, // 搜索关键词
+          pageNum: 1,
+          pageSize: 50 // 根据需求调整
+        }
+
+        const response = await periodList(params)
+        this.periodLists = response.data.list || response.data || []
+      } catch (error) {
+        console.error('获取营期列表失败:', error)
+        this.periodLists = []
+      }
+    },
+    // 下拉框获取焦点时加载数据
+    async handleFocus() {
+      if (this.periodLists.length === 0) {
+        this.getPeriodList();
+      }
+    },
+
+
+    handleClick(tab, event) {
 	    this.activeName=tab.name;
-	    this.queryParams.status=tab.name
-	    this.getList();
+      if(tab.name == "00") {
+        this.queryParams.status = null;
+      } else {
+        this.queryParams.status = tab.name;
+      }
+        this.getList();
 	  },
-
     /** 查询短链课程看课记录列表 */
     getList() {
       this.loading = true;
-
       if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
-        this.queryParams.companyUserIds = this.selectedCompanyList;
+        this.queryParams.userIds = this.selectedCompanyList;
       }else {
-        this.queryParams.companyUserIds = [];
+        this.queryParams.userIds = [];
       }
-
-      listCourseRedPacketLog(this.queryParams).then(response => {
-        console.log("response",response)
+      listCourseRedPacketLogPage(this.queryParams).then(response => {
         this.courseRedPacketLogList = response.data.list;
         this.total = response.data.total;
         this.loading = false;
-      });
+      })
     },
 	change(){
 	      if(this.createTime!=null){
@@ -302,7 +370,6 @@ export default {
 
 	    },
 	courseChange(row){
-
 		if(row==""){
 			this.videoList=[]
 			this.queryParams.videoId=null
@@ -345,6 +412,10 @@ export default {
 	   this.createTime=null;
 	  this.queryParams.sTime=null;
 	  this.queryParams.eTime=null;
+      this.selectedCompanyList = [];
+      this.queryParams.pageNum = 1;    // Reset to first page
+      this.queryParams.pageSize = 10;  // Reset to default page size
+	  this.queryParams.periodId=null;
       this.handleQuery();
     },
     // 多选框选中数据
@@ -403,18 +474,13 @@ export default {
           this.msgSuccess("删除成功");
         }).catch(() => {});
     },
-	getSubCateList(pid){
-	  this.form.subCateId=null;
-	  if(pid == ''){
-	    this.subCategoryOptions=[];
-	    return
-	  }
-	  getCateListByPid(pid).then(response => {
-	    this.subCategoryOptions = response.data;
-	  });
-	},
     /** 导出按钮操作 */
     handleExport() {
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
           confirmButtonText: "确定",

+ 35 - 47
src/views/course/courseWatchLog/index.vue

@@ -11,37 +11,20 @@
 <!--          />-->
 <!--        </el-select>-->
 <!--      </el-form-item>-->
-      <el-form-item label="公司名" prop="companyId">
+      <el-form-item label="员工部门" prop="companyId">
         <select-tree
           v-model="selectedCompanyList"
           :raw-data="deptList"
-          placeholder="请选择销售"
           :parentSelectable="true"
+          placeholder="请选择"
           :multiple="true"
           component-width="300px"
           :max-display-tags="3"
           :check-strictly="false"
           :return-leaf-only="false"
+          @change="handleMultiChange"
         ></select-tree>
       </el-form-item>
-      <el-form-item label="客户ID" prop="qwExternalContactId">
-        <el-input
-          v-model="queryParams.qwExternalContactId"
-          placeholder="请输入会员ID"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="会员ID" prop="userId">
-        <el-input
-          v-model="queryParams.userId"
-          placeholder="请输入会员ID"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
       <el-form-item label="课程" prop="courseId">
         <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" @change="courseChange(queryParams.courseId)">
           <el-option
@@ -171,6 +154,7 @@
       </el-table-column>
       <el-table-column label="播放时长" align="center" prop="duration" />
       <el-table-column label="所属销售" align="center" prop="companyUserName" />
+      <el-table-column label="销售部门" align="center" prop="deptName" />
 <!--      <el-table-column label="所属公司" align="center" prop="companyName" />-->
 <!--      <el-table-column label="企微员工名称" align="center" prop="qwUserName" />-->
       <el-table-column label="所属发送方式" align="center" prop="sendType" />
@@ -192,21 +176,21 @@
 </template>
 
 <script>
-import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog } from "@/api/course/courseWatchLog";
+import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,listCourseWatchLogPage } from "@/api/course/courseWatchLog";
 import { allList, getCompanyList } from '@/api/company/company'
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getUserList} from "@/api/company/companyUser";
 import {getFsUserList} from "@/api/users/user";
-import SelectTree from '@/components/TreeSelect/index.vue'
-import { getDeptData } from '@/api/system/employeeStats'
+import {getDeptData} from "@/api/system/employeeStats";
+import SelectTree from "@/components/TreeSelect/index.vue";
 export default {
   name: "CourseWatchLog",
-  components: { SelectTree },
+  components: {SelectTree},
   data() {
     return {
+      userSourceTypeOptions: [],
       selectedCompanyList: [],
       deptList: [],
-      userSourceTypeOptions: [],
       activeName:"00",
       createTime:null,
       updateTime:null,
@@ -216,7 +200,7 @@ export default {
       companyList: [],
       queryUserLoading: false,
       // 遮罩层
-      loading: false,
+      loading: true,
       // 导出遮罩层
       exportLoading: false,
       // 选中数组
@@ -270,11 +254,6 @@ export default {
     };
   },
   created() {
-
-    getDeptData().then(response => {
-      this.deptList = response.data;
-    })
-
     courseList().then(response => {
       this.courseLists = response.list;
     });
@@ -295,11 +274,13 @@ export default {
     // 设置默认当天时间 xgb 防止频繁查询大量数据
     this.setToday();
 
-    // this.getList();
+    this.getList();
 
     this.loading = false;
 
-
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    })
   },
   computed: {
     sourceTypeModel: {
@@ -312,7 +293,9 @@ export default {
     }
   },
   methods: {
+    handleMultiChange(e){
 
+    },
     setToday(){
       const today = new Date();
       const todayStart = new Date(today);
@@ -453,7 +436,12 @@ export default {
     },
     /** 查询短链课程看课记录列表 */
     getList() {
-
+      // 在API调用前设置部门参数
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      } else {
+        this.queryParams.userIds = [];
+      }
       // xgb 看课数据量太大必须限制时间if (this.isEmptyArray(this.createTime) &&
       if (this.isEmptyArray(this.createTime) &&
         this.isEmptyArray(this.updateTime) &&
@@ -466,20 +454,11 @@ export default {
         this.queryParams.logType = null;
       }
 
-      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
-        this.queryParams.userIds = this.selectedCompanyList;
-      }else {
-        this.queryParams.userIds = [];
-      }
-
-      listCourseWatchLog(this.queryParams).then(response => {
+      listCourseWatchLogPage(this.queryParams).then(response => {
         this.courseWatchLogList = response.data.list;
         this.total = response.data.total;
         this.loading = false;
-      }).catch(() => {
-          this.loading = false;
-        }
-      );
+      })
     },
     // 取消按钮
     cancel() {
@@ -504,6 +483,7 @@ export default {
         courseId: null,
         scheduleStartTime: null,
         scheduleEndTime: null,
+        userIds: null,
       };
       this.scheduleTime=null;
       this.resetForm("form");
@@ -517,7 +497,6 @@ export default {
     resetQuery() {
       this.resetForm("queryForm");
       // this.createTime = null;
-      this.selectedCompanyList=[];
       this.scheduleTime = null;
       // this.queryParams.sTime = null;
       // this.queryParams.eTime = null;
@@ -527,6 +506,8 @@ export default {
       this.queryParams.scheduleEndTime = null;
       this.scheduleTime=null;
       this.updateTime=null;
+      this.selectedCompanyList = [];
+      // this.selectedCompanyList = [];
       // 重置时间当天
       this.setToday();
 
@@ -595,6 +576,11 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
       // xgb 看课数据量太大必须限制时间
       if (this.isEmptyArray(this.createTime) &&
         this.isEmptyArray(this.updateTime) &&
@@ -621,7 +607,9 @@ export default {
         }).then(response => {
           this.download(response.msg);
           this.exportLoading = false;
-        }).catch(() => {});
+        }).catch(() => {}).finally(res=>{
+          this.exportLoading = false;
+      });
     },
     handleScheduleTimeChange(scheduleTime) {
       if (scheduleTime && scheduleTime.length >= 2) {

+ 2 - 2
src/views/course/fsCourseProductOrder/index.vue

@@ -167,7 +167,7 @@
       </el-table-column>
       <el-table-column label="支付时间" align="center" prop="payTime" width="180">
         <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.payTime, '{y}-{m}-{d}') }}</span>
+          <span>{{ parseTime(scope.row.payTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
       <el-table-column label="订单状态" align="center" prop="status">
@@ -181,7 +181,7 @@
       </el-table-column>
       <el-table-column label="申请退款时间" align="center" prop="refundTime" width="180">
         <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.refundTime, '{y}-{m}-{d}') }}</span>
+          <span>{{ parseTime(scope.row.refundTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
       <el-table-column label="申请退款理由" :show-overflow-tooltip="true" align="center" prop="refundExplain" />

+ 7 - 6
src/views/course/userCourse/index.vue

@@ -828,6 +828,7 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.queryParams.companyIdsList = [];
       this.queryParams.isShow = this.activeName
       this.handleQuery();
     },
@@ -1103,24 +1104,24 @@ export default {
     handleAmountInput(rule, field) {
       let value = rule[field];
       if (value === null || value === undefined) return;
-      
+
       // 转换为字符串处理
       let str = value.toString();
-      
+
       // 移除除数字和小数点外的所有字符
       str = str.replace(/[^0-9.]/g, '');
-      
+
       // 只保留一个小数点
       const dotIndex = str.indexOf('.');
       if (dotIndex !== -1) {
         str = str.substring(0, dotIndex + 1) + str.substring(dotIndex + 1).replace(/\./g, '');
       }
-      
+
       // 限制小数点后最多两位
       if (dotIndex !== -1 && str.length > dotIndex + 3) {
         str = str.substring(0, dotIndex + 3);
       }
-      
+
       // 转换回数字并更新
       rule[field] = parseFloat(str) || 0;
     },
@@ -1149,7 +1150,7 @@ export default {
     validateMinAmount(rule, value, callback) {
       // debugger;
       // const maxAmount = this.form29.rules[].maxAmount
-      
+
       const index = rule.index;
       const maxAmount = this.openRedPage.rules[index].maxAmount;
 

+ 3 - 2
src/views/course/userCourse/public.vue

@@ -662,9 +662,10 @@ export default {
     },
     handleShow(row) {
       var isShowValue = row.isShow === 0 ? 1 : 0;
-      var course = {courseId: row.courseId, isShow: isShowValue};
+      var course = {courseId: row.courseId, isShow: isShowValue, isPrivate: row.isPrivate};
       updateIsShow(course).then(response => {
-        this.msgSuccess("修改成功");
+        var isShowText = isShowValue === 1 ? "上架成功" : "下架成功";
+        this.msgSuccess(isShowText);
         this.getList();
       });
     },

+ 738 - 0
src/views/his/merchantAppConfig/index.vue

@@ -0,0 +1,738 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <!--   主键ID   -->
+      <el-form-item label="主键ID" prop="id">
+        <el-input v-model="queryParams.id" placeholder="请输入主键ID" clearable size="small" @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="商户类型" prop="merchantType">
+        <el-select v-model="queryParams.merchantType" placeholder="请选择商户类型" clearable size="small">
+          <el-option
+            v-for="dict in sysPayModes"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <!--  商户号    -->
+      <el-form-item label="商户号" prop="merchantId">
+        <el-input v-model="queryParams.merchantId" placeholder="请输入商户号" clearable size="small" @keyup.enter.native="handleQuery" />
+      </el-form-item>
+<!--      <el-form-item label="应用ID" prop="appIds">-->
+<!--        <el-select-->
+<!--          v-model="queryParams.appIds"-->
+<!--          placeholder="请选择应用ID"-->
+<!--          clearable-->
+<!--          size="small"-->
+<!--        >-->
+<!--          <el-option-->
+<!--            v-for="dict in appIdOptions"-->
+<!--            :key="dict.appid"-->
+<!--            :label="dict.name"-->
+<!--            :value="dict.appid"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+<!--      <el-form-item label="创建时间">-->
+<!--        <el-date-picker-->
+<!--          v-model="daterangeCreatedTime"-->
+<!--          size="small"-->
+<!--          style="width: 240px"-->
+<!--          value-format="yyyy-MM-dd"-->
+<!--          type="daterange"-->
+<!--          range-separator="-"-->
+<!--          start-placeholder="开始日期"-->
+<!--          end-placeholder="结束日期"-->
+<!--        ></el-date-picker>-->
+<!--      </el-form-item>-->
+      <el-form-item label="状态" prop="isDeleted">
+        <el-select v-model="queryParams.isDeleted" placeholder="请选择状态" clearable size="small">
+          <el-option
+            v-for="dict in isDeletedOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['merchantAppConfig:merchantAppConfig:add']"
+        >新增</el-button>
+      </el-col>
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="success"-->
+<!--          plain-->
+<!--          icon="el-icon-edit"-->
+<!--          size="mini"-->
+<!--          :disabled="single"-->
+<!--          @click="handleUpdate"-->
+<!--          v-hasPermi="['merchantAppConfig:merchantAppConfig:edit']"-->
+<!--        >修改</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="danger"-->
+<!--          plain-->
+<!--          icon="el-icon-delete"-->
+<!--          size="mini"-->
+<!--          :disabled="multiple"-->
+<!--          @click="handleDelete"-->
+<!--          v-hasPermi="['merchantAppConfig:merchantAppConfig:remove']"-->
+<!--        >删除</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="warning"-->
+<!--          plain-->
+<!--          icon="el-icon-download"-->
+<!--          size="mini"-->
+<!--          :loading="exportLoading"-->
+<!--          @click="handleExport"-->
+<!--          v-hasPermi="['merchantAppConfig:merchantAppConfig:export']"-->
+<!--        >导出</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="merchantAppConfigList" @selection-change="handleSelectionChange">
+<!--      <el-table-column type="selection" width="55" align="center" />-->
+      <el-table-column label="主键ID" align="center" prop="id" />
+      <el-table-column label="商户号" align="center" prop="merchantId" />
+      <el-table-column label="商户类型" align="center" prop="merchantType">
+        <template slot-scope="scope">
+          <dict-tag :options="sysPayModes" :value="scope.row.merchantType"/>
+        </template>
+      </el-table-column>
+
+      <!--   appId 转化 appIdOptions   -->
+      <el-table-column label="应用名称" align="center" prop="appId">
+        <template slot-scope="scope">
+          <span v-if="scope.row.appId">
+            {{ getAppNames(scope.row.appId) }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="应用ID" align="center" prop="appId">
+        <template slot-scope="scope">
+          <span>{{ scope.row.appId }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="回调地址" align="center" prop="callbackUrl" />
+      <el-table-column label="配置详情" align="center" prop="dataJson">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleView(scope.row)"
+          >详情</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createdTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createdTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="修改时间" align="center" prop="updatedTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.updatedTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="isDeleted">
+        <template slot-scope="scope">
+          <dict-tag :options="isDeletedOptions" :value="scope.row.isDeleted"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['merchantAppConfig:merchantAppConfig:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['merchantAppConfig:merchantAppConfig:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改商户应用配置对话框 -->
+    <el-dialog :title="title" :visible.sync="dialogVisible" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="!isViewMode ? rules : {}" label-width="160px" :disabled="isViewMode">
+        <el-form-item label="商户类型" prop="merchantType">
+          <el-select
+            v-model="form.merchantType"
+            placeholder="请选择商户类型"
+            :disabled="form.id !== null"
+            @change="handleMerchantTypeChange"
+          >
+            <el-option
+              v-for="dict in sysPayModes"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="应用ID" prop="appIds">
+          <el-select
+            v-model="form.appIds"
+            placeholder="请选择应用ID"
+            clearable
+            size="small"
+            multiple
+          >
+            <el-option
+              v-for="dict in appIdOptions"
+              :key="dict.appid"
+              :label="dict.name"
+              :value="dict.appid"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-divider></el-divider>
+        </el-form-item>
+
+
+        <!-- 动态渲染不同商户类型的配置表单 -->
+        <div v-if="form.merchantType">
+          <!-- 易宝支付配置 -->
+          <div v-if="form.merchantType === 'yb'">
+            <el-form-item label="易宝商户号" prop="ybAccount">
+              <el-input v-model="ybConfig.ybAccount" placeholder="请输入易宝商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="易宝Key" prop="ybKey">
+              <el-input v-model="ybConfig.ybKey" placeholder="请输入易宝Key"></el-input>
+            </el-form-item>
+            <el-form-item label="易宝回调地址" prop="ybNotifyUrl">
+              <el-input v-model="ybConfig.ybNotifyUrl" placeholder="易宝回调地址"></el-input>
+            </el-form-item>
+          </div>
+
+          <!-- 台州银行配置 -->
+          <div v-else-if="form.merchantType === 'tz'">
+            <el-form-item label="台州商户号" prop="tzPlatMerCstNo">
+              <el-input v-model="tzConfig.tzPlatMerCstNo" placeholder="请输入台州商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="台州appSecret" prop="tzAppSecret">
+              <el-input v-model="tzConfig.tzAppSecret" placeholder="请输入台州appSecret"></el-input>
+            </el-form-item>
+            <el-form-item label="台州私钥" prop="tzPrivateKey">
+              <el-input v-model="tzConfig.tzPrivateKey" placeholder="请输入台州私钥"></el-input>
+            </el-form-item>
+            <el-form-item label="台州平台公钥" prop="tzPlatformPublicKey">
+              <el-input v-model="tzConfig.tzPlatformPublicKey" placeholder="请输入台州平台公钥"></el-input>
+            </el-form-item>
+            <el-form-item label="台州appKey" prop="tzAppKey">
+              <el-input v-model="tzConfig.tzAppKey" placeholder="请输入台州appKey"></el-input>
+            </el-form-item>
+            <el-form-item label="台州支付回调地址" prop="tzPayDecrypt">
+              <el-input v-model="tzConfig.tzPayDecrypt" placeholder="请输入台州支付回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="退款回调地址" prop="tzRefundDecrypt">
+              <el-input v-model="tzConfig.tzRefundDecrypt" placeholder="请输入退款回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="分账回调地址" prop="tzOrderShareDecrypt">
+              <el-input v-model="tzConfig.tzOrderShareDecrypt" placeholder="请输入台州分账回调地址"></el-input>
+            </el-form-item>
+          </div>
+
+          <!-- 微信支付配置 -->
+            <div v-else-if="form.merchantType === 'wx'">
+            <el-form-item label="微信商户号" prop="wxMchId">
+              <el-input v-model="wxConfig.wxMchId" placeholder="请输入微信商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="微信Key" prop="wxMchKey">
+              <el-input v-model="wxConfig.wxMchKey" placeholder="请输入微信Key"></el-input>
+            </el-form-item>
+            <el-form-item label="微信商户V3密钥" prop="wxApiV3Key">
+              <el-input v-model="wxConfig.wxApiV3Key" placeholder="请输入商户V3密钥"></el-input>
+            </el-form-item>
+            <el-form-item label="微信回调地址(scrm)" prop="notifyUrlScrm">
+              <el-input v-model="wxConfig.notifyUrlScrm" placeholder="请输入商城微信回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="p12证书路径" prop="keyPath">
+              <el-input v-model="wxConfig.keyPath" placeholder="请输入p12证书文件的绝对路径"></el-input>
+            </el-form-item>
+          </div>
+
+          <!-- 汇付支付配置 -->
+          <div v-else-if="form.merchantType === 'hf'">
+            <el-form-item label="汇付产品号" prop="hfProductId">
+              <el-input v-model="hfConfig.hfProductId" placeholder="汇付产品号"></el-input>
+            </el-form-item>
+            <el-form-item label="系统号" prop="hfSysId">
+              <el-input v-model="hfConfig.hfSysId" placeholder="系统号Key"></el-input>
+            </el-form-item>
+            <el-form-item label="商户号" prop="hfHuifuId">
+              <el-input v-model="hfConfig.huifuId" placeholder="商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="商户私钥" prop="hfRsaPrivateKey">
+              <el-input v-model="hfConfig.hfRsaPrivateKey" placeholder="商户私钥"></el-input>
+            </el-form-item>
+            <el-form-item label="汇付公钥" prop="hfRsaPublicKey">
+              <el-input v-model="hfConfig.hfRsaPublicKey" placeholder="汇付公钥"></el-input>
+            </el-form-item>
+            <el-form-item label="汇付支付回调地址" prop="hfPayNotifyUrl">
+              <el-input v-model="hfConfig.hfPayNotifyUrl" placeholder="汇付支付回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="大额支付回调地址" prop="hfPayOnlineNotifyUrl">
+              <el-input v-model="hfConfig.hfPayOnlineNotifyUrl" placeholder="汇付支付回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="汇付退款回调地址" prop="hfRefundNotifyUrl">
+              <el-input v-model="hfConfig.hfRefundNotifyUrl" placeholder="汇付退款回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="汇付大额退款回调地址" prop="hfOnlineRefundNotifyUrl">
+              <el-input v-model="hfConfig.hfOnlineRefundNotifyUrl" placeholder="汇付分账回调地址"></el-input>
+            </el-form-item>
+          </div>
+        </div>
+      </el-form>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm" v-if="!isViewMode">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import { listMerchantAppConfig, getMerchantAppConfig, delMerchantAppConfig, addMerchantAppConfig, updateMerchantAppConfig, exportMerchantAppConfig } from "@/api/merchantAppConfig/merchantAppConfig";
+import { listAll } from "@/api/course/coursePlaySourceConfig";
+
+export default {
+  name: "MerchantAppConfig",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 商户应用配置表格数据
+      merchantAppConfigList: [],
+      // 弹出层标题
+      title: "",
+      // 创建时间时间范围
+      daterangeCreatedTime: [],
+      // 删除状态:0-正常,1-已删除字典
+      isDeletedOptions: [],
+      sysPayModes: [],
+      detailOpen: false,  // 详情对话框开关
+      isViewMode: false,  // 是否为查看模式
+      dialogVisible: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        merchantType: null,
+        appIds: null,
+        createdTime: null,
+        isDeleted: "0",
+        id: null
+      },
+      appIdOptions:[],
+      ybConfig: {}, // 易宝配置
+      tzConfig: {}, // 台州银行配置
+      wxConfig: {}, // 微信配置
+      hfConfig: {}, // 汇付配置
+      // 表单参数
+      form: {
+        id: null,
+        merchantType: null,
+        appIds: [],
+        callbackUrl: null,
+        dataJson: null,
+        createdTime: null,
+        updatedTime: null,
+        isDeleted: null,
+        createdBy: null,
+        updatedBy: null
+      },
+      // 表单校验
+      rules: {
+        merchantType: [
+          { required: true, message: "商户类型不能为空", trigger: "change" }
+        ],
+        isDeleted: [
+          { required: true, message: "删除状态:0-正常,1-已删除不能为空", trigger: "change" }
+        ],
+        createdBy: [
+          { required: true, message: "创建人ID或用户名不能为空", trigger: "blur" }
+        ],
+        updatedBy: [
+          { required: true, message: "修改人ID或用户名不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+
+    this.getDicts("sys_normal_disable").then(response => {
+      this.isDeletedOptions = response.data;
+    });
+    this.getDicts("sys_pay_mode").then(response => {
+      this.sysPayModes = response.data;
+    });
+    listAll().then(response => {
+      this.appIdOptions=response.data;
+    });
+    this.getList();
+
+  },
+  methods: {
+    /** 详情按钮操作 */
+    handleView(row) {
+      this.isViewMode = true;
+      this.dialogVisible = true;  // 改为设置 dialogVisible
+      this.title = "查看商户应用配置";
+
+      // 加载数据(复用修改逻辑)
+      getMerchantAppConfig(row.id).then(response => {
+        // 先设置基础数据
+        Object.keys(response.data).forEach(key => {
+          if (key !== 'appIds') { // appIds单独处理
+            this.$set(this.form, key, response.data[key]);
+          }
+        });
+
+        // 单独处理 appIds,确保它是响应式的数组
+        let appIdsArray = [];
+        if (response.data.appId) {
+          if (typeof response.data.appId === 'string') {
+            appIdsArray = response.data.appId.split(',').map(item => item.trim()).filter(item => item);
+          } else if (Array.isArray(response.data.appId)) {
+            appIdsArray = [...response.data.appId];
+          }
+        }
+
+        // 使用 $set 确保响应式
+        this.$set(this.form, 'appIds', appIdsArray);
+
+        // 解析配置详情JSON
+        if (this.form.dataJson) {
+          try {
+            const configData = JSON.parse(this.form.dataJson);
+            switch(this.form.merchantType) {
+              case 'yb':
+                this.ybConfig = { ...configData };
+                break;
+              case 'tz':
+                this.tzConfig = { ...configData };
+                break;
+              case 'wx':
+                this.wxConfig = { ...configData };
+                break;
+              case 'hf':
+                this.hfConfig = { ...configData };
+                break;
+            }
+          } catch (e) {
+            console.error('解析配置详情失败:', e);
+          }
+        }
+      });
+    }
+    ,
+    /** 关闭详情对话框 */
+    closeDetailView() {
+      this.detailOpen = false;
+      this.isViewMode = false;
+      this.reset();
+    },
+    getAppNames(appIds) {
+      if (!appIds) return '';
+
+      // 处理逗号分隔的字符串
+      const appIdArray = typeof appIds === 'string' ? appIds.split(',') : Array.isArray(appIds) ? appIds : [appIds];
+
+      // 根据 appIdOptions 查找对应的应用名称
+      const names = appIdArray
+        .map(id => {
+          const option = this.appIdOptions.find(opt => opt.appid === id.trim());
+          return option ? option.name : id;
+        })
+        .filter(name => name); // 过滤掉空值
+
+      return names.join(', ');
+    },
+    /** 商户类型变化处理 */
+    handleMerchantTypeChange(value) {
+      // 清空之前的选择
+      this.ybConfig = {};
+      this.tzConfig = {};
+      this.wxConfig = {};
+      this.hfConfig = {};
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          // 构建配置详情JSON
+          let configData = {};
+          switch(this.form.merchantType) {
+            case 'yb':
+              configData = { ...this.ybConfig };
+              break;
+            case 'tz':
+              configData = { ...this.tzConfig };
+              break;
+            case 'wx':
+              configData = { ...this.wxConfig };
+              break;
+            case 'hf':
+              configData = { ...this.hfConfig };
+              break;
+          }
+
+          // 正确处理多选应用ID转字符串
+          if (this.form.appIds && Array.isArray(this.form.appIds) && this.form.appIds.length > 0) {
+            this.form.appId = this.form.appIds.join(',');
+          } else {
+            this.form.appId = '';
+          }
+
+          // 将配置转换为JSON字符串
+          this.form.dataJson = JSON.stringify(configData);
+
+          if (this.form.id != null) {
+            updateMerchantAppConfig(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.dialogVisible = false;
+              this.getList();
+            });
+          } else {
+            addMerchantAppConfig(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.dialogVisible = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 修改按钮操作 */
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids;
+      getMerchantAppConfig(id).then(response => {
+        // 先设置基础数据
+        Object.keys(response.data).forEach(key => {
+          if (key !== 'appIds') { // appIds单独处理
+            this.$set(this.form, key, response.data[key]);
+          }
+        });
+
+        // 单独处理 appIds,确保它是响应式的数组
+        let appIdsArray = [];
+        if (response.data.appId) {
+          if (typeof response.data.appId === 'string') {
+            appIdsArray = response.data.appId.split(',').map(item => item.trim()).filter(item => item);
+          } else if (Array.isArray(response.data.appId)) {
+            appIdsArray = [...response.data.appId];
+          }
+        }
+
+        // 使用 $set 确保响应式
+        this.$set(this.form, 'appIds', appIdsArray);
+
+        // 解析配置详情JSON
+        if (this.form.dataJson) {
+          try {
+            const configData = JSON.parse(this.form.dataJson);
+            switch(this.form.merchantType) {
+              case 'yb':
+                this.ybConfig = { ...configData };
+                break;
+              case 'tz':
+                this.tzConfig = { ...configData };
+                break;
+              case 'wx':
+                this.wxConfig = { ...configData };
+                break;
+              case 'hf':
+                this.hfConfig = { ...configData };
+                break;
+            }
+          } catch (e) {
+            console.error('解析配置详情失败:', e);
+          }
+        }
+
+        this.isViewMode = false; // 添加此行
+        this.dialogVisible = true; // 替代 this.open = true
+        this.title = "修改商户应用配置";
+      });
+    }
+
+    ,
+    /** 查询商户应用配置列表 */
+    getList() {
+      this.loading = true;
+      // if (this.queryParams.appIds && this.queryParams.appIds.length > 0) {
+      //   this.queryParams.appIds = this.queryParams.appIds.join(',');
+      // }
+      this.queryParams.params = {};
+      if (null != this.daterangeCreatedTime && '' != this.daterangeCreatedTime) {
+        this.queryParams.params["beginCreatedTime"] = this.daterangeCreatedTime[0];
+        this.queryParams.params["endCreatedTime"] = this.daterangeCreatedTime[1];
+      }
+      listMerchantAppConfig(this.queryParams).then(response => {
+        this.merchantAppConfigList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.dialogVisible = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        merchantType: null,
+        appId: null,  // 应该删除这一行
+        appIds: [],   // 初始化为空数组而不是null
+        callbackUrl: null,
+        dataJson: null,
+        createdTime: null,
+        updatedTime: null,
+        isDeleted: null,
+        createdBy: null,
+        updatedBy: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.daterangeCreatedTime = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.isViewMode = false; // 添加此行
+      this.dialogVisible = true; // 替代 this.open = true
+      this.title = "添加商户应用配置";
+    },
+    // /** 修改按钮操作 */
+    // handleUpdate(row) {
+    //   this.reset();
+    //   const id = row.id || this.ids
+    //   getMerchantAppConfig(id).then(response => {
+    //     this.form = response.data;
+    //     this.open = true;
+    //     this.title = "修改商户应用配置";
+    //   });
+    // },
+    // /** 提交按钮 */
+    // submitForm() {
+    //   this.$refs["form"].validate(valid => {
+    //     if (valid) {
+    //       if (this.form.id != null) {
+    //         updateMerchantAppConfig(this.form).then(response => {
+    //           this.msgSuccess("修改成功");
+    //           this.open = false;
+    //           this.getList();
+    //         });
+    //       } else {
+    //         addMerchantAppConfig(this.form).then(response => {
+    //           this.msgSuccess("新增成功");
+    //           this.open = false;
+    //           this.getList();
+    //         });
+    //       }
+    //     }
+    //   });
+    // },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除商户应用配置编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delMerchantAppConfig(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有商户应用配置数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportMerchantAppConfig(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 2 - 1
src/views/his/storeOrder/order1.vue

@@ -1047,7 +1047,8 @@ export default {
         { key: 'sex', label: '性别', checked: false },
         { key: 'erpPhone', label: 'ERP电话', checked: false },
         { key: 'erpAccount', label: 'ERP账号', checked: false },
-        { key: 'source', label: '订单来源', checked: false }
+        { key: 'source', label: '订单来源', checked: false },
+        { key: 'countGoods', label: '统计商品数量', checked: false }
       ],
       // 已选择的导出字段
       selectedExportFields: [],

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

@@ -27,6 +27,16 @@
           size="small"
           @keyup.enter.native="handleQuery"
         />
+      </el-form-item>
+      <el-form-item label="类别" prop="logType">
+        <el-select v-model="queryParams.logType" placeholder="请选择类别" clearable size="small">
+          <el-option
+            v-for="dict in intefralLogTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
       </el-form-item>
        <el-form-item label="时间" prop="createTime">
                  <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
@@ -38,6 +48,17 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['his:userIntegralLogs:remove']"
+        >删除</el-button>
+      </el-col>
       <el-col :span="1.5">
         <el-button
           type="warning"
@@ -53,6 +74,7 @@
     </el-row>
 
     <el-table v-loading="loading" border :data="userIntegralLogsList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="用户id" align="center" prop="userId" />
       <el-table-column label="用户昵称" align="center" prop="nickName" />
       <el-table-column label="用户电话" align="center" prop="phone" />

+ 21 - 0
src/views/hisStore/adv/index.vue

@@ -392,6 +392,27 @@ export default {
         this.form.status = response.data.status.toString();
         this.form.advType = response.data.advType.toString();
         this.form.showType = response.data.showType ? response.data.showType.toString() : "";
+        // 根据 imageUrl 判断 urlType
+        if (this.form.imageUrl) {
+          // 可以根据文件扩展名判断是图片还是视频
+          const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'];
+          const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv'];
+
+          const lowerImageUrl = this.form.imageUrl.toLowerCase();
+          let isImage = imageExtensions.some(ext => lowerImageUrl.includes(ext));
+          let isVideo = videoExtensions.some(ext => lowerImageUrl.includes(ext));
+
+          if (isImage) {
+            this.form.urlType = 1; // 图片
+          } else if (isVideo) {
+            this.form.urlType = 2; // 视频
+          } else {
+            this.form.urlType = 1; // 默认图片
+          }
+        } else {
+          this.form.urlType = 1; // 默认图片
+        }
+        console.log('urlType:', this.form.urlType, typeof this.form.urlType);
         this.open = true;
         this.title = "修改广告";
         setTimeout(() => {

+ 1 - 1
src/views/hisStore/store/audit.vue

@@ -63,7 +63,7 @@
           size="mini"
           :loading="exportLoading"
           @click="handleExport"
-          v-hasPermi="['his:store:export']"
+          v-hasPermi="['store:his:store:export']"
         >导出</el-button>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>

+ 12 - 7
src/views/hisStore/store/index.vue

@@ -71,7 +71,7 @@
           icon="el-icon-plus"
           size="mini"
           @click="handleAdd"
-          v-hasPermi="['his:store:add']"
+          v-hasPermi="['store:his:store:add']"
         >新增</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -82,7 +82,7 @@
           size="mini"
           :disabled="single"
           @click="handleUpdate"
-          v-hasPermi="['his:store:edit']"
+          v-hasPermi="['store:his:store:edit']"
         >修改</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -93,7 +93,7 @@
           size="mini"
           :disabled="multiple"
           @click="handleDelete"
-          v-hasPermi="['his:store:remove']"
+          v-hasPermi="['store:his:store:remove']"
         >删除</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -104,7 +104,7 @@
           size="mini"
           :loading="exportLoading"
           @click="handleExport"
-          v-hasPermi="['his:store:export']"
+          v-hasPermi="['store:his:store:export']"
         >导出</el-button>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
@@ -173,13 +173,14 @@
             type="text"
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
-            v-hasPermi="['his:store:edit']"
+            v-hasPermi="['store:his:store:edit']"
           >修改</el-button>
           <el-button
             size="mini"
             type="text"
             icon="el-icon-s-promotion"
             @click="handledetails(scope.row)"
+            v-hasPermi="['store:his:store:query']"
           >详情
           </el-button>
           <el-button
@@ -187,14 +188,14 @@
             type="text"
             icon="el-icon-delete"
             @click="handleDelete(scope.row)"
-            v-hasPermi="['his:store:remove']"
+            v-hasPermi="['store:his:store:remove']"
           >删除</el-button>
           <el-button
             size="mini"
             type="text"
             icon="el-icon-refresh"
             @click="handleRefresh(scope.row)"
-            v-hasPermi="['his:store:refresh']"
+            v-hasPermi="['store:his:store:refresh']"
           >重置密码</el-button>
         </template>
       </el-table-column>
@@ -903,6 +904,10 @@ export default {
         this.form = response.data;
         this.open = true;
         this.title = "修改店铺";
+        // 移除 phone 字段的验证规则
+        const newRules = Object.assign({}, this.rules);
+        delete newRules.phone;
+        this.rules = newRules;
         let str = this.form.shippingType
         this.form.shippingType = str.split(",")
         this.form.cityIds = ((this.form.cityIds).split(",")).map(Number)

+ 1 - 0
src/views/hisStore/storeCouponIssue/index.vue

@@ -234,6 +234,7 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.dateRange = [];
       this.resetForm("queryForm");
       this.handleQuery();
     },

+ 10 - 5
src/views/hisStore/storeProduct/index.vue

@@ -985,7 +985,7 @@ export default {
         // 设置上传的请求头部
         headers: { Authorization: "Bearer " + getToken() },
         // 上传的地址
-        url: process.env.VUE_APP_BASE_API + "/store/storeProduct/importData"
+        url: process.env.VUE_APP_BASE_API + "/store/store/storeProduct/importData"
       },
       // 添加药品相关字段
       isDrugOptions: [
@@ -1177,9 +1177,9 @@ export default {
         precautions: [
           { required: true, message: "注意事项不能为空", trigger: "blur" }
         ],
-        // storeId :[
-        //   { required: true, message: "所属店铺不能为空", trigger: "blur"}
-        // ],
+        storeId :[
+          { required: true, message: "所属店铺不能为空", trigger: "blur"}
+        ],
       }
     };
   },
@@ -1684,7 +1684,12 @@ export default {
           }
           addOrEdit(this.form).then(response => {
             if (response.code === 200) {
-              this.msgSuccess("修改成功");
+              // 根据是否有productId判断是新增还是修改
+              if (this.form.productId) {
+                this.msgSuccess("修改成功");
+              } else {
+                this.msgSuccess("新增成功");
+              }
               this.open = false;
               this.getList();
             }

+ 137 - 23
src/views/live/liveConsole/LiveConsole.vue

@@ -111,8 +111,9 @@
             全局用户自见
           </label>
         </div>
-        <el-scrollbar class="custom-scrollbar" style="height: 500px; width: 100%;" ref="manageRightRef">
-          <el-row v-for="m in msgList" :key="m.msgId">
+        <div class="message-container" @click="handleMessageBoxClick">
+          <el-scrollbar class="custom-scrollbar" style="height: 500px; width: 100%;" ref="manageRightRef">
+            <el-row v-for="m in msgList" :key="m.msgId">
             <el-row v-if="m.userId === userId && m.msgId == null" style="padding: 8px 0" type="flex" align="top" justify="end">
               <div style="display: flex;justify-content: flex-end">
                 <div style="display: flex;justify-content: flex-end;flex-direction: column;max-width: 200px;align-items: flex-end">
@@ -133,11 +134,11 @@
                     </div>
                   </el-col>
                   <el-col>
-                    <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="changeUserState(m)">{{ m.msgStatus === 1 ? '解禁' : '禁言' }}</a>
-                    <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="blockUser(m)">拉黑</a>
-                    <a v-if="m.singleVisible === 1" style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="singleVisible(m)">解除用户自见</a>
-                    <a v-else style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="singleVisible(m)">用户自见</a>
-                    <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="deleteMsg(m)">删除</a>
+                    <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="changeUserState(m)">{{ m.msgStatus === 1 ? '解禁' : '禁言' }}</a>
+                    <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="blockUser(m)">拉黑</a>
+                    <a v-if="m.singleVisible === 1" style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="singleVisible(m)">解除用户自见</a>
+                    <a v-else style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="singleVisible(m)">用户自见</a>
+                    <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="deleteMsg(m)">删除</a>
                   </el-col>
                 </el-row>
               </el-col>
@@ -146,7 +147,18 @@
           </el-row>
           <!-- 底部留白 -->
           <div style="height: 20px;"></div>
-        </el-scrollbar>
+          </el-scrollbar>
+          <!-- 加载最新消息按钮 -->
+          <el-button 
+            v-if="showLoadLatestBtn" 
+            class="load-latest-btn" 
+            type="primary" 
+            size="small" 
+            @click.stop="loadLatestMessages"
+            icon="el-icon-refresh">
+            加载最新消息
+          </el-button>
+        </div>
         <!--        <div class="message-list">-->
         <!--          <div class="message-item" v-for="msg in msgList" :key="msg.id">-->
         <!--            <div class="message-avatar">-->
@@ -391,6 +403,15 @@ export default {
       topMsgForm: {
         msg: '',
         duration: 5
+      },
+      // 消息滚动控制
+      isAutoScrollEnabled: true, // 是否启用自动滚动
+      autoScrollTimer: null, // 自动滚动定时器
+      showLoadLatestBtn: false, // 是否显示加载最新消息按钮
+      msgParams: {
+        pageNum: 1,
+        pageSize: 30,
+        liveId: null
       }
     };
   },
@@ -432,6 +453,65 @@ export default {
     this.initScrollListeners();
   },
   methods: {
+    // 点击消息框
+    handleMessageBoxClick() {
+      // 点击消息框时,停止自动滚动
+      this.isAutoScrollEnabled = false;
+      // 停止自动滚动定时器
+      if (this.autoScrollTimer) {
+        clearTimeout(this.autoScrollTimer);
+        this.autoScrollTimer = null;
+      }
+      // 检查是否在底部,如果不在底部则显示加载最新消息按钮
+      this.$nextTick(() => {
+        if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
+          const wrap = this.$refs.manageRightRef.wrap;
+          const scrollHeight = wrap.scrollHeight;
+          const clientHeight = wrap.clientHeight;
+          const currentScrollTop = wrap.scrollTop;
+          const maxScrollTop = scrollHeight - clientHeight;
+          
+          if (currentScrollTop < maxScrollTop - 50) {
+            this.showLoadLatestBtn = true;
+          }
+        }
+      });
+    },
+    // 滚动到底部
+    scrollToBottom(forceScroll = false) {
+      // 如果自动滚动被禁用且不是强制滚动,则不执行
+      if (!this.isAutoScrollEnabled && !forceScroll) {
+        return;
+      }
+      
+      if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
+        this.$nextTick(() => {
+          const wrap = this.$refs.manageRightRef.wrap;
+          if (!wrap) return;
+          
+          const scrollHeight = wrap.scrollHeight;
+          const clientHeight = wrap.clientHeight;
+          const currentScrollTop = wrap.scrollTop;
+          const maxScrollTop = scrollHeight - clientHeight;
+          
+          // 强制滚动或启用自动滚动时,直接滚动到底部并隐藏按钮
+          if (forceScroll || this.isAutoScrollEnabled) {
+            this.showLoadLatestBtn = false;
+            wrap.scrollTop = maxScrollTop;
+          }
+        });
+      }
+    },
+    // 加载最新消息
+    loadLatestMessages() {
+      this.showLoadLatestBtn = false;
+      // 恢复自动滚动
+      this.isAutoScrollEnabled = true;
+      // 重新请求最新消息
+      this.resetMsgParams();
+      // loadMsgList 中会自动滚动到底部,因为 isAutoScrollEnabled 已经是 true
+      this.loadMsgList();
+    },
     singleVisible(m){
       // 过滤当前所有消息 找到userId的相同的消息 更改他们的自可见状态
       m.singleVisible= m.singleVisible === 1 ? 0 : 1
@@ -638,12 +718,17 @@ export default {
             this.msgList.shift()
           }
           this.msgList.push(message)
-          // 移动到底部
-          this.$nextTick(() => {
-            setTimeout(() => {
-              this.$refs.manageRightRef.wrap.scrollTop = this.$refs.manageRightRef.wrap.scrollHeight - this.$refs.manageRightRef.wrap.clientHeight
-            }, 200)
-          })
+          // 如果启用自动滚动,自动滚动到底部
+          if (this.isAutoScrollEnabled) {
+            this.$nextTick(() => {
+              this.autoScrollTimer = setTimeout(() => {
+                this.scrollToBottom();
+              }, 200);
+            });
+          } else {
+            // 自动滚动被禁用时,显示加载最新消息按钮
+            this.showLoadLatestBtn = true;
+          }
         } else if (cmd === 'entry' || cmd === 'out') {
           const user = data;
           const online = cmd === 'entry' ? 0 : 1; // 0=在线,1=离线
@@ -1077,22 +1162,13 @@ export default {
           let totalPage = (total % this.msgParams.pageSize == 0) ? Math.floor(total / this.msgParams.pageSize) : Math.floor(total / this.msgParams.pageSize + 1);
           rows.forEach(row => {
             if (!this.msgList.some(m => m.msgId === row.msgId)) {
-
               let user = this.alDisplayList.find(u => u.userId === row.userId)
               if (user) {
                 row.msgStatus = user.msgStatus
               } else {
                 row.msgStatus = 0
               }
-
               this.msgList.push(row)
-
-              // 移动到底部
-              this.$nextTick(() => {
-                setTimeout(() => {
-                  this.$refs.manageRightRef.wrap.scrollTop = this.$refs.manageRightRef.wrap.scrollHeight - this.$refs.manageRightRef.wrap.clientHeight
-                }, 200)
-              })
             }
           })
 
@@ -1101,6 +1177,30 @@ export default {
           this.alDisplayList.forEach(u => {
             this.msgList.filter(m => m.userId === u.userId).forEach(m => m.msgStatus = u.msgStatus)
           })
+          // 所有消息加载完成后,根据自动滚动状态决定是否滚动
+          this.$nextTick(() => {
+            setTimeout(() => {
+              if (this.isAutoScrollEnabled) {
+                // 如果启用自动滚动,强制滚动到底部并隐藏按钮
+                this.scrollToBottom(true);
+              } else {
+                // 如果禁用自动滚动,检查是否在底部,决定是否显示按钮
+                if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
+                  const wrap = this.$refs.manageRightRef.wrap;
+                  const scrollHeight = wrap.scrollHeight;
+                  const clientHeight = wrap.clientHeight;
+                  const currentScrollTop = wrap.scrollTop;
+                  const maxScrollTop = scrollHeight - clientHeight;
+                  
+                  if (currentScrollTop < maxScrollTop - 50) {
+                    this.showLoadLatestBtn = true;
+                  } else {
+                    this.showLoadLatestBtn = false;
+                  }
+                }
+              }
+            }, 300);
+          });
         }
       })
 
@@ -1201,6 +1301,7 @@ export default {
         pageSize: 30,
         liveId: this.liveId
       };
+      // 重置时不改变按钮状态,由后续的滚动逻辑决定
       this.taskParams = {
         currentPage: 1,
         pageSize: 20,
@@ -1321,6 +1422,9 @@ export default {
     if (this.autoMsgTimer != null) {
       clearInterval(this.autoMsgTimer);
     }
+    if (this.autoScrollTimer) {
+      clearTimeout(this.autoScrollTimer);
+    }
   },
   // 使用 deactivated 和 activated 钩子替代 beforeDestroy 和 destroyed
   deactivated() {
@@ -1624,4 +1728,14 @@ export default {
   text-align: center;
   border-radius: 4px;
 }
+.message-container {
+  position: relative;
+}
+.load-latest-btn {
+  position: absolute;
+  bottom: 20px;
+  right: 20px;
+  z-index: 10;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+}
 </style>

+ 13 - 14
src/views/qw/externalContact/index.vue

@@ -181,8 +181,8 @@
             @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="添加时间" prop="createTime">
-        <el-date-picker v-model="queryParams.createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
+      <el-form-item label="添加时间">
+        <el-date-picker v-model="daterange" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
       </el-form-item>
 
 
@@ -427,6 +427,7 @@ export default {
   components: { PaginationMore },
   data() {
     return {
+      daterange: [],
       // 遮罩层
       loading: false,
       // 导出遮罩层
@@ -516,6 +517,8 @@ export default {
         isRepeat: null,
         commentStatus: null,
         isBindMini:null,
+        sTime:null,
+        eTime:null
       },
       //标签
       changeTagDialog:{
@@ -609,6 +612,13 @@ export default {
     /** 查询企业微信客户列表 */
     getList() {
       this.loading = true;
+      if(this.daterange!=null){
+        this.queryParams.sTime=this.daterange[0];
+        this.queryParams.eTime=this.daterange[1];
+      }else{
+        this.queryParams.sTime=null;
+        this.queryParams.eTime=null;
+      }
       listExternalContact(this.queryParams).then(response => {
         this.externalContactList = response.rows;
         this.total = response.total;
@@ -646,7 +656,6 @@ export default {
         status: 0,
         stageStatus: "0",
         createBy: null,
-        createTime: null,
         updateBy: null,
         updateTime: null,
         transferTime: null,
@@ -672,16 +681,6 @@ export default {
       };
       this.resetForm("form");
     },
-    change(){
-      if(this.createTime!=null){
-        this.queryParams.sTime=this.createTime[0];
-        this.queryParams.eTime=this.createTime[1];
-      }else{
-        this.queryParams.sTime=null;
-        this.queryParams.eTime=null;
-      }
-
-    },
     /** 搜索按钮操作 */
     handleQuery() {
       //验证是否选择企业
@@ -720,10 +719,10 @@ export default {
       this.queryParams.corpId= this.qwCompanyList[0].dictValue;
       this.selectTags=[];
       this.queryParams.qwUserId = null;
-      this.createTime=null;
       this.queryParams.sTime=null;
       this.queryParams.eTime=null;
       this.externalContactList=[];
+      this.daterange=[];
       if(this.qwCompanyList!=null){
         this.queryParams.companyId=this.qwCompanyList[0].companyId;
         this.getAllUserlist(this.queryParams.companyId);

+ 4 - 0
src/views/system/keyword/index.vue

@@ -196,6 +196,9 @@ export default {
       form: {},
       // 表单校验
       rules: {
+        keyword: [
+          { required: true, message: "关键字不能为空", trigger: "blur" }
+        ],
       }
     };
   },
@@ -252,6 +255,7 @@ export default {
       this.reset();
       this.open = true;
       this.title = "添加关键字";
+      this.keywordId = null;
     },
     /** 修改按钮操作 */
     handleUpdate(row) {