Browse Source

课程管理重粉导出

yh 3 weeks ago
parent
commit
d9c5909c40
2 changed files with 376 additions and 20 deletions
  1. 365 9
      src/views/course/userCourse/index.vue
  2. 11 11
      src/views/course/userCourseCategory/index.vue

+ 365 - 9
src/views/course/userCourse/index.vue

@@ -22,15 +22,72 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="课堂名称" prop="courseName">
-        <el-input
-          v-model="queryParams.courseName"
-          placeholder="请输入课堂名称"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
+<!--      <el-form-item label="课堂名称" prop="courseName">-->
+<!--        <el-input-->
+<!--          v-model="queryParams.courseName"-->
+<!--          placeholder="请输入课堂名称"-->
+<!--          clearable-->
+<!--          size="small"-->
+<!--          @keyup.enter.native="handleQuery"-->
+<!--        />-->
+<!--      </el-form-item>-->
+
+      <el-form-item label="课堂名称" prop="courseNames">
+        <div class="tag-input-container">
+          <!-- 标签显示区域 -->
+          <div class="tags-wrapper" @click="focusInput">
+            <!-- 已添加的订单号标签 -->
+            <el-tag
+              v-for="(code, index) in queryParams.courseNames"
+              :key="index"
+              closable
+              size="small"
+              @close="removeOrderCode(index)"
+              class="order-tag"
+              :class="{ 'tag-error': false }"
+            >
+              {{ code }}
+            </el-tag>
+
+            <!-- 输入框 -->
+            <el-input
+              ref="tagInput"
+              v-model="currentInput"
+              v-show="inputVisible || queryParams.courseNames.length === 0"
+              :placeholder="queryParams.courseNames.length === 0 ? '请输入课堂名称,按回车或逗号分隔' : '继续输入...'"
+              size="small"
+              class="tag-input"
+              @keydown.native="handleKeyDown"
+              @keyup.native="handleKeyUp"
+              @blur="handleInputConfirm"
+              @focus="inputVisible = true"
+              clearable
+            />
+
+            <!-- 添加按钮(当没有输入时显示) -->
+            <el-button
+              v-if="!inputVisible && queryParams.courseNames.length > 0"
+              class="button-new-tag"
+              size="small"
+              @click="showInput"
+              icon="el-icon-plus"
+              type="text"
+            >
+              添加课堂名称
+            </el-button>
+          </div>
+
+          <!-- 输入提示 -->
+          <div class="input-tips">
+            <span class="tip-text">
+              支持:回车、逗号、空格分隔 |
+              已添加 {{ queryParams.courseNames.length }} 个课堂名称
+              <span v-if="maxOrderCodes > 0"> (最多{{ maxOrderCodes }}个)</span>
+            </span>
+          </div>
+        </div>
       </el-form-item>
+
       <el-form-item label="关联的公司" prop="companyIds">
         <el-select v-model="queryParams.companyIdsList" multiple placeholder="请选择公司" filterable clearable style="width: 90%;">
           <el-option
@@ -117,6 +174,18 @@
         >导出
         </el-button>
       </el-col>
+
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleFansExport"
+          v-hasPermi="['course:userCourseCategory:fansExport']"
+        >重粉导出</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -489,10 +558,11 @@ 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, exportFans} from "@/api/course/userCourseCategory";
 import {allList} from "@/api/company/company";
 import VideoUpload from '@/components/VideoUpload/index.vue'
 import { getConfigByKey } from '@/api/system/config'
+import {getTask} from "@/api/common";
 export default {
   name: "UserCourse",
   components: {
@@ -598,6 +668,16 @@ export default {
         price: null,
         isPrivate: 1,
         companyIdsList:[],
+        courseNames: [],
+      },
+      // 当前输入值
+      currentInput: '',
+      // 输入框是否可见
+      inputVisible: false,
+      // 最大订单号数量限制
+      maxOrderCodes: {
+        type: Number,
+        default: 50
       },
       // 表单参数
       form: {},
@@ -829,6 +909,13 @@ export default {
     },
     /** 查询课程列表 */
     getList() {
+      // 处理订单号数组
+      if (this.queryParams.courseNames && this.queryParams.courseNames.length > 0) {
+        this.queryParams.courseNameList = this.queryParams.courseNames.join(',');
+      } else {
+        this.queryParams.courseNameList = null;
+      }
+
       this.loading = true;
       listUserCourse(this.queryParams).then(response => {
         this.userCourseList = response.rows;
@@ -885,6 +972,88 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    // 聚焦输入框
+    focusInput() {
+      if (!this.inputVisible) {
+        this.showInput()
+      }
+    },
+    // 删除课堂名称
+    removeOrderCode(index) {
+      this.queryParams.courseNames.splice(index, 1)
+    },
+    // 处理键盘按下事件
+    handleKeyDown(event) {
+      const { key, target } = event
+
+      // 处理退格键删除标签
+      if (key === 'Backspace' && !target.value && this.queryParams.courseNames.length > 0) {
+        event.preventDefault()
+        this.removeOrderCode(this.queryParams.courseNames.length - 1)
+      }
+
+      // 处理分隔符
+      if ([',', ',', ' ', 'Enter'].includes(key)) {
+        event.preventDefault()
+        this.handleInputConfirm()
+      }
+    },
+
+    // 处理键盘抬起事件(实时分割输入)
+    handleKeyUp(event) {
+      const value = event.target.value
+
+      // 检查是否包含分隔符
+      if (/[,,\s]/.test(value)) {
+        this.handleInputConfirm()
+      }
+    },
+
+    // 确认输入
+    handleInputConfirm() {
+      const inputValue = this.currentInput.trim()
+
+      if (inputValue) {
+        // 分割多个订单号
+        const codes = inputValue.split(/[,,\s]+/).filter(code => code.trim())
+
+        codes.forEach(code => {
+          this.addOrderCode(code.trim())
+        })
+      }
+
+      this.currentInput = ''
+    },
+
+    // 显示输入框
+    showInput() {
+      this.inputVisible = true
+      this.$nextTick(() => {
+        this.$refs.tagInput.focus()
+      })
+    },
+
+    // 添加订单号
+    addOrderCode(code) {
+      if (!code) return
+
+      // 检查数量限制
+      if (this.maxOrderCodes > 0 && this.queryParams.courseNames.length >= this.maxOrderCodes) {
+        this.$message.warning(`最多只能添加 ${this.maxOrderCodes} 个课堂名称`)
+        return
+      }
+
+      // 检查重复
+      if (this.queryParams.courseNames.includes(code)) {
+        this.$message.warning(`课堂名称 "${code}" 已存在`)
+        return
+      }
+
+      // 添加到列表
+      this.queryParams.courseNames.push(code)
+
+    },
+
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
@@ -1054,6 +1223,37 @@ export default {
       }).catch(() => {
       });
     },
+
+    handleFansExport() {
+      if (!Array.isArray(this.queryParams.courseNames) || this.queryParams.courseNames.length === 0) {
+        this.$message.warning('请至少输入一条课堂名称');
+        return;
+      }
+
+      const params = { courseNames: this.queryParams.courseNames };
+
+      this.$confirm('是否确认导出重粉?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        exportFans(params).then(res => {
+          this.$message.success(res.msg);
+          const taskId = res.data;
+
+          this.time = setInterval(() => {
+            getTask(taskId).then(res => {
+              if (res.data.status === 1) {
+                clearInterval(this.time);
+                this.download(res.data.fileUrl);
+              }
+            });
+          }, 10000);
+        });
+      });
+    },
+
+
     putOn() {
       const courseIds = this.ids;
       if (courseIds == null || courseIds == "") {
@@ -1240,3 +1440,159 @@ export default {
   }
 };
 </script>
+
+<style scoped>
+.tag-input-order-search {
+  padding: 20px;
+  background: #fff;
+  border-radius: 4px;
+}
+
+.tag-input-container {
+  min-width: 445px;
+}
+
+.tags-wrapper {
+  min-height: 32px;
+  padding: 4px 8px;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  cursor: text;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 4px;
+  transition: border-color 0.2s;
+}
+
+.tags-wrapper:hover {
+  border-color: #c0c4cc;
+}
+
+.tags-wrapper:focus-within {
+  border-color: #409eff;
+  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+}
+
+.order-tag {
+  margin: 2px;
+  flex-shrink: 0;
+}
+
+.tag-error {
+  background-color: #fef0f0;
+  border-color: #fbc4c4;
+  color: #f56c6c;
+}
+
+.tag-input {
+  border: none;
+  outline: none;
+  flex: 1;
+  min-width: 120px;
+}
+
+.tag-input >>> .el-input__inner {
+  border: none;
+  padding: 0;
+  height: 24px;
+  line-height: 24px;
+}
+
+.button-new-tag {
+  height: 24px;
+  line-height: 22px;
+  padding: 0 8px;
+  margin: 2px;
+}
+
+.input-tips {
+  margin-top: 4px;
+  font-size: 12px;
+  color: #909399;
+}
+
+/* 新增排序相关样式 */
+.sort-info {
+  margin-top: 10px;
+  padding: 8px 0;
+}
+
+/* 表格布局优化 */
+.el-table {
+  min-width: 100%;
+  table-layout: fixed;
+}
+
+.el-table .el-table__body-wrapper {
+  overflow-x: auto;
+}
+
+.tip-text {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.quick-actions {
+  margin-top: 12px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 8px 0;
+  border-top: 1px solid #ebeef5;
+}
+
+.stats-info {
+  font-size: 12px;
+  color: #909399;
+  display: flex;
+  align-items: center;
+  gap: 4px;
+}
+
+.invalid-codes-list {
+  margin: 16px 0;
+  max-height: 200px;
+  overflow-y: auto;
+}
+
+.invalid-tag {
+  margin: 4px;
+}
+
+.debug-preview {
+  margin-top: 20px;
+}
+
+.debug-content {
+  font-size: 12px;
+}
+
+.debug-content code {
+  display: block;
+  background: #f5f5f5;
+  padding: 8px;
+  border-radius: 4px;
+  margin: 4px 0 12px 0;
+  white-space: pre-wrap;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .tag-input-container {
+    min-width: auto;
+    width: 100%;
+  }
+
+  .tags-wrapper {
+    min-height: 40px;
+  }
+
+  .quick-actions {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 8px;
+  }
+}
+</style>

+ 11 - 11
src/views/course/userCourseCategory/index.vue

@@ -81,17 +81,17 @@
         >导入</el-button>
       </el-col>
 
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          :loading="exportLoading"
-          @click="handleFansExport"
-          v-hasPermi="['course:userCourseCategory:fansExport']"
-        >重粉导出</el-button>
-      </el-col>
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="warning"-->
+<!--          plain-->
+<!--          icon="el-icon-download"-->
+<!--          size="mini"-->
+<!--          :loading="exportLoading"-->
+<!--          @click="handleFansExport"-->
+<!--          v-hasPermi="['course:userCourseCategory:fansExport']"-->
+<!--        >重粉导出</el-button>-->
+<!--      </el-col>-->
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>