Files
smartDriveEEUniApp/pages-subpackage/champion/components/training-tab.vue
2026-01-31 21:10:40 +08:00

1243 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<scroll-view
class="tab-content training-content"
scroll-y
@scrolltolower="onTrainingReachBottom">
<view class="service-status-toolbar">
<text class="toolbar-total">{{ trainingTotal }}</text>
<picker
class="toolbar-picker"
mode="selector"
:range="finishStatusOptions"
range-key="label"
:value="finishStatusIndex >= 0 ? finishStatusIndex : 0"
@change="onFinishStatusChange">
<view class="toolbar-picker-view">
<text :class="finishStatusIndex === -1 ? 'toolbar-picker-placeholder' : 'toolbar-picker-text'">
{{ finishStatusIndex === -1 ? '状态' : finishStatusOptions[finishStatusIndex].label }}
</text>
<uni-icons type="bottom" size="14" color="#999"></uni-icons>
</view>
</picker>
<input
class="toolbar-input"
v-model="trainingQuery.participantName"
placeholder="参与人姓名"
placeholder-style="color: #b0b0b0"
confirm-type="search"
@confirm="onTrainingSearch"
/>
<input
class="toolbar-input"
v-model="trainingQuery.participantPhone"
placeholder="参与人电话"
placeholder-style="color: #b0b0b0"
confirm-type="search"
@confirm="onTrainingSearch"
/>
<view class="toolbar-actions">
<view class="toolbar-btn toolbar-btn--refresh" @click="onTrainingRefresh">
<uni-icons type="refresh" size="18" color="#2A68FF"></uni-icons>
<text>刷新</text>
</view>
</view>
</view>
<view
class="service-card training-card-item"
v-for="(item, index) in trainingList"
:key="item.id || index"
:class="{ 'training-card-item--active': selectedTrainingItem && selectedTrainingItem.id === item.id }">
<view class="card-header">
<view class="staff-info">
<view class="staff-avatar">
<text class="avatar-text">{{ (item.title || '陪').charAt(0) }}</text>
</view>
<text class="staff-name">{{ item.title || '未命名陪练' }}</text>
</view>
<view class="training-card-action-btn" @click.stop="onTrainingActionBtnClick(item)">
<uni-icons type="more-filled" size="20" color="#999"></uni-icons>
</view>
</view>
<!-- 操作菜单 -->
<view
class="training-action-menu"
v-if="selectedTrainingItem && selectedTrainingItem.id === item.id && showTrainingActionMenu"
@click.stop>
<view class="training-action-menu-item" @click="startTraining(item)">
<text>开始</text>
</view>
</view>
<view class="customer-info">
<text class="customer-name" v-if="item.scenario">陪练场景: {{ item.scenario }}</text>
</view>
<view class="customer-tags">
<view class="tag-item tag-blue" v-if="item.participantName">
<text>参与人: {{ item.participantName }}</text>
</view>
<view class="tag-item tag-orange" v-if="item.participantPhone">
<text>电话: {{ item.participantPhone }}</text>
</view>
<view class="tag-item tag-status" v-if="item.finishStatus">
<text>状态: {{ getFinishStatusLabel(item.finishStatus) }}</text>
</view>
</view>
<view class="service-duration" v-if="item.endTime">
<text>结束时间: {{ formatDateTime(item.endTime) }}</text>
</view>
</view>
<view class="service-status-empty" v-if="!trainingLoading && !trainingList.length">
<text>暂无陪练记录</text>
</view>
<view class="service-status-loading-more" v-if="trainingLoading && trainingList.length">
<text>正在加载更多...</text>
</view>
<!-- 遮罩层点击关闭菜单 -->
<view
class="training-action-menu-mask"
v-if="showTrainingActionMenu"
@click="closeTrainingActionMenu">
</view>
</scroll-view>
<!-- 陪练中列表弹出框 -->
<view class="material-popup-mask" v-if="showTrainingItemListPopup" @click="closeTrainingItemListPopup">
</view>
<view class="material-popup training-item-list-popup" v-if="showTrainingItemListPopup" @click.stop>
<view class="popup-header">
<text class="popup-title">陪练中</text>
<view class="popup-close" @click="closeTrainingItemListPopup">
<uni-icons type="close" size="20" color="#999"></uni-icons>
</view>
</view>
<scroll-view class="popup-content" scroll-y @scrolltolower="onTrainingItemListReachBottom">
<view
class="service-card training-item-card"
v-for="(item, index) in trainingItemList"
:key="item.id || index">
<view class="card-header">
<view class="staff-info">
<view class="staff-avatar">
<text class="avatar-text">{{ (item.question || '题').charAt(0) }}</text>
</view>
<text class="staff-name">{{ item.question || '未命名题目' }}</text>
</view>
</view>
<view class="customer-info" v-if="item.answer">
<text class="customer-name">答案: {{ item.answer }}</text>
</view>
<!-- 回答输入框 -->
<view class="form-item">
<textarea
class="form-item__textarea"
v-model="trainingItemAnswers[item.id]"
placeholder="请输入回答"
placeholder-style="color: #9ca3af"
maxlength="2000"
/>
</view>
<!-- 操作按钮 -->
<view class="training-item-actions">
<view class="action-btn action-btn--continue" @click="handleContinue(item)">
<text>继续</text>
</view>
<view class="action-btn action-btn--end" @click="handleEnd(item)">
<text>结束</text>
</view>
</view>
</view>
<view class="service-status-empty" v-if="!trainingItemLoading && !trainingItemList.length">
<text>暂无记录</text>
</view>
<view class="service-status-loading-more" v-if="trainingItemLoading && trainingItemList.length">
<text>正在加载更多...</text>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import { getApiUrl } from "@/common/config.js";
// 获取租户ID
function getTenantId() {
try {
return uni.getStorageSync('backend-tenant-id') || '';
} catch (e) {
console.error('获取 tenantId 失败:', e);
return '';
}
}
export default {
name: 'TrainingTab',
data() {
return {
// 陪练列表相关数据
trainingList: [],
trainingLoading: false,
trainingTotal: 0,
trainingPage: {
current: 1,
size: 10
},
trainingQuery: {
participantName: '',
participantPhone: '',
finishStatus: ''
},
// 状态选项
finishStatusOptions: [
{ value: 'init', label: '初始状态' },
{ value: 'finished', label: '完成状态' }
],
finishStatusIndex: -1, // -1表示未选择不发送finishStatus参数
// 陪练操作菜单
selectedTrainingItem: null,
showTrainingActionMenu: false,
// 陪练中列表弹出框
showTrainingItemListPopup: false,
trainingItemList: [],
trainingItemLoading: false,
trainingItemTotal: 0,
trainingItemPage: {
current: 1,
size: 10
},
currentTrainingParentId: '',
// 存储每个陪练项的答案输入
trainingItemAnswers: {}
}
},
mounted() {
this.fetchTrainingList();
},
methods: {
// 状态选择改变事件
onFinishStatusChange(e) {
const index = parseInt(e.detail.value);
this.finishStatusIndex = index;
if (index >= 0 && index < this.finishStatusOptions.length) {
this.trainingQuery.finishStatus = this.finishStatusOptions[index].value;
} else {
this.trainingQuery.finishStatus = '';
this.finishStatusIndex = 0;
}
this.onTrainingSearch();
},
// 获取状态标签
getFinishStatusLabel(status) {
if (status === 'init') {
return '初始状态';
} else if (status === 'finished') {
return '完成状态';
}
return status || '';
},
// 陪练列表相关方法
onTrainingSearch() {
this.trainingPage.current = 1;
this.fetchTrainingList({ force: true });
},
onTrainingRefresh() {
this.trainingPage.current = 1;
this.fetchTrainingList({ force: true });
},
onTrainingReachBottom() {
// 已在加载中或全部加载完成则不再触发
if (this.trainingLoading) return;
if (this.trainingList.length >= this.trainingTotal) return;
this.trainingPage.current += 1;
this.fetchTrainingList();
},
async fetchTrainingList({ force = false } = {}) {
if (this.trainingLoading && !force) {
return;
}
this.trainingLoading = true;
try {
// 构建查询参数
const queryParams = {
current: this.trainingPage.current,
size: this.trainingPage.size
};
const trimmedParticipantName = this.trainingQuery?.participantName?.trim();
const trimmedParticipantPhone = this.trainingQuery?.participantPhone?.trim();
const finishStatus = this.trainingQuery?.finishStatus;
if (trimmedParticipantName) {
queryParams.participantName = trimmedParticipantName;
}
if (trimmedParticipantPhone) {
queryParams.participantPhone = trimmedParticipantPhone;
}
if (finishStatus) {
queryParams.finishStatus = finishStatus;
}
// 将参数转换为 URL 查询字符串
const queryString = Object.keys(queryParams)
.map(key => `${key}=${encodeURIComponent(queryParams[key])}`)
.join('&');
const url = `${getApiUrl('/api/trainingMain/list')}?${queryString}`;
// 获取租户ID
const tenantId = getTenantId();
const headers = {};
if (tenantId) {
headers['X-Tenant-Id'] = tenantId;
// 同时添加到查询参数中
queryParams.tenantId = tenantId;
}
// 重新构建查询字符串包含tenantId
const finalQueryString = Object.keys(queryParams)
.map(key => `${key}=${encodeURIComponent(queryParams[key])}`)
.join('&');
const finalUrl = `${getApiUrl('/api/trainingMain/list')}?${finalQueryString}`;
const res = await uni.request({
url: finalUrl,
method: 'POST',
header: headers,
timeout: 10000
});
if (res.statusCode === 200 && res.data && res.data.success) {
const records = Array.isArray(res.data.data) ? res.data.data : [];
// 第一页或强制刷新时重置列表,否则追加
if (this.trainingPage.current === 1 || force) {
this.trainingList = records;
} else {
this.trainingList = this.trainingList.concat(records);
}
this.trainingTotal = Number(res.data.total) || 0;
} else {
this.trainingList = [];
this.trainingTotal = 0;
uni.showToast({
title: res.data?.message || '获取陪练列表失败',
icon: 'none'
});
}
} catch (error) {
console.error('获取陪练列表失败:', error);
uni.showToast({
title: '获取陪练列表失败,请稍后重试',
icon: 'none'
});
} finally {
this.trainingLoading = false;
}
},
// 陪练操作菜单相关方法
onTrainingActionBtnClick(item) {
// 如果已经选中当前项,则关闭菜单
if (this.selectedTrainingItem && this.selectedTrainingItem.id === item.id && this.showTrainingActionMenu) {
this.closeTrainingActionMenu();
return;
}
// 显示菜单
this.selectedTrainingItem = item;
this.showTrainingActionMenu = true;
},
closeTrainingActionMenu() {
this.showTrainingActionMenu = false;
this.selectedTrainingItem = null;
},
async startTraining(item) {
this.closeTrainingActionMenu();
// 打开详情列表弹窗
this.currentTrainingParentId = item.id || '';
this.trainingItemList = [];
this.showTrainingItemListPopup = true;
// 加载详情列表调用listAll接口
await this.fetchTrainingItemListAll(item.id || '');
},
closeTrainingItemListPopup() {
this.showTrainingItemListPopup = false;
this.currentTrainingParentId = '';
this.trainingItemPage.current = 1;
this.trainingItemList = [];
// 清理答案输入
this.trainingItemAnswers = {};
},
onTrainingItemListReachBottom() {
// 已在加载中或全部加载完成则不再触发
if (this.trainingItemLoading) return;
if (this.trainingItemList.length >= this.trainingItemTotal) return;
this.trainingItemPage.current += 1;
this.fetchTrainingItemList();
},
async fetchTrainingItemListAll(parentId) {
if (!parentId) {
uni.showToast({
title: '缺少父ID参数',
icon: 'none'
});
return;
}
this.trainingItemLoading = true;
try {
// 获取租户ID
const tenantId = getTenantId();
// 构建查询参数
const queryParams = {
parentId: parentId
};
if (tenantId) {
queryParams.tenantId = tenantId;
}
// 将参数转换为 URL 查询字符串
const queryString = Object.keys(queryParams)
.filter(key => queryParams[key] !== null && queryParams[key] !== undefined && queryParams[key] !== '')
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(queryParams[key])}`)
.join('&');
const url = `${getApiUrl('/api/trainingItem/listAll')}?${queryString}`;
// 构建请求头
const headers = {
"Content-Type": "application/json"
};
if (tenantId) {
headers['X-Tenant-Id'] = tenantId;
}
const res = await uni.request({
url: url,
method: 'POST',
header: headers,
timeout: 30000
});
if (res.statusCode === 200 && res.data && res.data.success) {
const records = Array.isArray(res.data.data) ? res.data.data : [];
this.trainingItemList = records;
this.trainingItemTotal = Number(res.data.count) || records.length;
// 初始化答案输入
this.initTrainingItemAnswers(records);
} else {
this.trainingItemList = [];
this.trainingItemTotal = 0;
uni.showToast({
title: res.data?.message || '获取陪练中列表失败',
icon: 'none'
});
}
} catch (error) {
console.error('获取陪练中列表失败:', error);
uni.showToast({
title: '获取陪练中列表失败,请稍后重试',
icon: 'none'
});
} finally {
this.trainingItemLoading = false;
}
},
async fetchTrainingItemList({ force = false } = {}) {
if (this.trainingItemLoading && !force) {
return;
}
if (!this.currentTrainingParentId) {
return;
}
this.trainingItemLoading = true;
try {
// 构建查询参数
const queryParams = {
current: this.trainingItemPage.current,
size: this.trainingItemPage.size,
parentId: this.currentTrainingParentId
};
// 获取租户ID
const tenantId = getTenantId();
if (tenantId) {
queryParams.tenantId = tenantId;
}
// 将参数转换为 URL 查询字符串
const queryString = Object.keys(queryParams)
.filter(key => queryParams[key] !== null && queryParams[key] !== undefined && queryParams[key] !== '')
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(queryParams[key])}`)
.join('&');
const url = `${getApiUrl('/api/trainingItem/list')}?${queryString}`;
// 构建请求头
const headers = {};
if (tenantId) {
headers['X-Tenant-Id'] = tenantId;
}
const res = await uni.request({
url: url,
method: 'GET',
header: headers,
timeout: 30000
});
if (res.statusCode === 200 && res.data && res.data.success) {
const records = Array.isArray(res.data.data) ? res.data.data : [];
// 第一页或强制刷新时重置列表,否则追加
if (this.trainingItemPage.current === 1 || force) {
this.trainingItemList = records;
// 初始化答案输入
this.initTrainingItemAnswers(records);
} else {
this.trainingItemList = this.trainingItemList.concat(records);
// 追加时也初始化新记录的答案输入
this.initTrainingItemAnswers(records);
}
this.trainingItemTotal = Number(res.data.total) || 0;
} else {
this.trainingItemList = [];
this.trainingItemTotal = 0;
uni.showToast({
title: res.data?.message || '获取陪练中列表失败',
icon: 'none'
});
}
} catch (error) {
console.error('获取陪练中列表失败:', error);
uni.showToast({
title: '获取陪练中列表失败,请稍后重试',
icon: 'none'
});
} finally {
this.trainingItemLoading = false;
}
},
formatDateTime(value) {
if (!value) {
return '';
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return '';
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
// 初始化陪练项答案输入
initTrainingItemAnswers(records) {
if (!Array.isArray(records)) return;
records.forEach(item => {
if (item.id) {
// 如果已有答案,则使用已有答案,否则初始化为空
// 使用$set确保响应式
if (!this.trainingItemAnswers.hasOwnProperty(item.id)) {
this.$set(this.trainingItemAnswers, item.id, item.answer || '');
}
}
});
},
// 继续按钮处理
async handleContinue(item) {
if (!item || !item.id) {
uni.showToast({
title: '记录ID不能为空',
icon: 'none'
});
return;
}
if (!this.currentTrainingParentId) {
uni.showToast({
title: '缺少父ID参数',
icon: 'none'
});
return;
}
try {
uni.showLoading({
title: "提交中..."
});
// 获取租户ID
const tenantId = getTenantId();
// 获取当前输入的答案
const answer = this.trainingItemAnswers[item.id] || '';
// 构建请求数据
const payload = {
id: item.id,
parentId: this.currentTrainingParentId,
answer: answer
};
// 添加租户ID到payload
if (tenantId) {
payload.tenantId = tenantId;
}
const headers = {
"Content-Type": "application/json"
};
// 添加租户ID到header
if (tenantId) {
headers['X-Tenant-Id'] = tenantId;
}
const res = await uni.request({
url: getApiUrl('/api/trainingItem/traningNext'),
method: 'POST',
data: payload,
header: headers,
timeout: 15000
});
uni.hideLoading();
if (res.statusCode === 200 && res.data && (res.data.success || res.data.code === 200)) {
// 获取返回的数据
const newItems = Array.isArray(res.data.data) ? res.data.data : [];
if (newItems.length > 0) {
// 更新当前item的question、id和parentId
const newItem = newItems[0];
const index = this.trainingItemList.findIndex(i => i.id === item.id);
if (index !== -1) {
// 保存旧的id用于清理答案输入
const oldId = item.id;
// 更新question、id和parentId
if (newItem.question !== undefined) {
this.$set(this.trainingItemList[index], 'question', newItem.question);
}
if (newItem.id !== undefined) {
this.$set(this.trainingItemList[index], 'id', newItem.id);
}
if (newItem.parentId !== undefined) {
this.$set(this.trainingItemList[index], 'parentId', newItem.parentId);
}
// 如果id改变了需要更新答案输入的key
if (newItem.id && newItem.id !== oldId) {
// 获取旧答案
const oldAnswer = this.trainingItemAnswers[oldId] || '';
// 删除旧的答案输入
this.$delete(this.trainingItemAnswers, oldId);
// 设置新的答案输入(如果有旧答案则保留,否则为空)
this.$set(this.trainingItemAnswers, newItem.id, oldAnswer);
} else {
// id没变清空答案输入框新问题需要重新输入
this.$set(this.trainingItemAnswers, item.id, '');
}
}
}
uni.showToast({
title: res.data?.message || "提交成功",
icon: "success"
});
} else {
uni.showToast({
title: res.data?.message || "提交失败",
icon: "none"
});
}
} catch (error) {
uni.hideLoading();
console.error("提交失败:", error);
uni.showToast({
title: error?.message || "提交失败,请重试",
icon: "none"
});
}
},
// 结束按钮处理
async handleEnd(item) {
if (!this.currentTrainingParentId) {
uni.showToast({
title: '父ID不能为空',
icon: 'none'
});
return;
}
try {
uni.showLoading({
title: "提交中..."
});
// 获取租户ID
const tenantId = getTenantId();
// 构建请求数据只需要传递parentId
const payload = {
parentId: this.currentTrainingParentId
};
// 添加租户ID到payload
if (tenantId) {
payload.tenantId = tenantId;
}
const headers = {
"Content-Type": "application/json"
};
// 添加租户ID到header
if (tenantId) {
headers['X-Tenant-Id'] = tenantId;
}
const res = await uni.request({
url: getApiUrl('/api/trainingItem/traningFinish'),
method: 'POST',
data: payload,
header: headers,
timeout: 15000
});
uni.hideLoading();
if (res.statusCode === 200 && res.data && (res.data.success || res.data.code === 200)) {
uni.showToast({
title: res.data?.message || "提交成功",
icon: "success"
});
// 关闭弹窗
this.closeTrainingItemListPopup();
// 刷新陪练列表
this.trainingPage.current = 1;
this.fetchTrainingList({ force: true });
// 通知父组件切换到陪练tab确保在陪练tab页面
this.$emit('refresh-training-list');
} else {
uni.showToast({
title: res.data?.message || "提交失败",
icon: "none"
});
}
} catch (error) {
uni.hideLoading();
console.error("提交失败:", error);
uni.showToast({
title: error?.message || "提交失败,请重试",
icon: "none"
});
}
}
}
}
</script>
<style scoped>
/* 内容区域 - 使用绝对定位从tab页底部开始到底部导航栏结束 */
.tab-content {
position: absolute;
top: 160rpx; /* 导航栏(88rpx) + tab页(72rpx) = 160rpx */
left: 0;
right: 0;
bottom: 96rpx; /* 底部导航栏高度 */
background-color: #F5F5F5;
padding: 24rpx 16rpx 0 16rpx; /* 顶部24rpx间距底部0 */
box-sizing: border-box;
overflow-y: auto;
}
/* 陪练内容区域使用相同定位 */
.training-content {
position: absolute;
top: 160rpx; /* 导航栏(88rpx) + tab页(72rpx) = 160rpx */
left: 0;
right: 0;
bottom: 96rpx; /* 底部导航栏高度 */
background-color: #F5F5F5;
padding: 24rpx 16rpx 0 16rpx; /* 顶部24rpx间距与列表项间距一致底部0 */
box-sizing: border-box;
overflow-y: auto;
}
.service-status-toolbar {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 8rpx; /* 增加间距,避免元素被挤压 */
padding: 12rpx 8rpx; /* 增加内边距,给搜索框更多空间 */
margin-bottom: 24rpx; /* 与列表项间距保持一致24rpx */
background-color: #F8F8FA;
border-radius: 8rpx;
border: 1px solid #EFEFF2;
overflow-x: auto;
min-height: 64rpx; /* 设置最小高度,确保搜索区域不被挤压 */
box-sizing: border-box;
}
.toolbar-total {
font-size: 24rpx;
color: #666;
white-space: nowrap;
flex-shrink: 0;
margin-right: 8rpx; /* 增加右边距,与搜索框保持距离 */
line-height: 1.2;
padding: 0 4rpx; /* 增加左右内边距 */
}
.toolbar-input {
flex: 1;
min-width: 120rpx; /* 增加最小宽度,避免被挤压变形 */
max-width: 200rpx; /* 设置最大宽度,保持合理比例 */
height: 56rpx; /* 稍微增加高度,提升可用性 */
line-height: 56rpx;
background-color: #F5F6FA;
border-radius: 8rpx;
padding: 0 12rpx; /* 增加左右内边距 */
font-size: 24rpx;
border: 1px solid transparent;
box-sizing: border-box;
flex-shrink: 1; /* 允许适当收缩,但保持最小宽度 */
}
.toolbar-picker {
flex: 1;
min-width: 120rpx;
max-width: 200rpx;
flex-shrink: 1;
}
.toolbar-picker-view {
height: 56rpx;
line-height: 56rpx;
background-color: #F5F6FA;
border-radius: 8rpx;
padding: 0 12rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
.toolbar-picker-text {
font-size: 24rpx;
color: #333;
flex: 1;
}
.toolbar-picker-placeholder {
font-size: 24rpx;
color: #b0b0b0;
flex: 1;
}
.toolbar-actions {
display: flex;
align-items: center;
margin-left: auto;
flex-shrink: 0;
gap: 8rpx; /* 增加按钮之间的间距 */
}
.toolbar-btn {
padding: 0 12rpx; /* 增加左右内边距 */
height: 56rpx; /* 与输入框高度保持一致 */
min-width: 56rpx;
color: #2A68FF;
display: flex;
align-items: center;
justify-content: center;
gap: 4rpx; /* 增加图标和文字之间的间距 */
font-size: 24rpx;
font-weight: 400;
line-height: 1;
box-sizing: border-box;
}
.toolbar-btn text {
color: #2A68FF;
}
.service-card {
width: 100%;
box-sizing: border-box;
background-color: #FFFFFF;
border-radius: 16rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
overflow: visible;
}
.training-card-item {
padding-left: 32rpx;
padding-right: 32rpx;
padding-top: 32rpx;
padding-bottom: 32rpx;
position: relative;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
width: 100%;
box-sizing: border-box;
padding: 0;
margin: 0;
position: relative;
}
.training-card-action-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin-left: auto;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
flex-shrink: 0;
flex-grow: 0;
position: relative;
padding: 0;
}
.training-card-action-btn uni-icons {
display: block;
margin: 0;
padding: 0;
line-height: 1;
}
.training-card-action-btn:active {
opacity: 0.7;
}
.training-action-menu {
position: absolute;
top: 60rpx;
right: 32rpx;
width: 160rpx;
background-color: #FFFFFF;
border-radius: 12rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
z-index: 100;
overflow: hidden;
margin-right: 0;
}
.training-action-menu-item {
padding: 24rpx 32rpx;
font-size: 28rpx;
color: #333;
text-align: center;
background-color: #FFFFFF;
}
.training-action-menu-item:active {
background-color: #F5F5F5;
}
.training-action-menu-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: transparent;
z-index: 99;
}
.staff-info {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
margin: 0;
padding: 0;
}
.staff-avatar {
width: 64rpx;
height: 64rpx;
background-color: #2196F3;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16rpx;
margin-left: 0;
margin-top: 0;
margin-bottom: 0;
flex-shrink: 0;
}
.avatar-text {
font-size: 32rpx;
color: #FFFFFF;
font-weight: 500;
}
.staff-name {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.customer-tags {
display: flex;
flex-wrap: wrap;
margin-bottom: 20rpx;
gap: 12rpx;
box-sizing: border-box;
margin-left: 0;
margin-right: 0;
padding: 0;
width: 100%;
max-width: 100%;
}
.customer-info {
margin-bottom: 16rpx;
display: flex;
flex-direction: column;
gap: 8rpx;
box-sizing: border-box;
margin-left: 0;
margin-right: 0;
padding: 0;
width: 100%;
max-width: 100%;
}
.customer-name {
font-size: 28rpx;
color: #555;
}
.tag-item {
padding: 8rpx 16rpx;
border-radius: 8rpx;
box-sizing: border-box;
word-wrap: break-word;
word-break: break-all;
display: inline-block;
max-width: 100%;
}
.tag-blue {
background-color: #E3F2FD;
}
.tag-blue text {
font-size: 24rpx;
color: #1976D2;
}
.tag-orange {
background-color: #FFF3E0;
}
.tag-orange text {
font-size: 24rpx;
color: #F57C00;
}
.tag-status {
background-color: #F3F4F6;
}
.tag-status text {
font-size: 24rpx;
color: #666;
}
.service-duration {
padding-top: 16rpx;
border-top: 1px solid #F0F0F0;
}
.service-duration text {
font-size: 26rpx;
color: #999;
}
.service-status-empty {
padding: 48rpx 0;
text-align: center;
color: #999;
font-size: 28rpx;
}
.service-status-loading-more {
padding: 24rpx 0;
text-align: center;
color: #999;
font-size: 26rpx;
}
/* 添加素材弹出框样式 */
.material-popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
}
.material-popup {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: calc(100vw - 80rpx);
max-width: 90%;
box-sizing: border-box;
height: 80vh;
max-height: 80vh;
background-color: #FFFFFF;
border-radius: 16rpx;
z-index: 1000;
display: flex;
flex-direction: column;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2);
overflow: hidden;
}
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx;
border-bottom: 1px solid #E0E0E0;
flex-shrink: 0;
}
.popup-title {
font-size: 36rpx;
font-weight: 500;
color: #333;
}
.popup-close {
width: 48rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
}
.popup-content {
flex: 1;
min-height: 0;
padding: 20rpx 20rpx 28rpx;
box-sizing: border-box;
overflow-y: auto;
}
/* 陪练中列表弹窗样式 */
.training-item-list-popup {
max-height: 80vh;
}
.training-item-list-popup .popup-content {
padding: 24rpx;
}
.training-item-card {
margin-bottom: 24rpx;
}
.training-item-card:last-child {
margin-bottom: 0;
}
/* 表单样式 */
.form-item {
display: flex;
align-items: flex-start;
margin-bottom: 20rpx;
gap: 16rpx;
flex-direction: column;
}
.form-item__label {
font-size: 32rpx;
color: #333;
font-weight: 500;
width: 100%;
text-align: left;
}
.form-item__textarea {
width: 100%;
min-height: 200rpx;
background-color: #f9fafb;
border-radius: 12rpx;
padding: 24rpx;
font-size: 32rpx;
color: #333;
box-sizing: border-box;
border: 1px solid #e5e7eb;
}
/* 操作按钮样式 */
.training-item-actions {
display: flex;
gap: 24rpx;
margin-top: 24rpx;
padding-top: 24rpx;
border-top: 1px solid #F0F0F0;
}
.action-btn {
flex: 1;
height: 88rpx;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: 500;
}
.action-btn--continue {
background-color: #f3f4f6;
color: #2A68FF;
border: 1px solid #d1d5db;
}
.action-btn--continue:active {
background-color: #e5e7eb;
}
.action-btn--end {
background-color: #f3f4f6;
color: #2A68FF;
border: 1px solid #d1d5db;
}
.action-btn--end:active {
background-color: #e5e7eb;
}
</style>