Bladeren bron

update 租户后台 课程新增以及视频封面图片上传企微

ct 1 week geleden
bovenliggende
commit
fc49c4cb7d

+ 0 - 1
src/components/VideoUpload/index.vue

@@ -124,7 +124,6 @@
 <script>
 import {getSignature, uploadHuaWeiObs, uploadHuaWeiVod} from "@/api/common";
 import {getThumbnail} from "@/api/course/userVideo";
-import TcVod from "vod-js-sdk-v6";
 import { uploadObject } from "@/utils/cos.js";
 import { uploadToOBS } from "@/utils/obs.js";
 import Pagination from "@/components/Pagination";

+ 2 - 0
src/utils/node-empty-module.js

@@ -0,0 +1,2 @@
+// 浏览器端占位:@aws-sdk/@smithy 等会引用 node:* 内置模块,前端实际不需要
+export default {}

+ 847 - 194
src/views/course/userCourse/index.vue

@@ -2,25 +2,35 @@
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
       <el-form-item label="课堂分类" prop="cateId">
-        <el-select v-model="queryParams.cateId" placeholder="请选择" clearable size="small"  @change="getQuerySubCateList(queryParams.cateId)">
+        <el-select v-model="queryParams.cateId" placeholder="请选择" clearable size="small"
+                   @change="getQuerySubCateList(queryParams.cateId)">
           <el-option
-              v-for="dict in categoryOptions"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              :value="dict.dictValue"
-            />
+            v-for="dict in categoryOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
         </el-select>
       </el-form-item>
       <el-form-item label="课堂子分类" prop="subCateId">
         <el-select v-model="queryParams.subCateId" placeholder="请选择" clearable size="small">
           <el-option
-              v-for="dict in querySubCateOptions"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              :value="dict.dictValue"
-            />
+            v-for="dict in querySubCateOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
         </el-select>
       </el-form-item>
+      <el-form-item label="课堂id" prop="courseId">
+        <el-input
+          v-model="queryParams.courseId"
+          placeholder="请输入课堂id"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
       <el-form-item label="课堂名称" prop="courseName">
         <el-input
           v-model="queryParams.courseName"
@@ -40,57 +50,143 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="课堂类型" prop="isPrivate" style="display: none">
+        <el-select v-model="queryParams.isPrivate" placeholder="请选择" clearable size="small">
+          <el-option
+            v-for="dict in courseTypeOptions"
+            :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-tabs type="card" v-model="queryParams.isShow" @tab-click="handleClick">-->
-<!--      <el-tab-pane label="已上架" name="1"></el-tab-pane>-->
-<!--      <el-tab-pane label="待上架" name="0"></el-tab-pane>-->
-<!--    </el-tabs>-->
-    <el-table height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="课程ID" align="center" prop="courseId" />
-      <el-table-column label="封面图片" align="center" prop="imgUrl" width="120">
+    <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="['course:userCourse: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="['course:userCourse: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="['course:userCourse: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="['course:userCourse:export']"
+        >导出
+        </el-button>
+      </el-col>
+      <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 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"/>
+      <el-table-column label="封面图片" align="center" prop="imgUrl" width="170">
         <template slot-scope="scope">
           <el-popover
             placement="right"
             title=""
             trigger="hover"
           >
-            <img slot="reference" :src="scope.row.imgUrl" width="100" >
+            <img slot="reference" :src="scope.row.imgUrl" width="100">
             <img :src="scope.row.imgUrl" style="max-width: 300px;">
           </el-popover>
         </template>
       </el-table-column>
-      <el-table-column label="小封面" align="center" prop="secondImg" width="100">
-        <template slot-scope="scope">
-          <el-popover
-            placement="right"
-            title=""
-            trigger="hover"
-          >
-            <img slot="reference" :src="scope.row.secondImg" width="50">
-            <img :src="scope.row.secondImg" style="max-width: 100px;">
-          </el-popover>
-        </template>
-      </el-table-column>
-      <el-table-column label="课堂名称" align="center" show-overflow-tooltip prop="courseName" />
-      <el-table-column label="排序" align="center" prop="sort" />
-      <el-table-column label="分类名称" align="center" prop="cateName" />
-      <el-table-column label="子分类名称" align="center" prop="subCateName" />
-      <el-table-column label="原价" align="center" prop="price" />
-      <el-table-column label="售价" align="center" prop="sellPrice" />
-      <el-table-column label="单节积分" align="center" prop="integral" />
+      <el-table-column label="课堂名称" align="center" show-overflow-tooltip prop="courseName" min-width="100"/>
+      <el-table-column label="排序" align="center" prop="sort" width="80"/>
+      <el-table-column label="分类名称" align="center" prop="cateName" width="120"/>
+      <el-table-column label="子分类名称" align="center" prop="subCateName" width="120"/>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
             size="mini"
             type="text"
             @click="handleCatalog(scope.row)"
-          >目录管理</el-button>
+            v-hasPermi="['course:userCourse:cateMange']"
+          >目录管理
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['course:userCourse:edit']"
+          >修改
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdateRedPage(scope.row)"
+            v-hasPermi="['course:userCourse:editRedPage']"
+          >统一修改红包金额
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleCopy(scope.row)"
+            v-hasPermi="['course:userCourse:copy']"
+          >复制
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['course:userCourse:remove']"
+          >删除
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-if="scope.row.isPrivate === 1"
+            v-has-permi="['course:userCourse:editConfig']"
+            @click="configCourse(scope.row)"
+          >过程页配置
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -104,54 +200,323 @@
     />
 
     <!-- 添加或修改课程对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+        <el-row>
+          <el-form-item label="所属项目" prop="project">
+            <el-select v-model="form.project" placeholder="请选择项目" filterable clearable size="small">
+              <el-option
+                v-for="dict in projectOptions"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+        </el-row>
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="课堂名称" prop="courseName">
+              <el-input v-model="form.courseName" placeholder="请输入课堂名称"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="课堂分类" prop="cateId">
+              <el-select v-model="form.cateId" placeholder="请选择" clearable size="small"
+                         @change="getSubCateList(form.cateId)">
+                <el-option
+                  v-for="dict in categoryOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="课堂子分类" prop="subCateId">
+              <el-select v-model="form.subCateId" placeholder="请选择" clearable size="small">
+                <el-option
+                  v-for="dict in subCategoryOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="排序" prop="sort">
+              <el-input-number v-model="form.sort"  :min="0"  label="排序"></el-input-number>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="课堂简介" prop="description">
+              <el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入课堂简介"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="课程封面" prop="imgUrl">
+          <ImageUpload v-model="form.imgUrl" type="image" :num="10" :width="150" :height="150"/>
+        </el-form-item>
+        <el-form-item label="关联公司" prop="tags">
+          <el-select v-model="companyIds" multiple placeholder="请选择公司" filterable clearable style="width: 90%;">
+            <el-option
+              v-for="dict in companyOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+
+    <el-dialog title="修改课程红包金额" :visible.sync="openRedPage.open" width="1000px" append-to-body>
+      <el-form ref="openRedPage" :model="openRedPage" :rules="rulesRedPage" label-width="110px">
+        <el-form-item label="红包金额" prop="redPacketMoney">
+          <el-input-number v-model="openRedPage.redPacketMoney" :min="0.1" :max="200" :step="0.1"></el-input-number>
+        </el-form-item>
+        <div v-if="!!enableRandomRedPacket" style=" display: flex;
+                  flex-direction: column;">
+          <div v-for="(rule, index) in openRedPage.rules" :key="index" class="form-row">
+            <el-form-item
+              label="随机红包金额区间"
+              :prop="`rules.${index}.minAmount`"
+              :rules="[
+              { required: true, message: '请输入最小金额', trigger: 'blur' },
+              { validator: validateMinAmount, trigger: 'blur', index: index }
+            ]"
+              class="form-item-amount"
+            >
+              <el-input
+                v-model.number="rule.minAmount"
+                type="number"
+                :min="0.01"
+                :precision="2"
+                :step="0.01"
+                placeholder="最小金额"
+                size="small"
+                class="amount-input"
+                @input="handleAmountInput(rule, 'minAmount')"
+              ></el-input>
+              <span class="separator">-</span>
+              <el-input
+                v-model.number="rule.maxAmount"
+                type="number"
+                :min="rule.minAmount || 0.01"
+                :precision="2"
+                :step="0.01"
+                placeholder="最大金额"
+                size="small"
+                class="amount-input"
+                @input="handleAmountInput(rule, 'maxAmount')"
+              ></el-input>
+              <span class="suffix">元</span>
+            </el-form-item>
+            <el-form-item
+              label="随机权重"
+              :prop="`rules.${index}.weight`"
+              :rules="[
+                  { required: true, message: '请输入权重', trigger: 'blur' },
+                  { type: 'integer', message: '权重必须为整数', trigger: 'blur' },
+                ]"
+              class="form-item-weight"
+            >
+              <el-input
+                v-model.number="rule.weight"
+                type="number"
+                :min="1"
+                placeholder="权重"
+                size="small"
+              ></el-input>
+            </el-form-item>
+            <el-tooltip class="item" effect="dark" content="权重越高,被随机到的概率越大" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+            <div class="action-buttons">
+              <el-button
+                icon="el-icon-plus"
+                size="mini"
+                type="text"
+                @click="addRule(index)"
+                class="add-btn"
+              >
+                新增
+              </el-button>
+              <el-button
+                icon="el-icon-delete"
+                size="mini"
+                type="text"
+                @click="deleteRule(index)"
+                :disabled="openRedPage.rules.length <= 1"
+                class="delete-btn"
+              >
+                删除
+              </el-button>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFormRedPage">确 定</el-button>
+        <el-button @click="cancelRedPage">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 过程页配置 -->
+    <el-dialog
+      :visible.sync="configDialog.dialogVisible"
+      title="过程页配置"
+      append-to-body
+      width="1200px"
+    >
+      <el-form :model="configDialog.form" :rules="configDialog.rules" ref="configForm" label-width="110px">
+        <el-form-item label="过程页图片" prop="coverImg">
+          <ImageUpload v-model="configDialog.form.coverImg" :height="150" :limit="1" :width="150" type="image"/>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 不配置将使用课程默认图片</span>
+        </el-form-item>
+        <el-form-item label="首播电视台" prop="tvEnable">
+          <el-switch v-model="configDialog.form.tvEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="tv" v-if="configDialog.form.tvEnable">
+          <el-input v-model="configDialog.form.tv" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个首播电视台,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="网络播放平台" prop="networkEnable">
+          <el-switch v-model="configDialog.form.networkEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="network" v-if="configDialog.form.networkEnable">
+          <el-input v-model="configDialog.form.network" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个网络播放平台,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="制作单位" prop="unitEnable">
+          <el-switch v-model="configDialog.form.unitEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="unit" v-if="configDialog.form.unitEnable">
+          <el-input v-model="configDialog.form.unit" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个制作单位,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="专家顾问团队" prop="teamEnable">
+          <el-switch v-model="configDialog.form.teamEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="team" v-if="configDialog.form.teamEnable">
+          <el-input v-model="configDialog.form.team" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个专家顾问,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="支持单位" prop="supportEnable">
+          <el-switch v-model="configDialog.form.supportEnable" active-color="#13ce66"/>
+        </el-form-item>
+        <el-form-item prop="support" v-if="configDialog.form.supportEnable">
+          <el-input v-model="configDialog.form.support" clearable></el-input>
+          <i class="el-icon-warning"/>
+          <span style="color: rgb(153, 169, 191)"> 多个支持单位,请用英文逗号隔开</span>
+        </el-form-item>
+        <el-form-item label="监督投诉电话" prop="complaintPhone">
+          <el-input v-model="configDialog.form.complaintPhone" placeholder="请输入监督投诉电话" clearable/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary"
+                   :loading="configDialog.updating"
+                   :disabled="configDialog.updating"
+                   @click="submitConfigForm">确 定</el-button>
+        <el-button @click="cancelConfig">取 消</el-button>
+      </div>
+    </el-dialog>
+
     <el-drawer
-        :with-header="false"
-        size="75%"
-         :title="show.title" :visible.sync="show.open" append-to-body>
-     <userCourseCatalogDetails  ref="userCourseCatalogDetails" />
-   </el-drawer>
+      :with-header="false"
+      size="75%"
+      :title="show.title" :visible.sync="show.open" append-to-body>
+      <userCourseCatalogDetails ref="userCourseCatalogDetails"/>
+    </el-drawer>
   </div>
 </template>
 
 <script>
-import { listUserCourse, getUserCourse, delUserCourse, addUserCourse, updateUserCourse, exportUserCourse,updateIsShow,putOn,pullOff } from "@/api/course/userCourse";
+import {
+  listUserCourse,
+  getUserCourse,
+  delUserCourse,
+  addUserCourse,
+  updateUserCourse,
+  exportUserCourse,
+  updateIsShow,
+  copyUserCourse,
+  putOn,
+  pullOff, updateUserCourseRedPage,
+  editConfig
+} from '@/api/course/userCourse'
+
+import {getSelectableRange} from "@/api/qw/sopTemp";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import Editor from '@/components/Editor/wang';
 import ImageUpload from '@/components/ImageUpload/index';
+import {listBySearch} from "@/api/course/userTalent";
 import userCourseCatalogDetails from '../../components/course/userCourseCatalogDetails.vue';
-import { getAllCourseCategoryList,getCatePidList ,getCateListByPid} from "@/api/course/userCourseCategory";
+import {getAllCourseCategoryList, getCatePidList, getCateListByPid} from "@/api/course/userCourseCategory";
 import {allList} from "@/api/company/company";
-
+import VideoUpload from '@/components/VideoUpload/index.vue'
+import { getConfigByKey } from '@/api/system/config'
 export default {
   name: "UserCourse",
   components: {
+    VideoUpload,
     Treeselect,
-    Editor,ImageUpload,userCourseCatalogDetails
+    Editor, ImageUpload, userCourseCatalogDetails
+  },
+  watch:{
+    // 深度监听 rules 数组的变化,以更新总权重
+    "openRedPage.rules": {
+      handler(val) {
+        // this.calculateTotalWeight();
+        this.validateRules();
+      },
+      deep: true,
+    },
   },
   data() {
     return {
-      talentParam:{
-        phone:null,
-        talentId:null
+      /** 与后端 is_private 一致:1-课程管理(私域),0-公域课程管理 */
+      pageIsPrivate: 1,
+      talentParam: {
+        phone: null,
+        talentId: null
       },
-      talentList:[],
-      show:{
-        title:"目录管理",
-        open:false
+      talentList: [],
+      startTimeRange: [],
+      show: {
+        title: "目录管理",
+        open: false
       },
-      activeName:"1",
-      projectOptions:[],
-      tagsOptions:[],
-      tags:[],
+      activeName: "1",
+      projectOptions: [],
+      tagsOptions: [],
+      tags: [],
       companyIds: [],
-      courseTypeOptions:[],
+      courseTypeOptions: [],
       orOptions: [],
       specShowOptions: [],
       specTypeOptions: [],
-      categoryOptions:[],
-      subCategoryOptions:[],
-      querySubCateOptions:[],
+      categoryOptions: [],
+      subCategoryOptions: [],
+      querySubCateOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -173,12 +538,26 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
+      openRedPage:{
+        open:false,
+        courseId:null,
+        courseName:null,
+        redPacketMoney:0.1,
+        //随机红包配置
+        rules:[
+          {
+            minAmount: 0.01,
+            maxAmount: 0.01,
+            weight: 100,
+          }
+        ]
+      },
       // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
         cateId: null,
-        subCateId:null,
+        subCateId: null,
         title: null,
         imgUrl: null,
         userId: null,
@@ -193,6 +572,7 @@ export default {
         hotRanking: null,
         integral: null,
         price: null,
+        courseId: null,
         isPrivate: 1,
         companyIdsList:[],
       },
@@ -200,77 +580,122 @@ export default {
       form: {},
       // 表单校验
       rules: {
-        // talentId: [
-        //   { required: true, message: "归属达人不能为空", trigger: "change" }
-        // ],
-        cateId: [
-          { required: true, message: "分类不能为空", trigger: "change" }
-        ],
-        subCateId: [
-          { required: true, message: "子分类不能为空", trigger: "change" }
-        ],
         courseName: [
-          { required: true, message: "课堂名称不能为空", trigger: "blur" }
+          {required: true, message: "课堂名称不能为空", trigger: "blur"}
         ],
         imgUrl: [
-          { required: true, message: "封面图片不能为空", trigger: "blur" }
-        ],
-        secondImg: [
-          { required: true, message: "小封面图片不能为空", trigger: "blur" }
+          {required: true, message: "封面图片不能为空", trigger: "blur"}
         ],
         isTui: [
-          { required: true, message: "是否推荐不能为空", trigger: "blur" }
+          {required: true, message: "是否推荐不能为空", trigger: "blur"}
         ],
         isBest: [
-          { required: true, message: "是否精选不能为空", trigger: "blur" }
+          {required: true, message: "是否精选不能为空", trigger: "blur"}
         ],
         isFast: [
-          { required: true, message: "是否允许快进不能为空", trigger: "blur" }
+          {required: true, message: "是否允许快进不能为空", trigger: "blur"}
         ],
         isAutoPlay: [
-          { required: true, message: "是否自动播放不能为空", trigger: "blur" }
+          {required: true, message: "是否自动播放不能为空", trigger: "blur"}
         ],
         sort: [
-          { required: true, message: "排序不能为空", trigger: "blur" }
+          {required: true, message: "排序不能为空", trigger: "blur"}
         ],
         views: [
-          { required: true, message: "播放量不能为空", trigger: "blur" }
+          {required: true, message: "播放量不能为空", trigger: "blur"}
         ],
         likes: [
-          { required: true, message: "点赞数不能为空", trigger: "blur" }
+          {required: true, message: "点赞数不能为空", trigger: "blur"}
         ],
         favoriteNum: [
-          { required: true, message: "收藏数不能为空", trigger: "blur" }
+          {required: true, message: "收藏数不能为空", trigger: "blur"}
         ],
         shares: [
-          { required: true, message: "分享数不能为空", trigger: "blur" }
+          {required: true, message: "分享数不能为空", trigger: "blur"}
         ],
         isIntegral: [
-          { required: true, message: "是否允许积分兑换不能为空", trigger: "blur" }
-        ],
-        price: [
-          { required: true, message: "原价不能为空", trigger: "blur" }
-        ],
-        sellPrice: [
-          { required: true, message: "售价不能为空", trigger: "blur" }
+          {required: true, message: "是否允许积分兑换不能为空", trigger: "blur"}
         ],
         isShow: [
-          { required: true, message: "上架状态不能为空", trigger: "blur" }
+          {required: true, message: "上架状态不能为空", trigger: "blur"}
         ],
         isPrivate: [
-          { required: true, message: "公互联网医院不能为空", trigger: "blur" }
+          {required: true, message: "公私域不能为空", trigger: "blur"}
         ],
         integral: [
-          { required: true, message: "小节兑换积分不能为空", trigger: "blur" }
+          {required: true, message: "小节兑换积分不能为空", trigger: "blur"}
         ],
-      }
+      },
+
+      rulesRedPage:{
+        redPacketMoney: [
+          {required: true, message: "红包金额不能为空", trigger: "blur"}
+        ],
+      },
+      configDialog: {
+        dialogVisible: false,
+        updating: false,
+        form: {
+          id: null,
+          coverImg: null,
+          tvEnable: 0,
+          tv: null,
+          networkEnable: 0,
+          network: null,
+          unitEnable: 0,
+          unit: null,
+          teamEnable: 0,
+          team: null,
+          supportEnable: 0,
+          support: null,
+          //监督投诉电话
+          complaintPhone: null,
+        },
+        rules: {
+          tv: [
+            { required: true, message: '首播电视台不能为空', trigger: 'blur' }
+          ],
+          network: [
+            { required: true, message: '网络播放平台不能为空', trigger: 'blur' }
+          ],
+          unit: [
+            { required: true, message: '制作单位不能为空', trigger: 'blur' }
+          ],
+          team: [
+            { required: true, message: '专家顾问团队不能为空', trigger: 'blur' }
+          ],
+          support: [
+            { required: true, message: '支持单位不能为空', trigger: 'blur' }
+          ],
+        }
+      },
+      enableRandomRedPacket:false
     };
   },
   created() {
     this.getList();
+    getConfigByKey('randomRedpacket:config').then(res=>{
+      console.log("res::")
+      console.log(res);
+      let configData = res.data;
+      if(!!configData && !!configData.configValue){
+        let configValue = JSON.parse(configData.configValue);
+        console.log(configValue);
+        if(!!configValue.enableRandomRedpacket){
+          this.enableRandomRedPacket = configValue.enableRandomRedpacket;
+        }
+      }
+    }).catch(res=>{
+
+    })
     getCatePidList().then(response => {
-        this.categoryOptions = response.data;
+      this.categoryOptions = response.data;
     });
+
+
+    getSelectableRange().then(e => {
+      this.startTimeRange = e.data;
+    })
     // this.getTreeselect();
     this.getDicts("sys_spec_show").then(response => {
       this.specShowOptions = response.data;
@@ -295,37 +720,52 @@ export default {
     });
   },
   methods: {
+    selectTalent() {
 
-
-    getQuerySubCateList(pid){
-      this.queryParams.subCateId=null;
-      if(pid == ''){
-        this.querySubCateOptions=[];
+    },
+    talentMethod(query) {
+      if (query !== '') {
+        this.talentParam.phone = query;
+        listBySearch(this.talentParam).then(response => {
+          this.talentList = response.data;
+        });
+      }
+    },
+    getSubCateList(pid) {
+      this.form.subCateId = null;
+      if (pid == '') {
+        this.subCategoryOptions = [];
         return
       }
-      this.queryParams.subCateId=null;
+      getCateListByPid(pid).then(response => {
+        this.subCategoryOptions = response.data;
+      });
+    },
+    getQuerySubCateList(pid) {
+      this.queryParams.subCateId = null;
+      if (pid == '') {
+        this.querySubCateOptions = [];
+        return
+      }
+      this.queryParams.subCateId = null;
       getCateListByPid(pid).then(response => {
         this.querySubCateOptions = response.data;
       });
     },
     handleShow(row) {
       var isShowValue = row.isShow === 0 ? 1 : 0;
-      var course = { courseId: row.courseId, isShow: isShowValue };
+      var course = {courseId: row.courseId, isShow: isShowValue};
       updateIsShow(course).then(response => {
         this.msgSuccess("修改成功");
         this.getList();
       });
     },
-    handleCatalog(row){
+    handleCatalog(row) {
       const courseId = row.courseId;
-      this.show.open=true;
-        setTimeout(() => {
-             this.$refs.userCourseCatalogDetails.getDetails(courseId,row.courseName);
-        }, 200);
-    },
-    handleClick(tab, event) {
-      this.queryParams.isShow=tab.name;
-      this.getList();
+      this.show.open = true;
+      setTimeout(() => {
+        this.$refs.userCourseCatalogDetails.getDetails(courseId, row.courseName, row.isPrivate);
+      }, 200);
     },
     /** 转换课堂分类数据结构 */
     normalizer(node) {
@@ -342,12 +782,13 @@ export default {
       getAllCourseCategoryList().then(response => {
         this.categoryOptions = [];
         const data = this.handleTree(response.data, "cateId", "pid");
-        this.categoryOptions=data;
+        this.categoryOptions = data;
       });
     },
     /** 查询课程列表 */
     getList() {
       this.loading = true;
+      this.queryParams.isPrivate = this.pageIsPrivate;
       listUserCourse(this.queryParams).then(response => {
         this.userCourseList = response.rows;
         this.total = response.total;
@@ -364,10 +805,10 @@ export default {
       this.form = {
         courseId: null,
         cateId: null,
-        subCateId:null,
+        subCateId: null,
         title: null,
         imgUrl: null,
-        secondImg:null,
+        secondImg: null,
         userId: null,
         sort: null,
         createTime: null,
@@ -375,27 +816,26 @@ export default {
         status: 0,
         isVip: null,
         isAutoPlay: "1",
-        isIntegral:"0",
+        isIntegral: "0",
         isShow: "1",
-        isFast:"1",
-        isTui:"1",
-        isBest:"1",
-        isNext:"1",
-        isPrivate:"0",
+        isFast: "1",
+        isTui: "1",
+        isBest: "1",
+        isNext: "1",
+        isPrivate: String(this.pageIsPrivate),
         views: 100000,
         duration: null,
         description: null,
         hotRanking: null,
         integral: null,
         price: null,
-        likes:100000,
-        shares:100000,
-        favoriteNum:100000,
-        hotNum:100000,
-        companyIdsList:[]
+        likes: 100000,
+        shares: 100000,
+        favoriteNum: 100000,
+        hotNum: 100000,
       };
-      this.tags=[];
-      this.subCategoryOptions=[]
+      this.tags = [];
+      this.subCategoryOptions = []
       this.companyIds = []
       this.resetForm("form");
     },
@@ -407,39 +847,42 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
-      this.queryParams.companyIdsList=null;
-      this.queryParams.isShow=this.activeName
+      this.queryParams.companyIdsList = [];
+      this.queryParams.isShow = this.activeName
+      this.queryParams.isPrivate = this.pageIsPrivate;
       this.handleQuery();
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.courseId)
-      this.single = selection.length!==1
+      this.single = selection.length !== 1
       this.multiple = !selection.length
     },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
-      this.talentList=[];
+      this.talentList = [];
       this.open = true;
       this.title = "添加课程";
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
-      this.talentList=[];
+      this.talentList = [];
       const courseId = row.courseId || this.ids
       getUserCourse(courseId).then(response => {
         this.form = response.data;
         // this.form.cateId = response.data.cateId.toString();
-        getCateListByPid(this.form.cateId).then(response => {
-          this.subCategoryOptions = response.data;
-        });
+        if (this.form.cateId) {
+          getCateListByPid(this.form.cateId).then(response => {
+            this.subCategoryOptions = response.data;
+          });
+        }
         // this.form.courseType = response.data.courseType.toString();
-        if(response.data.project!=null){
+        if (response.data.project != null) {
           this.form.project = response.data.project.toString();
         }
-        if(response.data.tags!=null){
+        if (response.data.tags != null) {
           this.tags = response.data.tags.split(",")
         }
         this.form.isAutoPlay = response.data.isAutoPlay.toString();
@@ -449,22 +892,37 @@ export default {
         this.form.isIntegral = response.data.isIntegral.toString();
         this.form.isTui = response.data.isTui.toString();
         this.form.isNext = response.data.isNext.toString();
-        this.form.isPrivate = response.data.isPrivate.toString();
+        this.form.isPrivate = (response.data.isPrivate != null && response.data.isPrivate !== '')
+          ? response.data.isPrivate.toString()
+          : String(this.pageIsPrivate);
         this.talentParam.talentId = response.data.talentId;
+        if (this.form.companyIds != null) {
+          this.companyIds = ((this.form.companyIds).split(",").map(Number))
+        } else {
+          this.companyIds = []
+        }
+
+        listBySearch(this.talentParam).then(response => {
+          this.talentList = response.data;
+        });
         this.open = true;
         this.title = "修改课程";
       });
     },
+
+    handleUpdateRedPage(row){
+      this.openRedPage.open=true;
+      this.openRedPage.courseId=row.courseId;
+      this.openRedPage.courseName=row.courseName;
+
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {
         if (valid) {
-          if(this.tags.length>0){
-              this.form.tags=this.tags.toString();
-            }
-            else{
-              this.form.tags=null
-            }
+
+          this.form.companyIds = this.companyIds.toString()
+          this.form.isPrivate = this.pageIsPrivate
           if (this.form.courseId != null) {
             updateUserCourse(this.form).then(response => {
               this.msgSuccess("修改成功");
@@ -481,67 +939,262 @@ export default {
         }
       });
     },
+
+    submitFormRedPage(){
+
+      const courseId = this.openRedPage.courseId;
+      const redPacketMoney = this.openRedPage.redPacketMoney;
+      let randomRedPacketRules = JSON.stringify( this.openRedPage.rules);
+      console.log(randomRedPacketRules)
+      this.$confirm('是否确认将课程id 为"' + courseId + '"的红包批量修改为:【'+redPacketMoney+'】?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return updateUserCourseRedPage({courseId:courseId,redPacketMoney:redPacketMoney,randomRedPacketRules:randomRedPacketRules});
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("修改成功");
+        this.openRedPage.open=false;
+      }).finally(() => {
+        this.getList();
+        this.openRedPage.open=false;
+      });
+
+    },
+    cancelRedPage(){
+      this.openRedPage.open=false;
+    },
+
+    /** 复制按钮操作 */
+    handleCopy(row) {
+      const courseId = row.courseId;
+      this.$confirm('是否确认复制课程编号为"' + courseId + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return copyUserCourse(courseId);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("复制成功");
+      }).catch(() => {
+      });
+    },
     /** 删除按钮操作 */
     handleDelete(row) {
       const courseIds = row.courseId || this.ids;
       this.$confirm('是否确认删除课程编号为"' + courseIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delUserCourse(courseIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return delUserCourse(courseIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {
+      });
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
+      const queryParams = { ...this.queryParams, isPrivate: this.pageIsPrivate };
       this.$confirm('是否确认导出所有课程数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportUserCourse(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportUserCourse(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {
+      });
     },
     putOn() {
-      const courseIds =this.ids;
-      if(courseIds==null||courseIds==""){
-         return this.$message("未选择课程");
+      const courseIds = this.ids;
+      if (courseIds == null || courseIds == "") {
+        return this.$message("未选择课程");
       }
       this.$confirm('是否确认批量上架课程?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return putOn(courseIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("上架成功");
-        }).catch(function() {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return putOn(courseIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("上架成功");
+      }).catch(function () {
+      });
     },
     pullOff() {
-      const courseIds =this.ids;
-      if(courseIds==null||courseIds==""){
-         return this.$message("未选择课程");
+      const courseIds = this.ids;
+      if (courseIds == null || courseIds == "") {
+        return this.$message("未选择课程");
       }
       this.$confirm('是否确认批量下架课程?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return pullOff(courseIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("下架成功");
-        }).catch(function() {});
-    }
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return pullOff(courseIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("下架成功");
+      }).catch(function () {
+      });
+    },
+    configCourse(row) {
+      if (row.configJson) {
+        this.configDialog.form = {
+          tvEnable: 0,
+          networkEnable: 0,
+          unitEnable: 0,
+          teamEnable: 0,
+          supportEnable: 0,
+          ...JSON.parse(row.configJson)
+        }
+      }
+      this.configDialog.form.id = row.courseId
+      this.configDialog.dialogVisible = true;
+      this.configDialog.updating = false
+    },
+    submitConfigForm() {
+      this.$refs['configForm'].validate(valid => {
+        if (!valid) {
+          this.msgError('请完善配置内容')
+          return
+        }
+
+        if (this.configDialog.updating) {
+          return
+        }
+        this.configDialog.updating = true
+
+        const content = {
+          coverImg: this.configDialog.form.coverImg,
+          tvEnable: this.configDialog.form.tvEnable,
+          tv: this.configDialog.form.tv?.replace(",",","),
+          networkEnable: this.configDialog.form.networkEnable,
+          network: this.configDialog.form.network?.replace(",",","),
+          unitEnable: this.configDialog.form.unitEnable,
+          unit: this.configDialog.form.unit?.replace(",",","),
+          teamEnable: this.configDialog.form.teamEnable,
+          team: this.configDialog.form.team?.replace(",",","),
+          supportEnable: this.configDialog.form.supportEnable,
+          support: this.configDialog.form.support?.replace(",",","),
+        }
+
+        const params = {
+          id: this.configDialog.form.id,
+          configJson: JSON.stringify(content)
+        }
+
+        editConfig(params).then(() => {
+          this.msgSuccess('修改成功')
+          this.configDialog.dialogVisible = false;
+          this.getList()
+        }).finally(() => {
+          setTimeout(() => {
+            this.configDialog.updating = false
+          }, 500)
+        })
+      })
+    },
+    cancelConfig() {
+      this.configDialog.form = {
+        id: null,
+        coverImg: null,
+        tvEnable: 0,
+        tv: null,
+        networkEnable: 0,
+        network: null,
+        unitEnable: 0,
+        unit: null,
+        teamEnable: 0,
+        team: null,
+        supportEnable: 0,
+        support: null
+      }
+      this.resetForm('configForm')
+      this.configDialog.dialogVisible = false;
+    },
+    // 实时过滤金额输入,只允许两位小数
+    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;
+    },
+    deleteRule(index) {
+      this.$confirm("确定要删除这个区间吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      }).then(() => {
+        this.openRedPage.rules.splice(index, 1);
+        this.$message({
+          type: "success",
+          message: "删除成功!",
+        });
+      });
+    },
+    addRule(index) {
+      // 在当前行的后面插入一个新行
+      this.openRedPage.rules.splice(index + 1, 0, {
+        minAmount: 0.01,
+        maxAmount: 0.01,
+        weight: 100,
+      });
+    },
+    // 自定义校验规则:确保最大金额大于最小金额
+    validateMinAmount(rule, value, callback) {
+      // debugger;
+      // const maxAmount = this.form29.rules[].maxAmount
+
+      const index = rule.index;
+      const maxAmount = this.openRedPage.rules[index].maxAmount;
+
+      if (value > maxAmount) {
+        callback(new Error("最小金额不能大于最大金额"));
+      } else {
+        callback();
+      }
+    },
+    validateRules() {
+      this.openRedPage.rules.forEach((rule) => {
+        if (rule.minAmount === undefined || rule.minAmount < 0.01) {
+          rule.minAmount = 0.01;
+        }
+        if (rule.maxAmount === undefined || rule.maxAmount < rule.minAmount) {
+          rule.maxAmount = rule.minAmount;
+        }
+        if (rule.weight === undefined || rule.weight < 1) {
+          rule.weight = 1;
+        }
+      });
+    },
+
   }
 };
 </script>

+ 0 - 4
src/views/course/userVideo/index.vue

@@ -381,14 +381,10 @@
 <script>
 import VideoUpload from '@/components/VideoUpload/index';
 import { listUserVideo, getUserVideo, delUserVideo, addUserVideo, updateUserVideo, exportUserVideo,auditUserVideo,putOn,pullOff } from "@/api/course/userVideo";
-import {getSignature,uploadHuaWeiVod} from "@/api/common"
 import { listBySearch} from "@/api/course/userTalent";
 import { subList} from "@/api/course/userVideoTags";
 import { packageBySearch} from "@/api/his/package";
-import TcVod from 'vod-js-sdk-v6'
 import userVideoDetails from '../../components/course/userVideoDetails.vue';
-import { BasicCredentials } from '@huaweicloud/huaweicloud-sdk-core';
-import { VodClient, VodRegion, CreateAssetByFileUploadRequest,ShowAssetTempAuthorityRequest } from '@huaweicloud/huaweicloud-sdk-vod';
 import { Loading } from 'element-ui';
 import { uploadObject } from '@/utils/cos.js';
 import { uploadToOBS } from '@/utils/obs.js';

+ 103 - 380
src/views/qw/sopTemp/index.vue

@@ -1,6 +1,19 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="公司名" prop="companyId">
+        <select-tree
+          v-model="selectedCompanyList"
+          :raw-data="deptList"
+          placeholder="请选择销售"
+          :parentSelectable="true"
+          :multiple="true"
+          component-width="300px"
+          :max-display-tags="3"
+          :check-strictly="false"
+          :return-leaf-only="false"
+        ></select-tree>
+      </el-form-item>
       <el-form-item label="模板标题" prop="name">
         <el-input
           v-model="queryParams.name"
@@ -10,6 +23,15 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="模板编号" prop="id">
+        <el-input
+          v-model="queryParams.id"
+          placeholder="请输入模板编号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
       <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
           <el-option
@@ -39,21 +61,6 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="所属销售" prop="createBy">
-        <el-select v-model="queryParams.createBy" clearable filterable remote
-                   placeholder="请输入关键词" :remote-method="loadCompanyUserOptions"
-                   v-select-load-more="loadMoreCompanyUserOptions"
-                   :loading="companyUserOptionsLoading"
-                   @change="handleCompanyUserChange"
-                   @visible-change="handleCompanyUserDropdownVisible">
-          <el-option
-            v-for="item in companyUserOptions"
-            :key="item.dictValue"
-            :label="item.dictLabel"
-            :value="item.dictValue">
-          </el-option>
-        </el-select>
-      </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@@ -73,7 +80,6 @@
         <!--        >新增</el-button>-->
 
         <el-dropdown
-          v-hasPermi="['qw:sopTemp:add']"
           @command="handleCommand"
           trigger="click"
           placement="bottom-start"
@@ -126,9 +132,9 @@
     <el-table v-loading="loading" border :data="sopTempList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center"/>
       <el-table-column label="模板编号" align="center" prop="id"/>
-      <el-table-column label="公司名称" align="center">
+      <el-table-column label="销售公司" align="center">
         <template slot-scope="scope">
-          <el-tag v-for="item in companys" v-if="scope.row.companyId == item.companyId">{{item.companyName}}</el-tag>
+          <el-tag v-for="item in companys" v-if="scope.row.companyId == item.companyId">{{ item.companyName }}</el-tag>
         </template>
       </el-table-column>
       <el-table-column label="模板标题" align="center" prop="name"/>
@@ -144,10 +150,10 @@
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime"/>
-      <el-table-column label="创建人" align="center" prop="createByName"/>
-      <el-table-column label="创建部门" align="center" prop="createByDeptName"/>
       <el-table-column label="修改时间" align="center" prop="updateTime"/>
       <el-table-column label="排序" align="center" prop="sort"/>
+      <el-table-column label="创建人" align="center" prop="createByName"/>
+      <el-table-column label="创建人部门" align="center" prop="createByDeptName"/>
 
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
@@ -155,18 +161,10 @@
             size="mini"
             type="text"
             icon="el-icon-connection"
-
             @click="copyTemplate(scope.row)"
             v-hasPermi="['qw:sopTemp:edit']"
           >复制模板
           </el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-share"
-            @click="shareTemplate(scope.row)"
-            v-hasPermi="['qw:sopTemp:share']"
-          >分享模板</el-button>
           <el-button
             size="mini"
             type="text"
@@ -191,15 +189,6 @@
             v-hasPermi="['qw:sopTemp:edit']"
           >管理规则
           </el-button>
-          <el-button
-            v-if="scope.row.sendType == 11"
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleBatchOfficial(scope.row)"
-            v-hasPermi="['qw:sopTemp:edit']"
-          >开关官方群发
-          </el-button>
           <el-button
             size="mini"
             type="text"
@@ -234,6 +223,16 @@
         <el-form-item label="名称" prop="name">
           <el-input v-model="form.name" placeholder="请输入模板标题"/>
         </el-form-item>
+        <el-form-item label="销售公司" prop="companyId">
+          <el-select filterable v-model="form.companyId" placeholder="请选择公司名" size="small">
+            <el-option
+              v-for="item in companys"
+              :key="item.companyId"
+              :label="item.companyName"
+              :value="item.companyId"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item label="状态">
           <el-radio-group v-model="form.status">
             <el-radio
@@ -254,20 +253,9 @@
             />
           </el-select>
         </el-form-item>
-
-        <el-form-item label="归属部门" prop="createByDept">
-          <treeselect
-            style="width: 220px"
-            :clearable="false"
-            v-model="form.createByDept"
-            :options="deptOptions"
-            clearable
-            :show-count="true"
-            placeholder="请选择归属部门"
-          />
-        </el-form-item>
         <el-form-item label="课程" prop="courseId" v-if="form.sendType == 11 && !form.id">
-          <el-select v-model="form.courseId"placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable>
+          <el-select v-model="form.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini"
+                     filterable>
             <el-option
               v-for="dict in courseList"
               :key="dict.dictValue"
@@ -282,31 +270,6 @@
         <el-form-item label="排序" prop="sort">
           <el-input-number v-model="form.sort" :min="0" label="排序"></el-input-number>
         </el-form-item>
-        <el-form-item label="是否开启官方群发" v-if="form.sendType == 11 && (form.id === null || form.id === undefined)">
-          <el-radio-group v-model="form.openOfficial">
-            <el-radio
-              v-for="dict in openOfficialOptions"
-              :key="dict.dictValue"
-              :label="dict.dictValue"
-            >{{ dict.dictLabel }}
-            </el-radio>
-          </el-radio-group>
-        </el-form-item>
-
-        <el-form-item label="是否开启@所有人" v-if="form.sendType == 11 && (form.id === null || form.id === undefined)">
-          <el-radio-group v-model="form.openIsAtAll">
-            <el-radio
-              v-for="dict in openIsAtAllOptions"
-              :key="dict.dictValue"
-              :label="dict.dictValue"
-            >{{ dict.dictLabel }}
-            </el-radio>
-          </el-radio-group>
-        </el-form-item>
-
-        <el-form-item label="内容" prop="modeContent">
-          <el-input v-model="form.modeContent" placeholder="请输入文字内容"  type="textarea" :rows="3"/>
-        </el-form-item>
         <el-form-item label="发课时间" prop="time" v-if="form.sendType == 11 && !form.id">
           <el-time-picker
             class="custom-input"
@@ -318,27 +281,19 @@
           </el-time-picker>
         </el-form-item>
         <el-form-item label="每天催课次数" prop="num" v-if="form.sendType == 11 && !form.id">
-          <el-input-number v-model="form.num" :min="0" label="每天催课次数" @change="sendNumChange"></el-input-number>
+          <el-input-number v-model="form.num" :min="1" label="每天催课次数" @change="sendNumChange"></el-input-number>
         </el-form-item>
-        <el-form-item label="催课时间" v-if="form.sendType == 11 && !form.id && form.num > 0">
-          <div v-for="(item, index) in form.timeList" :key="index" style="margin-bottom: 10px;">
-            <el-time-picker
-              class="custom-input"
-              v-model="item.value"
-              value-format="HH:mm"
-              format="HH:mm"
-              :picker-options="{ selectableRange: startTimeRange }"
-              placeholder="时间"
-              style="width: 150px; height: 20px; margin-left: 10px; margin-top: 10px">
-            </el-time-picker>
-
-            <el-input
-              v-model="item.desc"
-              placeholder="催课内容"
-              type="textarea" :rows="2"
-              style="width: 500px; margin-left: 10px; margin-top: 10px;">
-            </el-input>
-          </div>
+        <el-form-item label="催课时间" v-if="form.sendType == 11 && !form.id">
+          <el-time-picker
+            v-for="item in form.timeList"
+            class="custom-input"
+            v-model="item.value"
+            value-format="HH:mm"
+            format="HH:mm"
+            :picker-options="{ selectableRange: startTimeRange }"
+            placeholder="时间"
+            style="width: 200px;height: 20px;margin-left: 10px;margin-top: 10px">
+          </el-time-picker>
         </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer" style="display: flex;justify-content: flex-end;">
@@ -352,7 +307,8 @@
         <el-table-column label="小节" align="left" prop="videoName"/>
         <el-table-column label="金额" align="center">
           <template slot-scope="scope">
-            <el-input-number v-model="scope.row.redPacketMoney" :min="0.01" step="0.01" label="红包金额"></el-input-number>
+            <el-input-number v-model="scope.row.redPacketMoney" :min="0.01" step="0.01"
+                             label="红包金额"></el-input-number>
           </template>
         </el-table-column>
       </el-table>
@@ -360,82 +316,6 @@
         <el-button type="primary" @click="updateRedData" :disabled="redData.loading">保 存</el-button>
       </div>
     </el-dialog>
-    
-    <el-dialog title="批量编辑官方群发" :visible.sync="official.open" width="500px" append-to-body>
-       <el-form :model="officialForm" ref="officialForm" :inline="true">
-         <el-form-item  label="官方群发" prop="isOfficial">
-            <el-radio-group v-model="officialForm.isOfficial">
-              <el-radio :label="0">关</el-radio>
-              <el-radio :label="1">开</el-radio>
-            </el-radio-group>
-         </el-form-item>
-       </el-form>
-      <div slot="footer" class="dialog-footer" style="display: flex;justify-content: flex-end;">
-        <el-button type="primary" @click="updateOfficial" :loading="official.loading">保 存</el-button>
-      </div>
-    </el-dialog>
-
-    <el-dialog :title="shareOptions.title" :visible.sync="shareOptions.open" width="800px" append-to-body>
-
-      <el-form :model="queryCompanyParams" ref="queryCompanyForm" :inline="true" v-show="showSearch" label-width="68px">
-        <el-form-item label="公司名称" prop="companyName">
-          <el-input
-            style="width: 220px"
-            v-model="queryCompanyParams.companyName"
-            placeholder="请输入企业名称"
-            clearable
-            size="small"
-            @keyup.enter.native="handleCompanyQuery"
-          />
-        </el-form-item>
-
-        <el-form-item label="状态" prop="status">
-          <el-select style="width: 220px" v-model="queryCompanyParams.status" placeholder="请选择状态" clearable size="small">
-            <el-option
-              v-for="dict in statusOptions"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              :value="dict.dictValue"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleCompanyQuery">搜索</el-button>
-          <el-button icon="el-icon-refresh" size="mini" @click="resetCompanyQuery">重置</el-button>
-        </el-form-item>
-      </el-form>
-      <el-row :gutter="10" class="mb8">
-        <el-col :span="1.5">
-          <el-button
-            plain
-            type="primary"
-            icon="el-icon-connection"
-            size="mini"
-            :disabled="multiple"
-            @click="handleShareTemplate"
-            v-hasPermi="['qw:sopTemp:share']"
-          >分享模板</el-button>
-        </el-col>
-      </el-row>
-      <el-table v-loading="companysloading" border :data="companyList" @selection-change="handleSelectionCompany">
-        <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="公司编号" align="center" prop="companyId" />
-                <el-table-column label="企业名" align="center" prop="companyName" />
-        <!--        <el-table-column label="备注" align="center" prop="remark"/>-->
-        <el-table-column label="状态" align="center" prop="status" >
-          <template slot-scope="scope">
-            <el-tag prop="status" v-for="(item, index) in statusOptions"  :type="scope.row.status==1?'success':'danger'"  v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
-          </template>
-        </el-table-column>
-      </el-table>
-      <pagination
-        v-show="companyTotal>0"
-        :total="companyTotal"
-        :page.sync="queryCompanyParams.pageNum"
-        :limit.sync="queryCompanyParams.pageSize"
-        @pagination="getCompanyList"
-      />
-    </el-dialog>
   </div>
 </template>
 
@@ -445,34 +325,27 @@ import {
   copyTemplate,
   delSopTemp,
   exportSopTemp,
-  getSopTemp,
-  listSopTemp,
   getSelectableRange,
+  getSopTemp,
   redList,
+  listSopTemp,
   shareSopTemp,
   updateRedPackage,
-  updateTemp,
-  batchOpenOrCloseOfficial
+  updateTemp
 } from "@/api/qw/sopTemp";
-import { getCompanyList, listCompany } from '@/api/company/company'
-import {courseList, getRoles} from "@/api/qw/sop";
-import {treeselect} from "../../../api/company/companyDept";
-import Treeselect from "@riophae/vue-treeselect";
-import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-import {getCompanyUserListLikeName} from "../../../api/company/companyUser";
+import {getCompanyList} from "@/api/company/company";
+import {courseList} from "@/api/qw/sop";
+import fa from "element-ui/src/locale/lang/fa";
+import SelectTree from '@/components/TreeSelect/index.vue'
+import { getDeptData } from '@/api/system/employeeStats'
+
 export default {
   name: "SopTemp",
-  components: {Treeselect},
+  components: { SelectTree },
   data() {
     return {
-      officialForm:{
-        tempId:null,
-        isOfficial:null,
-      },
-      official:{
-        open:false,
-        loading:false,
-      },
+      selectedCompanyList: [],
+      deptList: [],
       // 遮罩层
       loading: true,
       companysloading: false,
@@ -481,10 +354,8 @@ export default {
       // 选中数组
       ids: [],
       courseList: [],
-      roles: [],
       //选中的公司
       companys: [],
-      deptOptions: [],
       // 非单个禁用
       single: true,
       // 非多个禁用
@@ -500,7 +371,6 @@ export default {
       sysQwSopType: [],
       companyList: [],
       projectOptions: [],
-      startTimeRange: [],
       // 弹出层标题
       title: "",
       // 是否显示弹出层
@@ -508,8 +378,8 @@ export default {
       command: 0,
       // 状态字典
       statusOptions: [],
-      openOfficialOptions: [],
-      openIsAtAllOptions: [],
+      startTimeRange: [],
+
       shareOptions: {
         title: '分享模板',
         open: false,
@@ -528,14 +398,14 @@ export default {
       },
       // 查询参数
       queryParams: {
+        id:null,
         pageNum: 1,
         pageSize: 10,
         name: null,
         setting: null,
         status: '1',
         sort: null,
-        companyId: null,
-        createBy: null
+        companyId: null
       },
       // 表单参数
       form: {},
@@ -565,50 +435,25 @@ export default {
         project:[{
           required: true, message: '所属项目不能为空', trigger: 'blur'
         }],
-        createByDept:[
-          { required: true, message: '归属部门不能为空', trigger: 'blur' }
-        ]
       },
       contentRules: {
         time: [{required: true, message: '时间不能为空', trigger: 'blur'}],
       },
-      // 员工选项列表
-      companyUserOptionsParams: {
-        name: undefined,
-        hasNextPage: false,
-        pageNum: 1,
-        pageSize: 10
-      },
-      companyUserOptionsByAll: [],
-      companyUserOptions: [],
-      companyUserOptionsLoading: false,
-      companyUserFirstLoad: true, // 首次加载标志
-      companyUserDropdownVisible: false, // 下拉框显示状态
     };
   },
   created() {
-    this.getList();
 
-    this.getDeptTreeSelect();
-
-    getRoles().then(res => {
-      this.roles = res.data;
+    getDeptData().then(response => {
+      this.deptList = response.data;
     })
+
     this.getDicts("sys_company_status").then(response => {
       this.statusOptions = response.data;
     });
-
-    this.getDicts("sys_company_or").then(response => {
-      this.openOfficialOptions = response.data;
-    });
-
-    this.getDicts("sys_company_or").then(response => {
-      this.openIsAtAllOptions = response.data;
-    });
-
     getSelectableRange().then(e => {
       this.startTimeRange = e.data;
     })
+
     this.getDicts("sys_course_project").then(response => {
       this.projectOptions = response.data;
     });
@@ -621,85 +466,14 @@ export default {
       this.courseList = response.list;
     });
 
-    this.getCompanyList();
-
     getCompanyList().then(response => {
       this.companys = response.data;
     });
+
+    this.getList();
   },
   methods: {
 
-    handleCompanyUserChange(value) {
-      // 当清空选择时,将空字符串转为 null
-      this.queryParams.createBy = value === '' ? null : value;
-
-    },
-
-    /**
-     * 处理所属销售下拉框显示状态变化
-     */
-    handleCompanyUserDropdownVisible(visible) {
-      this.companyUserDropdownVisible = visible;
-      if (visible && this.companyUserFirstLoad) {
-        // 首次展开下拉框时加载数据
-        this.companyUserFirstLoad = false;
-        this.loadCompanyUserOptions('');
-      } else if (visible && this.companyUserOptions.length === 0) {
-        // 下拉框显示但无数据时重新加载
-        this.loadCompanyUserOptions('');
-      }
-    },
-
-    /**
-     * 加载更多员工选项
-     */
-    loadMoreCompanyUserOptions() {
-      if (!this.companyUserOptionsParams.hasNextPage) {
-        return;
-      }
-
-      this.companyUserOptionsParams.pageNum += 1
-      this.getCompanyUserListLikeName()
-    },
-
-    /**
-     * 根据名称模糊查询用户列表
-     * @param query 参数
-     */
-    loadCompanyUserOptions(query) {
-      this.companyUserOptions = [];
-      if (query === '') {
-        return;
-      }
-
-      this.companyUserOptionsParams.pageNum = 1
-      this.companyUserOptionsParams.name = query
-      this.companyUserOptionsLoading = true;
-      this.getCompanyUserListLikeName()
-    },
-
-    /**
-     * 获取员工列表
-     */
-    getCompanyUserListLikeName(isAll) {
-
-      if (isAll){
-        this.companyUserOptionsParams.pageSize = 200;
-        getCompanyUserListLikeName(this.companyUserOptionsParams).then(response => {
-          this.companyUserOptionsByAll = [...this.companyUserOptions, ...response.data.list]
-          this.companyUserOptionsParams.hasNextPage = response.data.hasNextPage
-          this.companyUserOptionsLoading = false;
-        });
-      }else {
-        this.companyUserOptionsParams.pageSize = 10;
-        getCompanyUserListLikeName(this.companyUserOptionsParams).then(response => {
-          this.companyUserOptions = [...this.companyUserOptions, ...response.data.list]
-          this.companyUserOptionsParams.hasNextPage = response.data.hasNextPage
-          this.companyUserOptionsLoading = false;
-        });
-      }
-
-    },
     handleCompanyQuery() {
       this.queryCompanyParams.pageNum = 1;
     },
@@ -707,28 +481,18 @@ export default {
       this.resetForm("queryCompanyForm");
       this.handleCompanyQuery();
     },
-
-    getDeptTreeSelect() {
-      treeselect().then((response) => {
-        this.deptOptions = response.data;
-      });
-    },
-
-    /** 查询企业列表 */
-    getCompanyList() {
-      this.companysloading = true;
-      listCompany(this.queryCompanyParams).then(response => {
-        this.companyList = response.rows;
-        this.companyTotal = response.total;
-        this.companysloading = false;
-      });
-    },
     /** 查询sop模板列表 */
     getList() {
       this.loading = true;
+
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.companyUserIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.companyUserIds = [];
+      }
       listSopTemp(this.queryParams).then(response => {
-        this.sopTempList = response.rows;
-        this.total = response.total;
+        this.sopTempList = response.data.list;
+        this.total = response.data.total;
         this.loading = false;
       });
     },
@@ -740,14 +504,13 @@ export default {
     // 表单重置
     reset() {
       this.form = {
+        id: null,
         gap: 1,
         sendType: this.sendType,
         sort: 0,
-        openOfficial: "1",
-        openIsAtAll: "1",
-        time: "",
         num: 1,
-        timeList: [{value: "",desc:""}],
+        time: "",
+        timeList: [{value: ""}],
         status: "1",
       };
       this.resetForm("form");
@@ -759,6 +522,7 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.selectedCompanyList=[];
       this.resetForm("queryForm");
       this.handleQuery();
     },
@@ -797,7 +561,7 @@ export default {
       // if (row.sendType==4) {
       //   this.$router.push(`/qw/sopTemp/updateAiChatTemp/${row.id}/3`)
       // }else{
-      this.$router.push(`/qw/sopTemp/updateSopTemp/${row.id}/3`)
+      this.$router.push(`/course/sopTempe/updateSopTemp/${row.id}/3`)
       // }
     },
     /** 修改按钮操作 */
@@ -815,22 +579,11 @@ export default {
       // if (row.sendType==4) {
       //   this.$router.push(`/qw/sopTemp/updateAiChatTemp/${row.id}/1`)
       // }else{
-      let url = `/qw/sopTemp/updateSopTemp/${row.id}/1`;
+      let url = `/course/sopTempe/updateSopTemp/${row.id}/1`;
       console.info(url)
       this.$router.push(url)
       // }
     },
-    /**
-     * 批量编辑官方群发
-     */
-    handleBatchOfficial(row){
-        this.officialForm={
-           tempId:null,
-           isOfficial:null
-        }
-        this.officialForm.tempId = row.id;
-        this.official.open = true;
-    },
     /** 修改按钮操作 */
     handleUpdateRed(row) {
       this.redData.open = true;
@@ -876,9 +629,9 @@ export default {
           this.title = "修改";
         }
         this.form = response.data;
-        if (!this.form.IsAtAll) {
-        this.form.IsAtAll = "1"; // 默认值
-    }
+        if(response.data.project){
+          this.form.project = String(response.data.project)
+        }
         this.open = true;
       });
     },
@@ -887,27 +640,10 @@ export default {
       delete this.form.rules
       this.$refs["form"].validate(valid => {
         if (valid) {
-
-          if (this.command != 2 && this.form.id == null && this.form.sendType == 11){
-
-            const hasEmptyFields = this.form.timeList.some(item => {
-              return !item.value || !item.desc;
-            });
-
-            if (hasEmptyFields) {
-              this.$message.error("请填写【催课时间】和【催课内容】!");
-              return; // 阻止提交
-            }
-
-          }
-
           let f = JSON.parse(JSON.stringify(this.form));
           if (f.timeList && f.timeList.length > 0) {
-            f.timeDesc = f.timeList.map(item => item.desc);
             f.timeList = f.timeList.map(item => item.value);
           }
-
-          console.log("f-----------",f)
           const loading = this.$loading({
             lock: true,
             text: 'Loading',
@@ -961,7 +697,7 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id || this.ids;
-      this.$confirm('是否确认删除当前所选模板?', "警告", {
+      this.$confirm('是否确认删除sop模板编号为"' + ids + '"的数据项?', "警告", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning"
@@ -981,8 +717,17 @@ export default {
         cancelButtonText: "取消",
         type: "warning"
       }).then(() => {
+        const loadingInstance = this.$loading({
+          lock: true,
+          text: '正在导出数据,请稍候...',
+          background: 'rgba(0, 0, 0, 0.7)'
+        });
+
         this.exportLoading = true;
-        return exportSopTemp(queryParams);
+        return exportSopTemp(queryParams).finally(res=>{
+          loadingInstance.close();
+        });
+
       }).then(response => {
         this.download(response.msg);
         this.exportLoading = false;
@@ -992,34 +737,12 @@ export default {
     sendNumChange(val, old) {
       if (val > old) {
         for (let i = 0; i < val - old; i++) {
-          this.form.timeList.push({value: "",desc:""});
+          this.form.timeList.push({value: ""});
         }
       } else {
         let len = old - val;
         this.form.timeList.splice(Math.max(this.form.timeList.length - len, 0), len);
       }
-    },
-    updateOfficial(){
-      if(!!this.officialForm){
-        if(this.officialForm.tempId == null || this.officialForm.tempId == '' || this.officialForm.tempId == undefined){
-            this.$message.error("参数错误");
-            return;
-        }
-        if(this.officialForm.isOfficial === null || this.officialForm.isOfficial === undefined){
-            this.$message.error("请选择官方群发操作结果");
-            return;
-        }
-      }else{
-          this.$message.error("参数错误");
-      }
-      this.official.loading = true;
-      batchOpenOrCloseOfficial(this.officialForm).then(res=>{
-         this.msgSuccess("保存成功");
-      this.official.loading = false;
-      this.official.open = false;
-      }).catch(res=>{
-      this.official.loading = false;
-      });
     }
   }
 };

+ 8 - 21
vue.config.js

@@ -1,5 +1,6 @@
 'use strict'
 const path = require('path')
+const webpack = require('webpack')
 
 function resolve(dir) {
   return path.join(__dirname, dir)
@@ -28,6 +29,7 @@ module.exports = {
   // transpileDependencies: true, // 默认情况下 babel-loader 忽略 node_modules 中的所有文件,启用此选项需配置transpileDependencies
   transpileDependencies: [
     /@aws-sdk/,
+    '@aws/lambda-invoke-store',
     /@aws/,
     /@smithy/,
     /@huaweicloud/,
@@ -68,27 +70,12 @@ module.exports = {
         '@': resolve('src')
       }
     },
-    externals: {
-      'node:async_hooks': 'commonjs async_hooks',
-      'node:crypto': 'commonjs crypto',
-      'node:fs': 'commonjs fs',
-      'node:fs/promises': 'commonjs fs/promises',
-      'node:http': 'commonjs http',
-      'node:os': 'commonjs os',
-      'node:path': 'commonjs path',
-      'node:process': 'commonjs process',
-      'node:stream': 'commonjs stream',
-      'node:stream/web': 'commonjs stream',
-      'node:buffer': 'commonjs buffer',
-      'node:util': 'commonjs util',
-      'node:url': 'commonjs url',
-      'node:net': 'commonjs net',
-      'node:tls': 'commonjs tls',
-      'node:events': 'commonjs events',
-      'node:https': 'commonjs https',
-      'node:zlib': 'commonjs zlib',
-      'node:child_process': 'commonjs child_process'
-    }
+    plugins: [
+      // @smithy/@aws-sdk 会 import node:stream 等内置模块,浏览器用空模块替代
+      new webpack.NormalModuleReplacementPlugin(/^node:/, resource => {
+        resource.request = resolve('src/utils/node-empty-module.js')
+      })
+    ]
   },
   chainWebpack(config) {
     config.plugins.delete('preload') // TODO: need test