|
@@ -3,46 +3,84 @@
|
|
|
<el-container>
|
|
|
<!-- 左侧区域 -->
|
|
|
<el-aside width="360px" class="left-aside">
|
|
|
- <!-- 左侧筛选条件 -->
|
|
|
- <el-form :model="leftQueryParams" ref="leftQueryForm" :inline="true" v-show="showSearch" label-width="84px">
|
|
|
- <el-form-item label="训练营名称" prop="trainingCampName">
|
|
|
+ <!-- 顶部区域 -->
|
|
|
+ <div class="left-header">
|
|
|
+ <div class="left-header-top">
|
|
|
+ <el-button type="primary" class="search-btn" @click="handleLeftQuery">搜索</el-button>
|
|
|
+ <div class="btn-group">
|
|
|
+ <el-button type="text" @click="showWarning">展示预警训练营</el-button>
|
|
|
+ <el-button type="primary" icon="el-icon-plus" @click="handleAddTrainingCamp">新建训练营</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="search-input-wrapper">
|
|
|
<el-input
|
|
|
v-model="leftQueryParams.trainingCampName"
|
|
|
placeholder="请输入训练营名称"
|
|
|
+ prefix-icon="el-icon-search"
|
|
|
clearable
|
|
|
size="small"
|
|
|
@keyup.enter.native="handleLeftQuery"
|
|
|
/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item>
|
|
|
- <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleLeftQuery">搜索</el-button>
|
|
|
- <el-button icon="el-icon-refresh" size="mini" @click="resetLeftQuery">重置</el-button>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
+ </div>
|
|
|
+ <div class="sort-wrapper">
|
|
|
+ <span class="sort-label">排序方式</span>
|
|
|
+ <el-select v-model="leftQueryParams.scs"
|
|
|
+ placeholder="按序号倒序"
|
|
|
+ size="small"
|
|
|
+ class="sort-select"
|
|
|
+ @change="handleSortChange"
|
|
|
+ >
|
|
|
+ <el-option label="按序号倒序" value="order_number(desc),training_camp_id(desc)" />
|
|
|
+ <el-option label="按序号顺序" value="order_number(asc),training_camp_id(desc)" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <!-- 左侧列表 -->
|
|
|
- <el-table v-loading="leftLoading" :data="leftList" @selection-change="handleLeftSelectionChange">
|
|
|
- <el-table-column type="selection" width="55" align="center" />
|
|
|
- <el-table-column label="训练营名称" align="center" prop="trainingCampName" />
|
|
|
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-button
|
|
|
- size="mini"
|
|
|
- type="text"
|
|
|
- icon="el-icon-view"
|
|
|
- @click="handleView(scope.row)"
|
|
|
- >查看</el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
+ <!-- 训练营列表 -->
|
|
|
+ <div class="camp-list" ref="campList" @scroll="handleScroll">
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in campList"
|
|
|
+ :key="index"
|
|
|
+ class="camp-item"
|
|
|
+ :class="{ 'active': activeCampIndex === index }"
|
|
|
+ @click="selectCamp(index)"
|
|
|
+ >
|
|
|
+ <div class="camp-content">
|
|
|
+ <div class="camp-title">
|
|
|
+ <i class="el-icon-s-flag camp-icon"></i>
|
|
|
+ {{ item.trainingCampName }}
|
|
|
+ </div>
|
|
|
+ <div class="camp-info">
|
|
|
+ <span>序号:{{ item.orderNumber }}</span>
|
|
|
+ <span>最新营期开课:{{ item.recentDate || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="camp-stats">
|
|
|
+ <span class="stat-item">
|
|
|
+ <i class="el-icon-s-data"></i>
|
|
|
+ 营期数:{{ item.periodCount || 0 }}
|
|
|
+ </span>
|
|
|
+ <span class="stat-item">
|
|
|
+ <i class="el-icon-user"></i>
|
|
|
+ 会员总数:{{ item.vipCount || 0 }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="camp-actions">
|
|
|
+ <el-button type="text" class="action-btn delete-btn" @click.stop="handleDeleteCamp(item)">删除</el-button>
|
|
|
+ <el-button type="text" class="action-btn copy-btn" @click.stop="handleCopyCamp(item)">复制</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 底部加载更多提示 -->
|
|
|
+ <div v-if="loadingMore" class="loading-more">
|
|
|
+ <i class="el-icon-loading"></i>
|
|
|
+ <span>加载中...</span>
|
|
|
+ </div>
|
|
|
|
|
|
- <pagination
|
|
|
- v-show="leftTotal>0"
|
|
|
- :total="leftTotal"
|
|
|
- :page.sync="leftQueryParams.pageNum"
|
|
|
- :limit.sync="leftQueryParams.pageSize"
|
|
|
- @pagination="getLeftList"
|
|
|
- />
|
|
|
+ <!-- 所有数据加载完毕提示 -->
|
|
|
+ <div v-if="campList.length > 0 && !leftQueryParams.hasNextPage && !loadingMore" class="no-more-data">
|
|
|
+ <span>—— 已加载全部训练营 ——</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</el-aside>
|
|
|
|
|
|
<!-- 右侧区域 -->
|
|
@@ -241,12 +279,26 @@
|
|
|
<el-button @click="cancel">取 消</el-button>
|
|
|
</div>
|
|
|
</el-dialog>
|
|
|
+
|
|
|
+ <!-- 添加训练营对话框 -->
|
|
|
+ <el-dialog :title="'新建训练营'" :visible.sync="campDialogVisible" width="500px" append-to-body>
|
|
|
+ <el-form ref="campForm" :model="campForm" :rules="campRules" label-width="100px">
|
|
|
+ <el-form-item label="训练营名称" prop="trainingCampName">
|
|
|
+ <el-input v-model="campForm.trainingCampName" placeholder="请输入训练营名称" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="submitCampForm">确 定</el-button>
|
|
|
+ <el-button @click="cancelCampForm">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import { listPeriod, getPeriod, delPeriod, addPeriod, updatePeriod, exportPeriod, pagePeriod } from "@/api/course/userCoursePeriod";
|
|
|
import { getCompanyList } from "@/api/company/company";
|
|
|
+import { listCamp, addCamp, delCamp, copyCamp } from "@/api/course/userCourseCamp";
|
|
|
|
|
|
export default {
|
|
|
name: "Period",
|
|
@@ -289,6 +341,8 @@ export default {
|
|
|
leftQueryParams: {
|
|
|
pageNum: 1,
|
|
|
pageSize: 10,
|
|
|
+ hasNextPage: false,
|
|
|
+ scs: 'order_number(desc),training_camp_id(desc)',
|
|
|
trainingCampName: null
|
|
|
},
|
|
|
// 表单参数
|
|
@@ -297,7 +351,28 @@ export default {
|
|
|
rules: {
|
|
|
},
|
|
|
// 公司选项
|
|
|
- companyOptions: []
|
|
|
+ companyOptions: [],
|
|
|
+ // 训练营列表
|
|
|
+ campList: [],
|
|
|
+ // 激活的训练营索引
|
|
|
+ activeCampIndex: null,
|
|
|
+ // 训练营对话框是否显示
|
|
|
+ campDialogVisible: false,
|
|
|
+ // 训练营表单
|
|
|
+ campForm: {
|
|
|
+ trainingCampName: ''
|
|
|
+ },
|
|
|
+ // 训练营表单校验
|
|
|
+ campRules: {
|
|
|
+ trainingCampName: [
|
|
|
+ { required: true, message: '训练营名称不能为空', trigger: 'blur' },
|
|
|
+ { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ // 滚动节流标志
|
|
|
+ scrollThrottle: false,
|
|
|
+ // 加载更多状态
|
|
|
+ loadingMore: false,
|
|
|
};
|
|
|
},
|
|
|
created() {
|
|
@@ -319,8 +394,37 @@ export default {
|
|
|
/** 查询左侧列表 */
|
|
|
getLeftList() {
|
|
|
this.leftLoading = true;
|
|
|
- // TODO: 调用左侧列表接口
|
|
|
- this.leftLoading = false;
|
|
|
+ // 重置页码和加载更多状态
|
|
|
+ this.leftQueryParams.pageNum = 1;
|
|
|
+ this.loadingMore = false;
|
|
|
+
|
|
|
+ // 训练营数据
|
|
|
+ listCamp(this.leftQueryParams).then(response => {
|
|
|
+ if (response && response.code === 200) {
|
|
|
+ this.campList = response.data.list || [];
|
|
|
+ this.leftQueryParams.hasNextPage = response.data.hasNextPage;
|
|
|
+ this.activeCampIndex = this.campList.length > 0 ? 0 : null;
|
|
|
+
|
|
|
+ // 如果当前显示的列表高度不足以触发滚动,但还有更多数据,自动加载下一页
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const scrollEl = this.$refs.campList;
|
|
|
+ if (scrollEl && this.leftQueryParams.hasNextPage && scrollEl.scrollHeight <= scrollEl.clientHeight) {
|
|
|
+ this.loadMoreCamps();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.$message.error(response.msg || '获取训练营列表失败');
|
|
|
+ this.campList = [];
|
|
|
+ this.leftQueryParams.hasNextPage = false;
|
|
|
+ }
|
|
|
+ this.leftLoading = false;
|
|
|
+ }).catch(error => {
|
|
|
+ console.error('获取训练营列表失败:', error);
|
|
|
+ this.$message.error('获取训练营列表失败');
|
|
|
+ this.campList = [];
|
|
|
+ this.leftQueryParams.hasNextPage = false;
|
|
|
+ this.leftLoading = false;
|
|
|
+ });
|
|
|
},
|
|
|
/** 搜索按钮操作 */
|
|
|
handleQuery() {
|
|
@@ -329,7 +433,9 @@ export default {
|
|
|
},
|
|
|
/** 左侧搜索按钮操作 */
|
|
|
handleLeftQuery() {
|
|
|
+ // 重置页码和列表
|
|
|
this.leftQueryParams.pageNum = 1;
|
|
|
+ this.campList = [];
|
|
|
this.getLeftList();
|
|
|
},
|
|
|
/** 重置按钮操作 */
|
|
@@ -338,25 +444,12 @@ export default {
|
|
|
this.queryParams.companyIdList = [];
|
|
|
this.handleQuery();
|
|
|
},
|
|
|
- /** 左侧重置按钮操作 */
|
|
|
- resetLeftQuery() {
|
|
|
- this.resetForm("leftQueryForm");
|
|
|
- this.handleLeftQuery();
|
|
|
- },
|
|
|
// 多选框选中数据
|
|
|
handleSelectionChange(selection) {
|
|
|
this.ids = selection.map(item => item.periodId)
|
|
|
this.single = selection.length!==1
|
|
|
this.multiple = !selection.length
|
|
|
},
|
|
|
- // 左侧多选框选中数据
|
|
|
- handleLeftSelectionChange(selection) {
|
|
|
- // TODO: 处理左侧选中数据
|
|
|
- },
|
|
|
- /** 查看按钮操作 */
|
|
|
- handleView(row) {
|
|
|
- // TODO: 处理查看操作
|
|
|
- },
|
|
|
/** 新增按钮操作 */
|
|
|
handleAdd() {
|
|
|
this.reset();
|
|
@@ -456,6 +549,196 @@ export default {
|
|
|
periodEndTime: null
|
|
|
};
|
|
|
this.resetForm("form");
|
|
|
+ },
|
|
|
+ // 处理训练营列表的逻辑
|
|
|
+ handleDeleteCamp(item) {
|
|
|
+ this.$confirm(`确定要删除训练营"${item.trainingCampName}"吗?`, '提示', {
|
|
|
+ confirmButtonText: '删除',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ // 调用删除训练营API
|
|
|
+ const trainingCampId = item.trainingCampId;
|
|
|
+ this.leftLoading = true;
|
|
|
+
|
|
|
+ delCamp(trainingCampId).then(response => {
|
|
|
+ if (response.code === 200) {
|
|
|
+ this.$message.success('删除成功');
|
|
|
+ // 从列表中移除
|
|
|
+ const index = this.campList.findIndex(camp => camp.trainingCampId === trainingCampId);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.campList.splice(index, 1);
|
|
|
+ }
|
|
|
+ // 如果删除的是当前选中的训练营,则重置选中状态
|
|
|
+ if (this.activeCampIndex === index) {
|
|
|
+ this.activeCampIndex = this.campList.length > 0 ? 0 : null;
|
|
|
+ if (this.activeCampIndex !== null) {
|
|
|
+ // 更新右侧列表
|
|
|
+ this.selectCamp(this.activeCampIndex);
|
|
|
+ } else {
|
|
|
+ // 没有训练营了,清空右侧列表
|
|
|
+ this.periodList = [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$message.error(response.msg || '删除失败');
|
|
|
+ }
|
|
|
+ this.leftLoading = false;
|
|
|
+ }).catch(error => {
|
|
|
+ this.$message.error('删除失败: ' + error.message);
|
|
|
+ this.leftLoading = false;
|
|
|
+ });
|
|
|
+ }).catch(() => {
|
|
|
+ this.$message.info('已取消删除');
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /** 复制训练营 */
|
|
|
+ handleCopyCamp(item) {
|
|
|
+ // 调用添加训练营API
|
|
|
+ copyCamp(item.trainingCampId).then(response => {
|
|
|
+ if (response.code === 200) {
|
|
|
+ this.$message.success('复制成功');
|
|
|
+ // 重新加载训练营列表
|
|
|
+ this.getLeftList();
|
|
|
+ } else {
|
|
|
+ this.$message.error(response.msg || '复制训练营失败');
|
|
|
+ }
|
|
|
+ }).catch(error => {
|
|
|
+ this.$message.error('复制训练营失败: ' + error.message);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /** 展示预警训练营 */
|
|
|
+ showWarning() {
|
|
|
+ console.log('展示预警训练营')
|
|
|
+ },
|
|
|
+ /** 新建训练营按钮操作 */
|
|
|
+ handleAddTrainingCamp() {
|
|
|
+ this.resetCampForm();
|
|
|
+ this.campDialogVisible = true;
|
|
|
+ },
|
|
|
+ /** 重置训练营表单 */
|
|
|
+ resetCampForm() {
|
|
|
+ this.campForm = {
|
|
|
+ trainingCampName: ''
|
|
|
+ };
|
|
|
+ // 如果表单已经创建,则重置校验结果
|
|
|
+ if (this.$refs.campForm) {
|
|
|
+ this.$refs.campForm.resetFields();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /** 取消训练营表单 */
|
|
|
+ cancelCampForm() {
|
|
|
+ this.campDialogVisible = false;
|
|
|
+ this.resetCampForm();
|
|
|
+ },
|
|
|
+ /** 提交训练营表单 */
|
|
|
+ submitCampForm() {
|
|
|
+ this.$refs.campForm.validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ // 显示加载中
|
|
|
+ this.leftLoading = true;
|
|
|
+ // 提交数据
|
|
|
+ addCamp(this.campForm).then(response => {
|
|
|
+ if (response.code === 200) {
|
|
|
+ this.$message.success('新建训练营成功');
|
|
|
+ this.campDialogVisible = false;
|
|
|
+ // 重新加载训练营列表
|
|
|
+ this.getLeftList();
|
|
|
+ } else {
|
|
|
+ this.$message.error(response.msg || '新建训练营失败');
|
|
|
+ this.leftLoading = false;
|
|
|
+ }
|
|
|
+ }).catch(error => {
|
|
|
+ this.$message.error('新建训练营失败: ' + error.message);
|
|
|
+ this.leftLoading = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /** 排序方式改变 */
|
|
|
+ handleSortChange(value) {
|
|
|
+ this.leftQueryParams.scs = value;
|
|
|
+ // 重置页码和列表
|
|
|
+ this.leftQueryParams.pageNum = 1;
|
|
|
+ this.campList = [];
|
|
|
+ this.getLeftList();
|
|
|
+ },
|
|
|
+ /** 选中训练营 */
|
|
|
+ selectCamp(index) {
|
|
|
+ this.activeCampIndex = index;
|
|
|
+ // TODO:加载对应的训练营营期数据
|
|
|
+ const selectedCamp = this.campList[index];
|
|
|
+ // 设置查询参数
|
|
|
+ // this.queryParams = {
|
|
|
+ // ...this.queryParams,
|
|
|
+ // trainingCampId: selectedCamp.trainingCampId
|
|
|
+ // };
|
|
|
+ // this.getList();
|
|
|
+ },
|
|
|
+ /** 处理滚动事件,实现滚动到底部加载更多 */
|
|
|
+ handleScroll() {
|
|
|
+ // 如果正在节流中或者正在加载中,则不处理
|
|
|
+ if (this.scrollThrottle || this.loadingMore) return;
|
|
|
+
|
|
|
+ // 设置节流,200ms内不再处理滚动事件
|
|
|
+ this.scrollThrottle = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.scrollThrottle = false;
|
|
|
+ }, 200);
|
|
|
+
|
|
|
+ const scrollEl = this.$refs.campList;
|
|
|
+ if (!scrollEl) return;
|
|
|
+
|
|
|
+ // 判断是否滚动到底部:滚动高度 + 可视高度 >= 总高度 - 30(添加30px的容差,提前触发加载)
|
|
|
+ const isBottom = scrollEl.scrollTop + scrollEl.clientHeight >= scrollEl.scrollHeight - 30;
|
|
|
+
|
|
|
+ // 如果滚动到底部,且有下一页数据,且当前不在加载中,则加载更多
|
|
|
+ if (isBottom && this.leftQueryParams.hasNextPage && !this.leftLoading && !this.loadingMore) {
|
|
|
+ this.loadMoreCamps();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /** 加载更多训练营数据 */
|
|
|
+ loadMoreCamps() {
|
|
|
+ // 已在加载中,防止重复加载
|
|
|
+ if (this.leftLoading || this.loadingMore) return;
|
|
|
+
|
|
|
+ // 设置加载状态
|
|
|
+ this.loadingMore = true;
|
|
|
+
|
|
|
+ // 页码加1
|
|
|
+ this.leftQueryParams.pageNum += 1;
|
|
|
+
|
|
|
+ // 加载下一页数据
|
|
|
+ listCamp(this.leftQueryParams).then(response => {
|
|
|
+ if (response && response.code === 200) {
|
|
|
+ // 将新数据追加到列表中
|
|
|
+ const newList = response.data.list || [];
|
|
|
+ if (newList.length > 0) {
|
|
|
+ this.campList = [...this.campList, ...newList];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新是否有下一页的标志
|
|
|
+ this.leftQueryParams.hasNextPage = response.data.hasNextPage;
|
|
|
+
|
|
|
+ // 如果当前显示的列表高度不足以触发滚动,但还有更多数据,自动加载下一页
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const scrollEl = this.$refs.campList;
|
|
|
+ if (scrollEl && this.leftQueryParams.hasNextPage && scrollEl.scrollHeight <= scrollEl.clientHeight) {
|
|
|
+ // 延迟一点再加载下一页,避免过快加载
|
|
|
+ setTimeout(() => {
|
|
|
+ this.loadMoreCamps();
|
|
|
+ }, 300);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.$message.error(response.msg || '加载更多训练营失败');
|
|
|
+ }
|
|
|
+ this.loadingMore = false;
|
|
|
+ }).catch(error => {
|
|
|
+ console.error('加载更多训练营失败:', error);
|
|
|
+ this.$message.error('加载更多训练营失败');
|
|
|
+ this.loadingMore = false;
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
};
|
|
@@ -464,10 +747,256 @@ export default {
|
|
|
<style scoped>
|
|
|
.left-aside {
|
|
|
background-color: #fff;
|
|
|
- border-right: 1px solid #e6e6e6;
|
|
|
+ border-right: 1px solid #EBEEF5;
|
|
|
+ padding: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 800px;
|
|
|
+}
|
|
|
+
|
|
|
+.left-header {
|
|
|
padding: 10px;
|
|
|
+ border-bottom: 1px solid #EBEEF5;
|
|
|
+}
|
|
|
+
|
|
|
+.left-header-top {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.search-btn {
|
|
|
+ padding: 7px 15px;
|
|
|
+ background-color: #409EFF;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
}
|
|
|
+
|
|
|
+.btn-group {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.search-input-wrapper {
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.sort-wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.sort-label {
|
|
|
+ width: 70px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.sort-select {
|
|
|
+ margin-left: 10px;
|
|
|
+ width: 280px;
|
|
|
+}
|
|
|
+
|
|
|
+.color-wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.color-label {
|
|
|
+ width: 70px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+
|
|
|
+.color-hint {
|
|
|
+ margin-left: 10px;
|
|
|
+ color: #606266;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.color-help {
|
|
|
+ margin-left: 5px;
|
|
|
+ color: #909399;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.hint-text {
|
|
|
+ color: #606266;
|
|
|
+ font-size: 12px;
|
|
|
+ margin-top: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-list {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 3px;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-item {
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ padding: 15px;
|
|
|
+ background-color: #ffffff;
|
|
|
+ position: relative;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ border: 1px solid #eaedf2;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-item:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-item:hover {
|
|
|
+ background-color: #f5f9ff;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-item.active {
|
|
|
+ background-color: #eaf4ff;
|
|
|
+ border-left: 2px solid #75b8fc;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-content {
|
|
|
+ flex: 1;
|
|
|
+ padding-right: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-title {
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 16px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ color: #333;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-icon {
|
|
|
+ font-size: 16px;
|
|
|
+ margin-right: 6px;
|
|
|
+ color: #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-info {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #c4c1c1;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-stats {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #666;
|
|
|
+ background-color: #f5f9ff;
|
|
|
+ padding: 6px 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-item i {
|
|
|
+ margin-right: 4px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.camp-actions {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: flex-end;
|
|
|
+ gap: 8px;
|
|
|
+ border-left: 1px dashed #eaedf2;
|
|
|
+ padding-left: 12px;
|
|
|
+ min-width: 50px;
|
|
|
+}
|
|
|
+
|
|
|
+.action-btn {
|
|
|
+ padding: 2px 5px;
|
|
|
+ font-size: 12px;
|
|
|
+ border-radius: 4px;
|
|
|
+ transition: all 0.2s;
|
|
|
+}
|
|
|
+
|
|
|
+.action-btn:hover {
|
|
|
+ background-color: rgba(255, 255, 255, 0.8);
|
|
|
+}
|
|
|
+
|
|
|
+.delete-btn {
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
+
|
|
|
+.delete-btn:hover {
|
|
|
+ background-color: rgba(245, 108, 108, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.copy-btn {
|
|
|
+ color: #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.copy-btn:hover {
|
|
|
+ background-color: rgba(64, 158, 255, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.warning-icon {
|
|
|
+ color: #E6A23C;
|
|
|
+ font-size: 16px;
|
|
|
+ margin-left: 5px;
|
|
|
+}
|
|
|
+
|
|
|
.el-main {
|
|
|
padding: 10px;
|
|
|
}
|
|
|
+
|
|
|
+/* 添加训练营表单样式 */
|
|
|
+.dialog-footer {
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.el-input-number {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 加载更多样式 */
|
|
|
+.loading-more {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 12px 0;
|
|
|
+ color: #909399;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-more i {
|
|
|
+ margin-right: 5px;
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 无更多数据提示 */
|
|
|
+.no-more-data {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 12px 0;
|
|
|
+ color: #c0c4cc;
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+
|
|
|
+.no-more-data span {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
</style>
|