|
|
@@ -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>
|