10 Commits b75720f085 ... e80ff15706

Autor SHA1 Mensagem Data
  15376779826 e80ff15706 Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_adminUI 2 semanas atrás
  15376779826 7f46604ee8 火山云服务端上传集成 2 semanas atrás
  15376779826 6bcf9e82dd 套餐包订单查询修改 1 mês atrás
  15376779826 ae6f41e790 Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_adminUI 1 mês atrás
  15376779826 df94e5bf4f Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_adminUI 1 mês atrás
  15376779826 bf3ef7bc5e 济南顺亿景配置 1 mês atrás
  15376779826 b5dadd291e Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_adminUI 1 mês atrás
  15376779826 47b2ae7012 Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_adminUI 1 mês atrás
  15376779826 16337e58fb Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_adminUI 2 meses atrás
  15376779826 3fc90e3738 济南顺亿景配置 2 meses atrás

+ 4 - 0
.env.development

@@ -26,6 +26,10 @@ VUE_APP_COS_REGION = ap-chongqing
 VUE_APP_VIDEO_LINE_1 = https://xfktcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://xfkobs.ylrztop.com
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://myhkvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = myhk-2114522511
 
 
 VUE_APP_LIVE_WS_URL = ws://127.0.0.1:7114/ws

+ 40 - 0
.env.prod-jnsyj

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =济南顺亿景SCRM管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =济南顺亿景
+# 公司名称
+VUE_APP_COMPANY_NAME =济南顺亿景
+# ICP备案号
+VUE_APP_ICP_RECORD =蜀ICP备2024052643号
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/jnsyj.png
+# 存储桶配置
+VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
+# 存储桶配置
+VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
+# 存储桶配置
+VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
+# 存储桶配置
+VUE_APP_OBS_BUCKET = jnsyj-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = jnsyj-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://jnsyjtcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://jnsyjobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'development'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 1 - 0
package.json

@@ -53,6 +53,7 @@
     "build:prod-gzzdy": "vue-cli-service build --mode prod-gzzdy",
     "build:prod-cfryt": "vue-cli-service build --mode prod-cfryt",
     "build:prod-hsyy": "vue-cli-service build --mode prod-hsyy",
+    "build:prod-jnsyj": "vue-cli-service build --mode prod-jnsyj",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src"
   },

+ 34 - 0
src/api/course/userVideo.js

@@ -104,3 +104,37 @@ export function getThumbnail(file) {
     }
   });
 }
+
+
+//火山云视频上传
+export function uploadUserVideo(file,uploadId) {
+  const formData = new FormData();
+  formData.append('file', file);
+  formData.append('uploadId', uploadId)
+  return request({
+    url: '/course/userVideo/uploadUserVideo',
+    method: 'post',
+    data: formData,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  });
+}
+
+// 查询火山云视频上传进度
+export function getUploadProgress(uploadId) {
+  return request({
+    url: '/course/userVideo/uploadProgress',
+    method: 'get',
+    params: { uploadId }
+  });
+}
+
+export function HsyAssumeRoleService() {
+  return request({
+    url: '/course/userVideo/HsyAssumeRoleService',
+    method: 'get',
+  });
+}
+
+

BIN
src/assets/logo/jnsyj.png


+ 92 - 0
src/utils/hsy.js

@@ -0,0 +1,92 @@
+import TTUploader from 'tt-uploader'
+import { HsyAssumeRoleService } from '@/api/course/userVideo'
+const  spaceName = process.env.VUE_APP_HSY_SPACE
+export const uploadToHSY = async (file, onProgress, type, callBackUp) => {
+  try {
+    const res = await HsyAssumeRoleService()
+    //console.log('火山云 STS 凭证:', res)
+    const credentials = res.data.result.credentials
+    //console.log('火山云 credentials 凭证:', credentials)
+
+    if (!credentials) {
+      throw new Error('未获取到火山云 STS 凭证')
+    }
+
+    const uploader = new TTUploader({
+      appId: '917052',
+      userId: '68185444',
+      videoConfig: {
+        spaceName: spaceName,
+      }
+    })
+
+    const date = new Date();
+    const yyyy = date.getFullYear();
+    const MM = String(date.getMonth() + 1).padStart(2, '0');
+    const dd = String(date.getDate()).padStart(2, '0');
+    const datePath = `${yyyy}${MM}${dd}`;
+
+
+    const fileName = `${Date.now()}.mp4`;
+
+    const remoteFileName = `course/${datePath}/${fileName}`;
+
+    const fileKey = uploader.addFile({
+      file,
+      type: 'video',
+      fileName:remoteFileName,
+      stsToken: {
+        CurrentTime: credentials.currentTime,
+        ExpiredTime: credentials.expiredTime,
+        SessionToken: credentials.sessionToken,
+        AccessKeyID: credentials.accessKeyId,
+        SecretAccessKey: credentials.secretAccessKey,
+      },
+    })
+
+    return new Promise((resolve, reject) => {
+
+      // 上传进度
+      uploader.on('progress', (info) => {
+        onProgress && onProgress({
+          percent: info.percent,
+        })
+      })
+
+      // 上传完成
+      uploader.on('complete', (info) => {
+        resolve({
+          ...info.uploadResult,
+          fileKey,
+        })
+      })
+
+      // 上传失败
+      uploader.on('error', (info) => {
+        reject(info)
+      })
+
+      // 取消上传支持
+      if (callBackUp) {
+        callBackUp({
+          uploader,
+          fileKey,
+          cancel: () => {
+            try {
+              uploader.removeFile(fileKey)
+              reject(new Error('Upload cancelled by user'))
+            } catch (e) {
+              reject(e)
+            }
+          }
+        })
+      }
+
+      uploader.start(fileKey)
+    })
+
+  } catch (error) {
+    console.error('火山云上传失败:', error)
+    throw error
+  }
+}

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

@@ -108,7 +108,8 @@
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange" style="width: 100%" :fit="true">
+<!--    <el-table height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange" style="width: 100%" :fit="true">-->
+    <el-table max-height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange" style="width: 100%" :fit="true">
       <el-table-column type="selection" width="55" align="center"/>
       <el-table-column label="课程ID" align="center" prop="courseId" width="55"/>
       <el-table-column label="所属项目" align="center" prop="projectName" width="120"/>

+ 121 - 28
src/views/course/videoResource/index.vue

@@ -774,7 +774,9 @@ import {getByIds, listCourseQuestionBank} from '@/api/course/courseQuestionBank'
 import {getThumbnail} from "@/api/course/userVideo";
 import {uploadObject} from "@/utils/cos.js";
 import {uploadToOBS} from "@/utils/obs.js";
+import {uploadToHSY} from "@/utils/hsy.js";
 import MinimizableDialog from "@/components/MinimizableDialog"
+import log from "@/views/monitor/job/log.vue";
 
 export default {
   name: 'VideoResource',
@@ -827,6 +829,8 @@ export default {
         typeSubId: null,
         projectIds: [],
         sort: null,
+        hsyVid:null,//火山云上传视频返回vid
+        hsyVodUrl:null,//火山云url
         // 新增上传状态字段
         uploadStatus: 'pending', // pending, uploading, success, failed
         uploadProgress: {
@@ -1108,6 +1112,7 @@ export default {
           this.add = true
 
           const params = Object.assign({}, this.form);
+          console.log("提交素材表单参数",this.form)
           params.projectIds = this.form.projectIds.join(',');
           if (this.form.id != null) {
             updateVideoResource(params).then(response => {
@@ -1302,37 +1307,95 @@ export default {
       }
     },
     //上传华为云Obs
-    async uploadVideoToHwObs(file, form, onProgress) {
+    // async uploadVideoToHwObs(file, form, onProgress) {
+    //   try {
+    //     // 更新线路2状态为上传中
+    //     this.updateUploadProgress('line2Status', 'uploading');
+    //
+    //     const data = await uploadToOBS(file, (progress) => {
+    //       const progressPercent = Math.floor(progress);
+    //       this.updateUploadProgress('line2', progressPercent);
+    //       const progressEvent = { percent: progressPercent, loaded: progress, total: progress, lengthComputable: true };
+    //       onProgress(progressEvent);
+    //     }, 1, (uploadInfo) => {
+    //       if (form.tempId) {
+    //         const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
+    //         tokens.obs = uploadInfo.cancel;
+    //         this.uploadCancellationTokens.set(form.tempId, tokens);
+    //       }
+    //     });
+    //
+    //     form.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
+    //
+    //     // 更新线路2状态为成功
+    //     this.updateUploadProgress('line2Status', 'success');
+    //     this.updateUploadProgress('line2', 100);
+    //
+    //     this.$message.success("线路二上传成功");
+    //     return { success: true, url: form.line2 };
+    //   } catch (error) {
+    //     // 更新线路2状态为失败
+    //     this.updateUploadProgress('line2Status', 'failed');
+    //     this.$message.error("线路二上传失败");
+    //     return { success: false, error: error.message };
+    //   }
+    // },
+    //上传火山云
+    async uploadVideoToHsy(file, form, onProgress) {
       try {
-        // 更新线路2状态为上传中
         this.updateUploadProgress('line2Status', 'uploading');
 
-        const data = await uploadToOBS(file, (progress) => {
-          const progressPercent = Math.floor(progress);
-          this.updateUploadProgress('line2', progressPercent);
-          const progressEvent = { percent: progressPercent, loaded: progress, total: progress, lengthComputable: true };
-          onProgress(progressEvent);
-        }, 1, (uploadInfo) => {
-          if (form.tempId) {
-            const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
-            tokens.obs = uploadInfo.cancel;
-            this.uploadCancellationTokens.set(form.tempId, tokens);
-          }
-        });
+        const data = await uploadToHSY(
+          file,
+          (progress) => {
+            // 火山云的进度是小数0-1
+            if (typeof progress.percent === 'number') {
+              const percent = Math.floor(progress.percent * 100);
+
+              // 更新线路2进度
+              this.updateUploadProgress('line2', percent);
+
+              // 对外统一 progress 事件(模拟 xhr)
+              onProgress?.({
+                percent,
+                loaded: percent,
+                total: 100,
+                lengthComputable: true
+              });
+            }
 
-        form.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
+            // 状态同步(成功 / 失败)
+            if (progress.status === 'success') {
+              this.updateUploadProgress('line2Status', 'success');
+              this.updateUploadProgress('line2', 100);
+            }
 
-        // 更新线路2状态为成功
-        this.updateUploadProgress('line2Status', 'success');
-        this.updateUploadProgress('line2', 100);
+            if (progress.status === 'failed') {
+              this.updateUploadProgress('line2Status', 'failed');
+            }
+          },
+          1,
+          (uploadInfo) => {
+            if (form.tempId) {
+              const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
+              tokens.hsy = uploadInfo.cancel;
+              this.uploadCancellationTokens.set(form.tempId, tokens);
+            }
+          }
+        );
+        console.log("上传火山云返回参数",data)
 
-        this.$message.success("线路二上传成功");
+        form.line2 = `${process.env.VUE_APP_VIDEO_URL}/${data.SourceInfo.FileName}`;
+        this.form.hsyVid = data.Vid
+        this.form.hsyVodUrl = process.env.VUE_APP_VIDEO_URL+"/"+data.SourceInfo.FileName
+        console.log("this.form",this.form)
+        this.$message.success('线路二上传成功');
         return { success: true, url: form.line2 };
+
       } catch (error) {
-        // 更新线路2状态为失败
         this.updateUploadProgress('line2Status', 'failed');
-        this.$message.error("线路二上传失败");
-        return { success: false, error: error.message };
+        this.$message.error('线路二上传失败');
+        return { success: false, error: error?.message || 'upload failed' };
       }
     },
     // 更新上传进度的辅助方法
@@ -1369,7 +1432,8 @@ export default {
         await this.getFirstThumbnail(file, this.form);
         const [line1Result, line2Result] = await Promise.allSettled([
           this.uploadVideoToTxPcdn(file, this.form, options.onProgress),
-          this.uploadVideoToHwObs(file, this.form, options.onProgress)
+          //this.uploadVideoToHwObs(file, this.form, options.onProgress)
+          this.uploadVideoToHsy(file, this.form, options.onProgress)
         ]);
 
         const line1Success = line1Result.status === 'fulfilled' && line1Result.value.success;
@@ -1471,6 +1535,7 @@ export default {
     },
     /** 批量修改 */
     submitBatchUpdate() {
+      console.log("批量上传表单提交参数",this.form)
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.batchUpdateForm.ids.length === 0) {
@@ -1504,6 +1569,7 @@ export default {
       }
 
       // 检查是否所有选中的视频都已上传完成
+      console.log("videoList",this.videoList)
       const incompleteVideos = this.videoList.filter(item => (item.progress || 0) < 100);
       if (incompleteVideos.length > 0) {
         this.$message.warning('有未完成上传的视频,请先完成上传');
@@ -1787,6 +1853,7 @@ export default {
       this.isProcessingBatch = false;
       this.isUploading = false;
       this.$message.success('所有视频上传队列处理完成!');
+      console.log("批量上传form",this.form)
     },
 
     async uploadSingleVideo(tempVideo) {
@@ -1797,7 +1864,9 @@ export default {
         // 并行上传到两个服务器
         const [line1Result, line2Result] = await Promise.allSettled([
           this.uploadVideoToTxPcdnBatch(tempVideo.file, tempVideo),
-          this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo)
+          // this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo)
+          this.uploadVideoToHSYBatch(tempVideo.file, tempVideo),
+
         ]);
 
         // 检查上传结果
@@ -2121,9 +2190,31 @@ export default {
       }
     },
     // 批量上传 - 华为云
-    async uploadVideoToHwObsBatch(file, tempVideo) {
+    // async uploadVideoToHwObsBatch(file, tempVideo) {
+    //   try {
+    //     const data = await uploadToOBS(file, (progress) => {
+    //       const progressPercent = Math.floor(progress);
+    //       const index = this.videoList.findIndex(item => item.tempId === tempVideo.tempId);
+    //       if (index !== -1) {
+    //         this.videoList[index].uploadDetails.line2 = progressPercent;
+    //         this.videoList[index].uploadDetails.line2Status = 'uploading';
+    //         this.updateBatchProgress(index);
+    //       }
+    //     }, 1, (uploadInfo) => {
+    //       const tokens = this.uploadCancellationTokens.get(tempVideo.tempId) || {};
+    //       tokens.obs = uploadInfo.cancel;
+    //       this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
+    //     });
+    //
+    //     tempVideo.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
+    //     return { success: true, url: tempVideo.line2 };
+    //   } catch (error) {
+    //     return { success: false, error: error.message };
+    //   }
+    // },
+    async uploadVideoToHSYBatch(file, tempVideo) {
       try {
-        const data = await uploadToOBS(file, (progress) => {
+        const data = await uploadToHSY(file, (progress) => {
           const progressPercent = Math.floor(progress);
           const index = this.videoList.findIndex(item => item.tempId === tempVideo.tempId);
           if (index !== -1) {
@@ -2136,9 +2227,11 @@ export default {
           tokens.obs = uploadInfo.cancel;
           this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
         });
+        console.log("批量上传返回参数",data)
+        tempVideo.line2 = `${process.env.VUE_APP_VIDEO_URL}/${data.SourceInfo.FileName}`;
+        tempVideo.hsyVid = data.Vid;
 
-        tempVideo.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
-        return { success: true, url: tempVideo.line2 };
+        return { success: true, url: tempVideo.line2};
       } catch (error) {
         return { success: false, error: error.message };
       }

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

@@ -301,6 +301,9 @@ export default {
         showType: [
           { required: true, message: "显示类别不能为空", trigger: "blur" }
         ],
+        activeId: [
+          { required: true, message: "活动不能为空", trigger: "blur" }
+        ],
       }
     };
   },

+ 15 - 4
src/views/his/packageOrder/index.vue

@@ -51,10 +51,19 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="员工" prop="companyUserName">
+      <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="员工昵称" prop="companyNickName">
+        <el-input
+          v-model="queryParams.companyNickName"
+          placeholder="员工昵称"
           clearable
           size="small"
           @keyup.enter.native="handleQuery"
@@ -156,7 +165,8 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="订单号" align="center" prop="orderSn" width="120px"/>
       <el-table-column label="所属公司" align="center" prop="companyName" />
-      <el-table-column label="员工" align="center" prop="companyUserName" />
+      <el-table-column label="员工账号" align="center" prop="companyUserName" />
+      <el-table-column label="员工昵称" align="center" prop="companyNickName" />
       <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="套餐名称" align="center" prop="packageName" />
       <el-table-column label="套餐别名" align="center" prop="packageSecondName" width="100px"/>
@@ -377,6 +387,7 @@ export default {
         endStartTime:null,
         endEndTime:null,
         companyUserName:null,
+        companyNickName:null,
         companyName:null,
         deptId:null,
         source:null,
@@ -423,7 +434,7 @@ export default {
     this.getDicts("sys_package_sub_type").then(response => {
       this.packageSubTypeOptions = response.data;
     });
-    
+
     // 获取小程序选项列表
     this.getAppMallOptions();
   },