'提交'
This commit is contained in:
@@ -46,22 +46,6 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- ==================== 空状态提示 ==================== -->
|
||||
<!-- 未选择项目时的提示 -->
|
||||
<view class="hint-state" v-if="!selectedProjectId">
|
||||
<view class="hint-icon">
|
||||
<u-icon name="list" size="80" color="#52c41a"></u-icon>
|
||||
</view>
|
||||
<text class="hint-text">请先选择项目</text>
|
||||
</view>
|
||||
|
||||
<!-- 无学生时的提示 -->
|
||||
<view class="hint-state" v-else-if="projectStudents.length === 0">
|
||||
<view class="hint-icon">
|
||||
<u-icon name="account" size="80" color="#52c41a"></u-icon>
|
||||
</view>
|
||||
<text class="hint-text">该项目暂无学员数据</text>
|
||||
</view>
|
||||
|
||||
<!-- ==================== 图表展示区域 ==================== -->
|
||||
<!-- 仅在选择了至少一名学生后显示 -->
|
||||
@@ -573,23 +557,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.hint-state {
|
||||
margin: 0 20rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 80rpx 40rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.hint-icon {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.hint-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-section {
|
||||
margin: 0 20rpx;
|
||||
|
||||
@@ -8,6 +8,42 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 选择器区域 -->
|
||||
<view class="selector-section">
|
||||
<view class="selector-item" @click="showProjectPicker = true">
|
||||
<text class="selector-label">项目名称</text>
|
||||
<view class="selector-value">
|
||||
<text class="value-text">{{ selectedProject }}</text>
|
||||
<u-icon name="arrow-down" size="24" color="#999"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="selector-item" @click="showStudentPicker = true">
|
||||
<text class="selector-label">选择学生</text>
|
||||
<view class="selector-value">
|
||||
<text class="value-text">{{ selectedStudent }}</text>
|
||||
<u-icon name="arrow-down" size="24" color="#999"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 项目选择器 -->
|
||||
<u-picker
|
||||
:show="showProjectPicker"
|
||||
:columns="[projectList]"
|
||||
@confirm="handleProjectConfirm"
|
||||
@cancel="showProjectPicker = false"
|
||||
keyName="label"></u-picker>
|
||||
|
||||
<!-- 学生选择器 -->
|
||||
<u-picker
|
||||
:show="showStudentPicker"
|
||||
:columns="[studentList]"
|
||||
@confirm="handleStudentConfirm"
|
||||
@cancel="showStudentPicker = false"
|
||||
keyName="label"
|
||||
multiple
|
||||
:defaultIndex="defaultStudentIndex"></u-picker>
|
||||
|
||||
<!-- 日历组件 -->
|
||||
<view class="calendar-wrapper">
|
||||
<uni-calendar
|
||||
@@ -55,13 +91,7 @@
|
||||
</sl-table>
|
||||
</view>
|
||||
|
||||
<!-- 未选择日期提示 -->
|
||||
<view class="hint-state" v-if="!selectedDate">
|
||||
<view class="hint-icon">
|
||||
<u-icon name="calendar" size="80" color="#faad14"></u-icon>
|
||||
</view>
|
||||
<text class="hint-text">请选择日期查看数据</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -115,18 +145,46 @@
|
||||
detail: string
|
||||
}
|
||||
|
||||
const tableData = ref<TableDataItem[]>([{ name: '张小明', projectName: '100米自由泳', plan: '2000米', completion: 95, detail: '1900/2000' },
|
||||
{ name: '李小红', projectName: '100米自由泳', plan: '2000米', completion: 88, detail: '1760/2000' },
|
||||
{ name: '王小明', projectName: '200米自由泳', plan: '1500米', completion: 100, detail: '1500/1500' }])
|
||||
const tableData = ref<TableDataItem[]>([])
|
||||
|
||||
// 项目列表
|
||||
const projectList = ref([
|
||||
{ label: '全部项目', value: 'all' },
|
||||
{ label: '100米自由泳', value: '100m-free' },
|
||||
{ label: '200米自由泳', value: '200m-free' },
|
||||
{ label: '400米自由泳', value: '400m-free' },
|
||||
{ label: '100米蛙泳', value: '100m-breast' }
|
||||
])
|
||||
|
||||
// 学生列表
|
||||
const studentList = ref([
|
||||
{ label: '全部学生', value: 'all' },
|
||||
{ label: '张小明', value: 'zhang-xiaoming' },
|
||||
{ label: '李小红', value: 'li-xiaohong' },
|
||||
{ label: '王小明', value: 'wang-xiaoming' },
|
||||
{ label: '赵小芳', value: 'zhao-xiaofang' },
|
||||
{ label: '陈小刚', value: 'chen-xiaogang' }
|
||||
])
|
||||
|
||||
// 选中的项目和学生
|
||||
const selectedProject = ref('全部项目')
|
||||
const selectedStudent = ref('全部学生')
|
||||
const selectedProjectValue = ref('all')
|
||||
const selectedStudentValues = ref<string[]>([])
|
||||
|
||||
// 选择器显示状态
|
||||
const showProjectPicker = ref(false)
|
||||
const showStudentPicker = ref(false)
|
||||
const defaultStudentIndex = ref<number[]>([0])
|
||||
|
||||
// 日历打点数据
|
||||
const selectedDates = ref([
|
||||
{ date: '2026-03-15', info: '训练' },
|
||||
{ date: '2026-03-18', info: '训练' },
|
||||
{ date: '2026-03-20', info: '训练' },
|
||||
{ date: '2026-03-22', info: '训练' },
|
||||
{ date: '2026-03-25', info: '训练' }
|
||||
])
|
||||
// const selectedDates = ref([
|
||||
// { date: '2026-03-15', info: '训练' },
|
||||
// { date: '2026-03-18', info: '训练' },
|
||||
// { date: '2026-03-20', info: '训练' },
|
||||
// { date: '2026-03-22', info: '训练' },
|
||||
// { date: '2026-03-25', info: '训练' }
|
||||
// ])
|
||||
|
||||
// 平均完成率
|
||||
const averageCompletion = computed(() => {
|
||||
@@ -135,37 +193,44 @@
|
||||
return Math.round(total / tableData.value.length)
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
// 完整模拟数据
|
||||
const mockData: Record<string, TableDataItem[]> = {
|
||||
'2026-03-15': [
|
||||
'2026-03-28': [
|
||||
{ name: '张小明', projectName: '100米自由泳', plan: '2000米', completion: 95, detail: '1900/2000' },
|
||||
{ name: '李小红', projectName: '100米自由泳', plan: '2000米', completion: 88, detail: '1760/2000' },
|
||||
{ name: '王小明', projectName: '200米自由泳', plan: '1500米', completion: 100, detail: '1500/1500' }
|
||||
],
|
||||
'2026-03-18': [
|
||||
{ name: '张小明', projectName: '100米自由泳', plan: '2000米', completion: 90, detail: '1800/2000' },
|
||||
{ name: '张小明', projectName: '200米自由泳', plan: '1500米', completion: 88, detail: '1320/1500' },
|
||||
{ name: '李小红', projectName: '100米自由泳', plan: '2000米', completion: 92, detail: '1840/2000' },
|
||||
{ name: '赵小芳', projectName: '100米自由泳', plan: '1800米', completion: 85, detail: '1530/1800' },
|
||||
{ name: '王小明', projectName: '200米自由泳', plan: '1500米', completion: 95, detail: '1425/1500' }
|
||||
{ name: '李小红', projectName: '400米自由泳', plan: '1200米', completion: 85, detail: '1020/1200' },
|
||||
{ name: '王小明', projectName: '100米自由泳', plan: '2000米', completion: 90, detail: '1800/2000' },
|
||||
{ name: '赵小芳', projectName: '100米蛙泳', plan: '1800米', completion: 88, detail: '1584/1800' },
|
||||
{ name: '陈小刚', projectName: '200米自由泳', plan: '1500米', completion: 95, detail: '1425/1500' }
|
||||
],
|
||||
'2026-03-20': [
|
||||
{ name: '张小明', projectName: '100米自由泳', plan: '2000米', completion: 87, detail: '1740/2000' },
|
||||
{ name: '李小红', projectName: '100米自由泳', plan: '2000米', completion: 90, detail: '1800/2000' }
|
||||
],
|
||||
'2026-03-22': [
|
||||
{ name: '张小明', projectName: '100米自由泳', plan: '2000米', completion: 92, detail: '1840/2000' },
|
||||
{ name: '李小红', projectName: '100米自由泳', plan: '2000米', completion: 88, detail: '1760/2000' },
|
||||
{ name: '赵小芳', projectName: '100米自由泳', plan: '1800米', completion: 90, detail: '1620/1800' },
|
||||
{ name: '王小明', projectName: '200米自由泳', plan: '1500米', completion: 98, detail: '1470/1500' },
|
||||
{ name: '陈小刚', projectName: '100米自由泳', plan: '2000米', completion: 75, detail: '1500/2000' }
|
||||
],
|
||||
'2026-03-25': [
|
||||
{ name: '张小明', projectName: '100米自由泳', plan: '2000米', completion: 85, detail: '1700/2000' },
|
||||
'2026-03-29': [
|
||||
{ name: '张小明', projectName: '100米自由泳', plan: '2000米', completion: 90, detail: '1800/2000' },
|
||||
{ name: '张小明', projectName: '100米蛙泳', plan: '1800米', completion: 85, detail: '1530/1800' },
|
||||
{ name: '李小红', projectName: '100米自由泳', plan: '2000米', completion: 95, detail: '1900/2000' },
|
||||
{ name: '赵小芳', projectName: '100米自由泳', plan: '1800米', completion: 88, detail: '1584/1800' }
|
||||
{ name: '李小红', projectName: '200米自由泳', plan: '1500米', completion: 92, detail: '1380/1500' },
|
||||
{ name: '王小明', projectName: '200米自由泳', plan: '1500米', completion: 98, detail: '1470/1500' },
|
||||
{ name: '赵小芳', projectName: '100米自由泳', plan: '2000米', completion: 82, detail: '1640/2000' },
|
||||
{ name: '陈小刚', projectName: '100米自由泳', plan: '2000米', completion: 88, detail: '1760/2000' }
|
||||
],
|
||||
'2026-03-30': [
|
||||
{ name: '张小明', projectName: '100米自由泳', plan: '2000米', completion: 92, detail: '1840/2000' },
|
||||
{ name: '张小明', projectName: '400米自由泳', plan: '1200米', completion: 90, detail: '1080/1200' },
|
||||
{ name: '李小红', projectName: '100米自由泳', plan: '2000米', completion: 88, detail: '1760/2000' },
|
||||
{ name: '李小红', projectName: '100米蛙泳', plan: '1800米', completion: 95, detail: '1710/1800' },
|
||||
{ name: '王小明', projectName: '100米自由泳', plan: '2000米', completion: 95, detail: '1900/2000' },
|
||||
{ name: '赵小芳', projectName: '200米自由泳', plan: '1500米', completion: 85, detail: '1275/1500' },
|
||||
{ name: '陈小刚', projectName: '400米自由泳', plan: '1200米', completion: 92, detail: '1104/1200' }
|
||||
]
|
||||
}
|
||||
|
||||
// 日历打点数据
|
||||
const selectedDates = ref([
|
||||
{ date: '2026-03-28', info: '训练' },
|
||||
{ date: '2026-03-29', info: '训练' },
|
||||
{ date: '2026-03-30', info: '训练' }
|
||||
])
|
||||
|
||||
onLoad(() => {
|
||||
loadData()
|
||||
})
|
||||
@@ -196,16 +261,86 @@
|
||||
|
||||
// 日期选择处理
|
||||
const handleDateChange = (e: any) => {
|
||||
// 点击日期后的处理
|
||||
const date = e.fulldate
|
||||
selectedDate.value = date
|
||||
filterAndLoadData()
|
||||
}
|
||||
|
||||
// 加载该日期的数据
|
||||
if (mockData[date]) {
|
||||
tableData.value = mockData[date]
|
||||
// 项目选择确认
|
||||
const handleProjectConfirm = (e: any) => {
|
||||
const item = e.value[0]
|
||||
selectedProject.value = item.label
|
||||
selectedProjectValue.value = item.value
|
||||
showProjectPicker.value = false
|
||||
filterAndLoadData()
|
||||
}
|
||||
|
||||
// 学生选择确认
|
||||
const handleStudentConfirm = (e: any) => {
|
||||
const items = e.value
|
||||
selectedStudentValues.value = items.map((item: any) => item.value)
|
||||
|
||||
if (selectedStudentValues.value.length === 0) {
|
||||
selectedStudent.value = '未选择'
|
||||
} else if (selectedStudentValues.value.includes('all')) {
|
||||
selectedStudent.value = '全部学生'
|
||||
} else {
|
||||
tableData.value = []
|
||||
const selectedNames = items.map((item: any) => item.label)
|
||||
selectedStudent.value = selectedNames.length > 2
|
||||
? `${selectedNames.slice(0, 2).join(', ')}等${selectedNames.length}人`
|
||||
: selectedNames.join(', ')
|
||||
}
|
||||
|
||||
defaultStudentIndex.value = e.indexs
|
||||
showStudentPicker.value = false
|
||||
filterAndLoadData()
|
||||
}
|
||||
|
||||
// 过滤并加载数据
|
||||
const filterAndLoadData = () => {
|
||||
if (!selectedDate.value) {
|
||||
tableData.value = []
|
||||
return
|
||||
}
|
||||
|
||||
const dateData = mockData[selectedDate.value]
|
||||
if (!dateData) {
|
||||
tableData.value = []
|
||||
return
|
||||
}
|
||||
|
||||
let filteredData = [...dateData]
|
||||
|
||||
// 按项目过滤
|
||||
if (selectedProjectValue.value !== 'all') {
|
||||
const projectMap: Record<string, string> = {
|
||||
'100m-free': '100米自由泳',
|
||||
'200m-free': '200米自由泳',
|
||||
'400m-free': '400米自由泳',
|
||||
'100m-breast': '100米蛙泳'
|
||||
}
|
||||
const targetProject = projectMap[selectedProjectValue.value]
|
||||
if (targetProject) {
|
||||
filteredData = filteredData.filter(item => item.projectName === targetProject)
|
||||
}
|
||||
}
|
||||
|
||||
// 按学生过滤
|
||||
if (selectedStudentValue.value !== 'all') {
|
||||
const studentMap: Record<string, string> = {
|
||||
'zhang-xiaoming': '张小明',
|
||||
'li-xiaohong': '李小红',
|
||||
'wang-xiaoming': '王小明',
|
||||
'zhao-xiaofang': '赵小芳',
|
||||
'chen-xiaogang': '陈小刚'
|
||||
}
|
||||
const targetStudent = studentMap[selectedStudentValue.value]
|
||||
if (targetStudent) {
|
||||
filteredData = filteredData.filter(item => item.name === targetStudent)
|
||||
}
|
||||
}
|
||||
|
||||
tableData.value = filteredData
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -241,6 +376,47 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* 选择器区域 */
|
||||
.selector-section {
|
||||
background-color: #fff;
|
||||
margin: 0 20rpx 20rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.selector-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 24rpx;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 12rpx;
|
||||
|
||||
.selector-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.selector-value {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
.value-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 日历组件包装 */
|
||||
.calendar-wrapper {
|
||||
background-color: #fff;
|
||||
|
||||
@@ -23,22 +23,6 @@
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- ==================== 空状态提示 ==================== -->
|
||||
<!-- 未选择项目时的提示 -->
|
||||
<view class="hint-state" v-if="!selectedProjectId">
|
||||
<view class="hint-icon">
|
||||
<u-icon name="list" size="80" color="#eb2f96"></u-icon>
|
||||
</view>
|
||||
<text class="hint-text">请先选择项目</text>
|
||||
</view>
|
||||
|
||||
<!-- 无数据时的提示 -->
|
||||
<view class="hint-state" v-else-if="gradeList.length === 0">
|
||||
<view class="hint-icon">
|
||||
<u-icon name="file-text" size="80" color="#eb2f96"></u-icon>
|
||||
</view>
|
||||
<text class="hint-text">该项目暂无排名数据</text>
|
||||
</view>
|
||||
|
||||
<!-- ==================== 排名列表区域 ==================== -->
|
||||
<!-- 仅在选择了项目且有数据时显示 -->
|
||||
@@ -70,11 +54,6 @@
|
||||
<text class="rank-number">{{ index + 1 }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 学生头像 -->
|
||||
<view class="student-avatar">
|
||||
<text class="avatar-text">{{ item.name.charAt(0) }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 学生信息 -->
|
||||
<view class="student-info">
|
||||
<text class="student-name">{{ item.name }}</text>
|
||||
@@ -308,9 +287,23 @@
|
||||
.project-select-section {
|
||||
background-color: #fff;
|
||||
margin: 0 20rpx 20rpx;
|
||||
border-radius: 16rpx;
|
||||
border-radius: 20rpx;
|
||||
padding: 28rpx;
|
||||
box-shadow: 0 2rpxrpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 6rpx;
|
||||
// background: linear-gradient(180deg, #1890ff 0%, #096dd9 100%);
|
||||
border-radius: 20rpx 0 0 20rpx;
|
||||
}
|
||||
|
||||
.picker-wrapper {
|
||||
display: flex;
|
||||
@@ -323,8 +316,9 @@
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
background-color: #f0f0f0;
|
||||
border-color: #eb2f96;
|
||||
background-color: #fff0f5;
|
||||
border-color: #1890ff;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
@@ -334,24 +328,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== 提示状态容器 ==================== */
|
||||
.hint-state {
|
||||
margin: 0 20rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 80rpx 40rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpxrpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.hint-icon {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.hint-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== 排名列表区域 ==================== */
|
||||
.ranking-section {
|
||||
@@ -360,13 +337,26 @@
|
||||
// 统计卡片
|
||||
.stats-card {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
box-shadow: 0 2rpxrpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 6rpx;
|
||||
// background: linear-gradient(180deg, #1890ff 0%, #096dd9 100%);
|
||||
border-radius: 20rpx 0 0 20rpx;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
@@ -381,7 +371,7 @@
|
||||
.stat-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #eb2f96;
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,32 +388,36 @@
|
||||
// 排名项
|
||||
.ranking-item {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
box-shadow: 0 2rpxrpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 6rpx;
|
||||
// background: linear-gradient(180deg, #1890ff 0%, #096dd9 100%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
border-radius: 20rpx 0 0 20rpx;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 4rpx 16rpx rgba(235, 47, 150, 0.15);
|
||||
}
|
||||
|
||||
// 前三名特殊样式
|
||||
&.top-three {
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 6rpx;
|
||||
background: linear-gradient(180deg, #eb2f96 0%, #f759ab 100%);
|
||||
border-radius: 16rpx 0 0 16rpx;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,7 +431,7 @@
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
background-color: #f0f0f0;
|
||||
box-shadow: 0 2rpxrpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.rank-number {
|
||||
font-size: 24rpx;
|
||||
@@ -448,7 +442,7 @@
|
||||
// 前三名特殊颜色
|
||||
&.rank-1 {
|
||||
background: linear-gradient(135deg, #ffd700 0%, #ffec3d 100%);
|
||||
box-shadow: 0 2rpxrpx 8rpx rgba(255, 215, 0, 0.4);
|
||||
box-shadow: 0 2rpx 8.6rpx rgba(255, 215, 0, 0.4);
|
||||
|
||||
.rank-number {
|
||||
color: #fff;
|
||||
@@ -458,7 +452,7 @@
|
||||
|
||||
&.rank-2 {
|
||||
background: linear-gradient(135deg, #c0c0c0 0%, #d9d9d9 100%);
|
||||
box-shadow: 0 2rpxrpx 8rpx rgba(192, 192, 192, 0.4);
|
||||
box-shadow: 0 2rpx 8rpx rgba(192, 192, 192, 0.4);
|
||||
|
||||
.rank-number {
|
||||
color: #fff;
|
||||
@@ -467,7 +461,7 @@
|
||||
|
||||
&.rank-3 {
|
||||
background: linear-gradient(135deg, #cd7f32 0%, #e6963d 100%);
|
||||
box-shadow: 0 2rpxrpx 8rpx rgba(205, 127, 50, 0.4);
|
||||
box-shadow: 0 2rpx 8rpx rgba(205, 127, 50, 0.4);
|
||||
|
||||
.rank-number {
|
||||
color: #fff;
|
||||
@@ -479,13 +473,13 @@
|
||||
.student-avatar {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
background: linear-gradient(135deg, #eb2f96 0%, #f759ab 100%);
|
||||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 2rpxrpx 8rpx rgba(235, 47, 150, 0.3);
|
||||
box-shadow: 0 2rpx 8rpx rgba(235, 47, 150, 0.3);
|
||||
|
||||
.avatar-text {
|
||||
font-size: 28rpx;
|
||||
@@ -509,7 +503,7 @@
|
||||
|
||||
.student-speed {
|
||||
font-size: 26rpx;
|
||||
color: #eb2f96;
|
||||
color: #1890ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -58,14 +58,7 @@
|
||||
</sl-table>
|
||||
</view>
|
||||
|
||||
<!-- 未选择日期提示 -->
|
||||
<!-- 未选择日期时显示提示信息 -->
|
||||
<view class="hint-state" v-if="!selectedDate">
|
||||
<view class="hint-icon">
|
||||
<u-icon name="calendar" size="80" color="#1890ff"></u-icon>
|
||||
</view>
|
||||
<text class="hint-text">请选择日期查看数据</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -152,37 +152,36 @@
|
||||
|
||||
/* 用户信息卡片 */
|
||||
.user-card {
|
||||
background: linear-gradient(135deg, #1890ff 0%, #36cfc9 50%, #096dd9 100%);
|
||||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||||
border-radius: 28rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
margin-bottom: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
box-shadow: 0 12rpx 32rpx rgba(24, 144, 255, 0.35),
|
||||
0 4rpx 12rpx rgba(24, 144, 255, 0.2);
|
||||
box-shadow: 0 8rpx 24rpx rgba(24, 144, 255, 0.25);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -60%;
|
||||
right: -40%;
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
background: radial-gradient(circle, rgba(255, 255, 255, 0.18) 0%, transparent 70%);
|
||||
top: -40%;
|
||||
right: -30%;
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
background: radial-gradient(circle, rgba(255, 255, 255, 0.15) 0%, transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -40%;
|
||||
bottom: -30%;
|
||||
left: -20%;
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
background: radial-gradient(circle, rgba(255, 255, 255, 0.12) 0%, transparent 70%);
|
||||
width: 250rpx;
|
||||
height: 250rpx;
|
||||
background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 分段数据 -->
|
||||
<view class="function-card segment-card" @click="goToSegment">
|
||||
<view class="function-card segment-card" @click="Service.GoPage('/pages/dataAnalyze/paragraphAnalyze')">
|
||||
<view class="card-icon segment-icon">
|
||||
<u-icon name="list" size="36" color="#fff"></u-icon>
|
||||
</view>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
902
src/pages/userFunc/setCourse.vue.bak
Normal file
902
src/pages/userFunc/setCourse.vue.bak
Normal file
@@ -0,0 +1,902 @@
|
||||
<template>
|
||||
<view class="course-container">
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-section">
|
||||
<!-- 项目名称 -->
|
||||
<view class="form-card">
|
||||
<view class="form-title">项目信息</view>
|
||||
<view class="form-group">
|
||||
<text class="form-label">项目名称</text>
|
||||
<input class="form-input" v-model="courseData.projectName" placeholder="请输入项目名称" placeholder-class="input-placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 出发方式 -->
|
||||
<view class="form-card">
|
||||
<view class="form-title">出发方式</view>
|
||||
<view class="radio-group">
|
||||
<view class="radio-item" :class="{ active: courseData.startType === 'together' }" @click="courseData.startType = 'together'">
|
||||
<view class="radio-icon">
|
||||
<view v-if="courseData.startType === 'together'" class="radio-inner"></view>
|
||||
</view>
|
||||
<text>一起出发</text>
|
||||
</view>
|
||||
<view class="radio-item" :class="{ active: courseData.startType === 'interval' }" @click="courseData.startType = 'interval'">
|
||||
<view class="radio-icon">
|
||||
<view v-if="courseData.startType === 'interval'" class="radio-inner"></view>
|
||||
</view>
|
||||
<text>间隔出发</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="courseData.startType === 'interval'" class="interval-input-wrapper">
|
||||
<text class="interval-label">间隔时间</text>
|
||||
<view class="interval-input">
|
||||
<input class="number-input" v-model="courseData.intervalSeconds" type="digit" placeholder="请输入秒数" />
|
||||
<text class="unit-text">秒</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 泳道设置 -->
|
||||
<view class="form-card">
|
||||
<view class="form-title">泳道设置</view>
|
||||
<view class="radio-group">
|
||||
<view class="radio-item" :class="{ active: courseData.laneType === 'single' }" @click="selectSingleLane">
|
||||
<view class="radio-icon">
|
||||
<view v-if="courseData.laneType === 'single'" class="radio-inner"></view>
|
||||
</view>
|
||||
<text>一个泳道</text>
|
||||
</view>
|
||||
<view class="radio-item" :class="{ active: courseData.laneType === 'multi' }" @click="selectMultiLane">
|
||||
<view class="radio-icon">
|
||||
<view v-if="courseData.laneType === 'multi'" class="radio-inner"></view>
|
||||
</view>
|
||||
<text>多个泳道</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="courseData.laneType === 'multi'" class="multi-lane-options">
|
||||
<view class="sub-option-item" :class="{ active: courseData.multiLaneMode === 'onePerson' }" @click="courseData.multiLaneMode = 'onePerson'">
|
||||
<view class="sub-option-icon">
|
||||
<view v-if="courseData.multiLaneMode === 'onePerson'" class="option-inner"></view>
|
||||
</view>
|
||||
<text>一个泳道一个人</text>
|
||||
</view>
|
||||
<view class="sub-option-item" :class="{ active: courseData.multiLaneMode === 'multiPerson' }" @click="courseData.multiLaneMode = 'multiPerson'">
|
||||
<view class="sub-option-icon">
|
||||
<view v-if="courseData.multiLaneMode === 'multiPerson'" class="option-inner"></view>
|
||||
</view>
|
||||
<text>一个泳道几个人</text>
|
||||
</view>
|
||||
<view v-if="courseData.multiLaneMode === 'multiPerson'" class="multi-person-input-wrapper">
|
||||
<text class="multi-label">每个泳道人数</text>
|
||||
<view class="multi-input">
|
||||
<input class="number-input" v-model="courseData.lanePersonCount" type="number" placeholder="请输入人数" />
|
||||
<text class="unit-text">人</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 学生列表 -->
|
||||
<view class="form-card">
|
||||
<view class="student-header">
|
||||
<view class="header-left">
|
||||
<text class="form-title">选择学生</text>
|
||||
<text class="student-count">已选({{ selectedStudentIds.length }}/{{ allStudents.length }})</text>
|
||||
</view>
|
||||
<view class="header-actions">
|
||||
<view class="select-all-btn" @click="toggleSelectAll">
|
||||
<view class="checkbox-icon" :class="{ checked: allSelected }">
|
||||
<u-icon v-if="allSelected" name="checkmark" size="14" color="#fff"></u-icon>
|
||||
</view>
|
||||
<text class="select-all-text">{{ allSelected ? '取消全选' : '全选' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="loading-state">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view v-else-if="allStudents.length === 0" class="empty-student-state">
|
||||
<view class="empty-icon">
|
||||
<u-icon name="account" size="48" color="#ddd"></u-icon>
|
||||
</view>
|
||||
<text class="empty-text">暂无学生</text>
|
||||
<text class="empty-desc">请先在学员管理中添加学生</text>
|
||||
</view>
|
||||
|
||||
<view v-else class="student-list">
|
||||
<view v-for="student in allStudents" :key="student.id" class="student-item" @click="toggleStudentSelect(student.id)">
|
||||
<view class="student-checkbox" :class="{ checked: selectedStudentIds.includes(student.id) }">
|
||||
<u-icon v-if="selectedStudentIds.includes(student.id)" name="checkmark" size="14" color="#fff"></u-icon>
|
||||
</view>
|
||||
<view class="student-avatar">
|
||||
<text class="avatar-text">{{ student.name.charAt(0) }}</text>
|
||||
</view>
|
||||
<view class="student-info">
|
||||
<view class="student-name">{{ student.name }}</view>
|
||||
<view class="student-meta">
|
||||
<text class="gender-badge" :class="student.gender === '男' ? 'male' : 'female'">
|
||||
{{ student.gender }}
|
||||
</text>
|
||||
<text class="age-text">{{ student.age }}岁</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已选学生预览 -->
|
||||
<view v-if="selectedStudents.length > 0" class="selected-preview">
|
||||
<view class="preview-header">
|
||||
<text class="preview-title">已选学生</text>
|
||||
</view>
|
||||
<view class="preview-list">
|
||||
<view v-for="(student, index) in selectedStudents" :key="student.id" class="preview-item">
|
||||
<text class="preview-index">{{ index + 1 }}</text>
|
||||
<text class="preview-name">{{ student.name }}</text>
|
||||
<view class="preview-remove" @click.stop="removeSelectedStudent(student.id)">
|
||||
<u-icon name="close" size="14" color="#ff4d4f"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部按钮区域 -->
|
||||
<view class="bottom-actions">
|
||||
<view class="action-buttons">
|
||||
<button class="cancel-btn" @click="goBack">取消</button>
|
||||
<button class="confirm-btn" @click="confirmCreate">创建项目</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { Service } from '@/Service/Service'
|
||||
|
||||
// 学生类型
|
||||
interface Student {
|
||||
id: string
|
||||
name: string
|
||||
gender: string
|
||||
age: string
|
||||
school?: string
|
||||
address?: string
|
||||
}
|
||||
|
||||
// 课程数据
|
||||
const courseData = ref({
|
||||
projectName: '',
|
||||
startType: 'together', // together | interval
|
||||
intervalSeconds: '',
|
||||
intervalSeconds: '',
|
||||
laneType: 'single', // single | multi
|
||||
multiLaneMode: 'onePerson', // onePerson | multiPerson
|
||||
lanePersonCount: ''
|
||||
})
|
||||
|
||||
// 所有学生列表
|
||||
const allStudents = ref<Student[]>([])
|
||||
|
||||
// 已选学生ID列表
|
||||
const selectedStudentIds = ref<string[]>([])
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
|
||||
// 是否全选
|
||||
const allSelected = computed(() => {
|
||||
return allStudents.value.length > 0 && allStudents.value.every(s => selectedStudentIds.value.includes(s.id))
|
||||
})
|
||||
|
||||
// 已选学生列表
|
||||
const selectedStudents = computed(() => {
|
||||
return allStudents.value.filter(s => selectedStudentIds.value.includes(s.id))
|
||||
})
|
||||
|
||||
// 选择单泳道
|
||||
const selectSingleLane = () => {
|
||||
courseData.value.laneType = 'single'
|
||||
courseData.value.multiLaneMode = 'onePerson'
|
||||
}
|
||||
|
||||
// 选择多泳道
|
||||
const selectMultiLane = () => {
|
||||
courseData.value.laneType = 'multi'
|
||||
}
|
||||
|
||||
// 获取学生列表(模拟接口)
|
||||
const getStudentList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// TODO: 实际项目中应从接口获取
|
||||
// const res = await Service.Request('/api/students', 'GET', {})
|
||||
// allStudents.value = res.data
|
||||
|
||||
// 模拟接口延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
|
||||
// 假数据
|
||||
allStudents.value = [
|
||||
{ id: '001', name: '张三', gender: '男', age: '12', school: '第一小学' },
|
||||
{ id: '002', name: '李四', gender: '女', age: '13', school: '第二小学' },
|
||||
{ id: '003', name: '王五', gender: '男', age: '11', school: '第一小学' },
|
||||
{ id: '004', name: '赵六', gender: '女', age: '12', school: '第三小学' },
|
||||
{ id: '005', name: '钱七', gender: '男', age: '14', school: '第二小学' },
|
||||
{ id: '006', name: '孙八', gender: '女', age: '10', school: '第一小学' },
|
||||
{ id: '007', name: '周九', gender: '男', age: '13', school: '第四小学' },
|
||||
{ id: '008', name: '吴十', gender: '女', age: '12', school: '第二小学' }
|
||||
]
|
||||
} catch (error) {
|
||||
Service.Msg('获取学生列表失败')
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 切换学生选中状态
|
||||
const toggleStudentSelect = (id: string) => {
|
||||
const index = selectedStudentIds.value.indexOf(id)
|
||||
if (index > -1) {
|
||||
selectedStudentIds.value.splice(index, 1)
|
||||
} else {
|
||||
selectedStudentIds.value.push(id)
|
||||
}
|
||||
}
|
||||
|
||||
// 全选/取消全选
|
||||
const toggleSelectAll = () => {
|
||||
if (allSelected.value) {
|
||||
// 取消全选
|
||||
selectedStudentIds.value = []
|
||||
} else {
|
||||
// 全选
|
||||
selectedStudentIds.value = allStudents.value.map(s => s.id)
|
||||
}
|
||||
}
|
||||
|
||||
// 移除已选学生
|
||||
const removeSelectedStudent = (id: string) => {
|
||||
const index = selectedStudentIds.value.indexOf(id)
|
||||
if (index > -1) {
|
||||
selectedStudentIds.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回
|
||||
const goBack = () => {
|
||||
Service.GoPageBack()
|
||||
}
|
||||
|
||||
// 创建项目
|
||||
const confirmCreate = () => {
|
||||
if (!courseData.value.projectName.trim()) {
|
||||
Service.Msg('请输入项目名称')
|
||||
return
|
||||
}
|
||||
|
||||
if (courseData.value.startType === 'interval' && !courseData.value.intervalSeconds.trim()) {
|
||||
Service.Msg('请输入间隔秒数')
|
||||
return
|
||||
}
|
||||
|
||||
if (courseData.value.laneType === 'multi' && courseData.value.multiLaneMode === 'multiPerson' && !courseData.value.lanePersonCount.trim()) {
|
||||
Service.Msg('请输入每个泳道人数')
|
||||
return
|
||||
}
|
||||
|
||||
if (selectedStudentIds.value.length === 0) {
|
||||
Service.Msg('请至少选择一位学生')
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: 调用API创建项目
|
||||
console.log('创建项目数据:', {
|
||||
course: courseData.value,
|
||||
studentIds: selectedStudentIds.value,
|
||||
students: selectedStudents.value
|
||||
})
|
||||
|
||||
Service.Msg('创建成功', 'success')
|
||||
setTimeout(() => {
|
||||
Service.GoPageBack()
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
// 页面加载时获取学生列表
|
||||
onMounted(() => {
|
||||
getStudentList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.course-container {
|
||||
min-height: 100vh;
|
||||
padding-bottom: 140rpx;
|
||||
}
|
||||
|
||||
/* 表单区域 */
|
||||
.form-section {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background-color: #fff;
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx 28rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||
|
||||
.form-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 28rpx;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* 表单输入 */
|
||||
.form-group {
|
||||
margin-bottom: 32rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:focus {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 0 4rpx rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 单选按钮组 */
|
||||
.radio-group {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.radio-item {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
transition: all 0.25s ease;
|
||||
border: 2rpx solid transparent;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
&.active {
|
||||
font-weight: 600;
|
||||
background-color: #e6f7ff;
|
||||
border-color: #1890ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.radio-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 50%;
|
||||
border: 3rpx solid #d9d9d9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
&.active .radio-icon {
|
||||
border-color: #1890ff;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
.radio-inner {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 间隔时间输入 */
|
||||
.interval-input-wrapper {
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.interval-label {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.interval-input {
|
||||
flex: 1;
|
||||
margin-left: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 72rpx;
|
||||
|
||||
.number-input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.unit-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 多泳道选项 */
|
||||
.multi-lane-options {
|
||||
padding-top: 20rpx;
|
||||
|
||||
.sub-option-item {
|
||||
padding: 20rpx 24rpx;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 16rpx;
|
||||
transition: all 0.2s ease;
|
||||
border: 2rpx solid transparent;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
&.active {
|
||||
font-weight: 600;
|
||||
background-color: #e6f7ff;
|
||||
border-color: #1890ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.sub-option-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #d9d9d9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
&.active .sub-option-icon {
|
||||
border-color: #1890ff;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
.option-inner {
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 多泳道人数输入 */
|
||||
.multi-person-input-wrapper {
|
||||
margin-top: 20rpx;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.multi-label {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.multi-input {
|
||||
flex: 1;
|
||||
margin-left: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 72rpx;
|
||||
|
||||
.number-input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.unit-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 学生列表头部 */
|
||||
.student-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
|
||||
.student-count {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
.select-all-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
.checkbox-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #d9d9d9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&.checked {
|
||||
border-color: #1890ff;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.select-all-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-state {
|
||||
padding: 80rpx 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.loading-spinner {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #f0f0f0;
|
||||
border-top-color: #1890ff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-student-state {
|
||||
padding: 60rpx 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.empty-icon {
|
||||
margin-bottom: 20rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.empty-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
/* 学生列表 */
|
||||
.student-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
|
||||
.student-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 20rpx;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 16rpx;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
|
||||
.student-checkbox {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #d9d9d9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&.checked {
|
||||
border-color: #1890ff;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.student-avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||||
border-radius: 14rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
.avatar-text {
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.student-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.student-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 6rpx;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.student-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
|
||||
.gender-badge {
|
||||
font-size: 22rpx;
|
||||
padding: 4rpx 10rpx;
|
||||
border-radius: 8rpx;
|
||||
font-weight: 500;
|
||||
|
||||
&.male {
|
||||
color: #1890ff;
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
|
||||
&.female {
|
||||
color: #fa8c16;
|
||||
background-color: #fff7e6;
|
||||
}
|
||||
}
|
||||
|
||||
.age-text {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 已选学生预览 */
|
||||
.selected-preview {
|
||||
margin-top: 32rpx;
|
||||
padding-top: 24rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
|
||||
.preview-header {
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.preview-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.preview-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding: 10rpx 16rpx;
|
||||
background-color: #e6f7ff;
|
||||
border-radius: 12rpx;
|
||||
|
||||
.preview-index {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
background-color: #1890ff;
|
||||
color: #fff;
|
||||
font-size: 18rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.preview-name {
|
||||
font-size: 26rpx;
|
||||
color: #1890ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.preview-remove {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 底部操作按钮 */
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
z-index: 99;
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cancel-btn,
|
||||
.confirm-btn {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
border-radius: 16rpx;
|
||||
border: none;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: #f5f5f5;
|
||||
color: #666;
|
||||
|
||||
&:active {
|
||||
background-color: #e8e8e8;
|
||||
transform: scale(0.96);
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||||
color: #fff;
|
||||
box-shadow: 0 6rpx 16rpx rgba(24, 144, 255, 0.35);
|
||||
|
||||
&:active {
|
||||
transform: scale(0.96);
|
||||
box-shadow: 0 3rpx 8rpx rgba(24, 144, 255, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
/* 动画 */
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -24,19 +24,19 @@
|
||||
</view>
|
||||
|
||||
<view class="athletes-list">
|
||||
<view v-for="(athlete, index) in athletes" :key="athlete.id" @longpress="deleStu(athlete.id)" class="athlete-item"
|
||||
:class="{ finished: athlete.finished, fastest: athlete.isFastest }">
|
||||
<view v-for="(athlete, index) in athletes" :key="athlete.id" @longpress="deleStu(athlete.id)"
|
||||
class="athlete-item" :class="{ finished: athlete.finished, fastest: athlete.isFastest }">
|
||||
<view class="athlete-number">{{ index+1 }}</view>
|
||||
<view class="athlete-info">
|
||||
<text class="athlete-name">{{ athlete.name }}</text>
|
||||
<text class="athlete-lane">{{ athlete.lane }}</text>
|
||||
<text class="athlete-lane">{{ athlete.gender }} · {{ athlete.age }}岁</text>
|
||||
</view>
|
||||
<view class="time-wrapper">
|
||||
<text class="athlete-time">{{ formatTime(athlete.time) }}</text>
|
||||
<text v-if="athlete.bestTime" class="best-time">最快: {{ formatTime(athlete.bestTime) }}</text>
|
||||
</view>
|
||||
<view class="" style="display: flex;align-items: center; gap: 10rpx;">
|
||||
<view v-if="stopwatchMode=='together'" @click="handleAthleteFirstButton(athlete, index)">
|
||||
<view @click="handleAthleteFirstButton(athlete, index)">
|
||||
<u-icon name="pause-circle" bold="true" size="22" color="#1890ff"></u-icon>
|
||||
</view>
|
||||
<view @click="resetAthleteTime(athlete)">
|
||||
@@ -128,12 +128,34 @@
|
||||
</view>
|
||||
<view class="modal-content">
|
||||
<view class="form-group">
|
||||
<text class="form-label">学生姓名</text>
|
||||
<input class="form-input" v-model="newStudentName" placeholder="请输入学生姓名" type="text" />
|
||||
<text class="form-label">姓名</text>
|
||||
<input class="form-input" v-model="newStudentName" placeholder="请输入姓名" type="text" />
|
||||
</view>
|
||||
<view class="form-group">
|
||||
<text class="form-label">序号</text>
|
||||
<input class="form-input" v-model="newStudentLane" placeholder="请输入序号" type="text" />
|
||||
<text class="form-label">性别</text>
|
||||
<radio-group class="radio-group" @change="onGenderChange">
|
||||
<label class="radio-item">
|
||||
<radio value="男" :checked="newStudentGender === '男'" color="#1890ff" />
|
||||
<text class="radio-text">男</text>
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<radio value="女" :checked="newStudentGender === '女'" color="#1890ff" />
|
||||
<text class="radio-text">女</text>
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
<view class="form-group">
|
||||
<text class="form-label">出生日期</text>
|
||||
<view class="date-picker-wrapper" @click="openDatePicker">
|
||||
<view class="date-value" :class="{ placeholder: !newStudentBirthday }">
|
||||
{{ Service.formatDate(newStudentBirthday,2) || '请选择出生日期' }}
|
||||
</view>
|
||||
<u-icon name="calendar" size="20" color="#999"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-group">
|
||||
<text class="form-label">年龄</text>
|
||||
<input class="form-input" v-model="newStudentAge" placeholder="自动计算" type="text" disabled />
|
||||
</view>
|
||||
</view>
|
||||
<view class="modal-footer">
|
||||
@@ -146,6 +168,9 @@
|
||||
<view class="float-save-btn" style="color: #fff; font-size: 24rpx;" @click="saveData">
|
||||
保存
|
||||
</view>
|
||||
|
||||
<!-- 日期选择器 -->
|
||||
<u-datetime-picker v-model="newStudentBirthday" :show="showDatePicker" mode="date" @confirm="onDateConfirm" @cancel="showDatePicker = false" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -158,7 +183,9 @@
|
||||
id : string
|
||||
number : string
|
||||
name : string
|
||||
lane : string
|
||||
gender : string
|
||||
age : string
|
||||
birthday : string
|
||||
time : number
|
||||
bestTime : number | null
|
||||
finished : boolean
|
||||
@@ -167,10 +194,10 @@
|
||||
|
||||
// 选手列表
|
||||
const athletes = ref<Athlete[]>([
|
||||
{ id: '1', number: '01', name: '张三', lane: '第一泳道', time: 0, bestTime: null, finished: false, isFastest: false },
|
||||
{ id: '2', number: '02', name: '李四', lane: '第二泳道', time: 0, bestTime: null, finished: false, isFastest: false },
|
||||
{ id: '3', number: '03', name: '王五', lane: '第三泳道', time: 0, bestTime: null, finished: false, isFastest: false },
|
||||
{ id: '4', number: '04', name: '赵六', lane: '第四泳道', time: 0, bestTime: null, finished: false, isFastest: false }
|
||||
{ id: '1', number: '01', name: '张三', gender: '男', age: '18', birthday: '2006-01-01', time: 0, bestTime: null, finished: false, isFastest: false },
|
||||
{ id: '2', number: '02', name: '李四', gender: '女', age: '17', birthday: '2007-01-01', time: 0, bestTime: null, finished: false, isFastest: false },
|
||||
{ id: '3', number: '03', name: '王五', gender: '男', age: '19', birthday: '2005-01-01', time: 0, bestTime: null, finished: false, isFastest: false },
|
||||
{ id: '4', number: '04', name: '赵六', gender: '女', age: '18', birthday: '2006-01-01', time: 0, bestTime: null, finished: false, isFastest: false }
|
||||
])
|
||||
|
||||
// 计时器状态
|
||||
@@ -194,24 +221,30 @@
|
||||
|
||||
// 新学生信息
|
||||
const newStudentName = ref('')
|
||||
const newStudentLane = ref('')
|
||||
const newStudentGender = ref('男')
|
||||
const newStudentBirthday = ref('')
|
||||
const newStudentAge = ref('')
|
||||
|
||||
// 日期选择器相关
|
||||
const showDatePicker = ref(false)
|
||||
const currentDate = ref('')
|
||||
|
||||
// 计算已完成的选手
|
||||
const finishedAthletes = computed(() => {
|
||||
return athletes.value.filter(a => a.finished)
|
||||
})
|
||||
|
||||
const deleStu = (id:any) => {
|
||||
const deleStu = (id : any) => {
|
||||
uni.showModal({
|
||||
title: '提示', // 对话框标题
|
||||
content: '是否删除该学生', // 显示的内容
|
||||
showCancel: true, // 是否显示取消按钮
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
let index= athletes.value.findIndex((item)=>{
|
||||
return item.id==id
|
||||
let index = athletes.value.findIndex((item) => {
|
||||
return item.id == id
|
||||
})
|
||||
athletes.value.splice(index,1)
|
||||
athletes.value.splice(index, 1)
|
||||
} else if (res.cancel) {
|
||||
|
||||
}
|
||||
@@ -317,34 +350,29 @@
|
||||
// 处理选手第一个按钮点击
|
||||
const handleAthleteFirstButton = (athlete : Athlete, index : number) => {
|
||||
// 如果是一起出发模式,记录该选手时间
|
||||
if (stopwatchMode.value === 'together') {
|
||||
if (athlete.finished) {
|
||||
Service.Msg('该选手已记录')
|
||||
return
|
||||
}
|
||||
if (athlete.finished) {
|
||||
Service.Msg('该选手已记录')
|
||||
return
|
||||
}
|
||||
|
||||
athlete.finished = true
|
||||
athlete.time = currentTime.value
|
||||
athlete.finished = true
|
||||
athlete.time = currentTime.value
|
||||
|
||||
// 更新最快记录
|
||||
if (athlete.bestTime === null || athlete.time < athlete.bestTime) {
|
||||
athlete.bestTime = athlete.time
|
||||
}
|
||||
// 更新最快记录
|
||||
if (athlete.bestTime === null || athlete.time < athlete.bestTime) {
|
||||
athlete.bestTime = athlete.time
|
||||
}
|
||||
|
||||
// 更新最快选手
|
||||
updateFastestAthlete()
|
||||
// 更新最快选手
|
||||
updateFastestAthlete()
|
||||
|
||||
// 检查是否所有选手都完成了
|
||||
const allFinished = athletes.value.every(a => a.finished)
|
||||
if (allFinished) {
|
||||
stopTimer()
|
||||
Service.Msg('所有选手已完成!')
|
||||
} else {
|
||||
Service.Msg(`${athlete.name} 已记录`)
|
||||
}
|
||||
// 检查是否所有选手都完成了
|
||||
const allFinished = athletes.value.every(a => a.finished)
|
||||
if (allFinished) {
|
||||
stopTimer()
|
||||
Service.Msg('所有选手已完成!')
|
||||
} else {
|
||||
// 间隔出发模式,重置选手时间
|
||||
resetAthleteTime(athlete)
|
||||
Service.Msg(`${athlete.name} 已记录`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,17 +429,61 @@
|
||||
showStopwatchModal.value = false
|
||||
}
|
||||
|
||||
// 性别选择变化
|
||||
const onGenderChange = (e : any) => {
|
||||
newStudentGender.value = e.detail.value
|
||||
}
|
||||
|
||||
// 打开日期选择器
|
||||
const openDatePicker = () => {
|
||||
showDatePicker.value = true
|
||||
}
|
||||
|
||||
// 根据出生日期计算年龄
|
||||
const calculateAge = (birthday : string) : string => {
|
||||
const birthDate = new Date(birthday)
|
||||
const today = new Date()
|
||||
let age = today.getFullYear() - birthDate.getFullYear()
|
||||
const monthDiff = today.getMonth() - birthDate.getMonth()
|
||||
|
||||
// 如果当前月份小于出生月份,或者月份相同但日期还没到,年龄减1
|
||||
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
||||
age--
|
||||
}
|
||||
|
||||
return age.toString()
|
||||
}
|
||||
|
||||
// 日期选择确认
|
||||
const onDateConfirm = (e : any) => {
|
||||
let selectedDate = e
|
||||
if (Array.isArray(e) && e.length > 0) {
|
||||
selectedDate = e[0]
|
||||
} else if (e && e.value) {
|
||||
selectedDate = e.value
|
||||
}
|
||||
newStudentBirthday.value = selectedDate
|
||||
newStudentAge.value = calculateAge(selectedDate)
|
||||
showDatePicker.value = false
|
||||
}
|
||||
|
||||
// 关闭添加学生弹出框
|
||||
const closeAddStudentModal = () => {
|
||||
showAddStudentModal.value = false
|
||||
newStudentName.value = ''
|
||||
newStudentLane.value = ''
|
||||
newStudentGender.value = '男'
|
||||
newStudentBirthday.value = ''
|
||||
newStudentAge.value = ''
|
||||
}
|
||||
|
||||
// 添加新学生
|
||||
const addNewStudent = () => {
|
||||
if (!newStudentName.value.trim()) {
|
||||
Service.Msg('请输入学生姓名')
|
||||
Service.Msg('请输入姓名')
|
||||
return
|
||||
}
|
||||
if (!newStudentBirthday.value.trim()) {
|
||||
Service.Msg('请选择出生日期')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -420,7 +492,9 @@
|
||||
id: Date.now().toString(),
|
||||
number: newNumber,
|
||||
name: newStudentName.value.trim(),
|
||||
lane: newStudentLane.value.trim() || `第${newNumber}泳道`,
|
||||
gender: newStudentGender.value,
|
||||
age: newStudentAge.value.trim(),
|
||||
birthday: newStudentBirthday.value.trim(),
|
||||
time: 0,
|
||||
bestTime: null,
|
||||
finished: false,
|
||||
@@ -873,6 +947,46 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* 性别单选按钮组 */
|
||||
.radio-group {
|
||||
display: flex;
|
||||
gap: 40rpx;
|
||||
|
||||
.radio-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
|
||||
.radio-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 日期选择器包装 */
|
||||
.date-picker-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 24rpx;
|
||||
cursor: pointer;
|
||||
|
||||
.date-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
|
||||
&.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 悬浮保存按钮 */
|
||||
.float-save-btn {
|
||||
position: fixed;
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
"f2",
|
||||
"图表",
|
||||
"可视化"
|
||||
],
|
||||
],
|
||||
"repository": "https://gitee.com/uCharts/uCharts",
|
||||
"engines": {
|
||||
"engines": {
|
||||
"uni-app": "^3.1.0",
|
||||
"uni-app-x": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -31,48 +33,66 @@
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/~qiun",
|
||||
"type": "component-vue"
|
||||
"type": "component-vue",
|
||||
"darkmode": "-",
|
||||
"i18n": "-",
|
||||
"widescreen": "-"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
"tcb": "√",
|
||||
"aliyun": "√"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
"uni-app": {
|
||||
"vue": {
|
||||
"vue2": "-",
|
||||
"vue3": "-"
|
||||
},
|
||||
"web": {
|
||||
"safari": "-",
|
||||
"chrome": "-"
|
||||
},
|
||||
"app": {
|
||||
"vue": "-",
|
||||
"nvue": "-",
|
||||
"android": "-",
|
||||
"ios": "-",
|
||||
"harmony": "-"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "-",
|
||||
"alipay": "-",
|
||||
"toutiao": "-",
|
||||
"baidu": "-",
|
||||
"kuaishou": "-",
|
||||
"jd": "-",
|
||||
"harmony": "-",
|
||||
"qq": "-",
|
||||
"lark": "-",
|
||||
"xhs": "-"
|
||||
},
|
||||
"quickapp": {
|
||||
"huawei": "-",
|
||||
"union": "-"
|
||||
}
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "y",
|
||||
"联盟": "y"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
"uni-app-x": {
|
||||
"web": {
|
||||
"safari": "-",
|
||||
"chrome": "-"
|
||||
},
|
||||
"app": {
|
||||
"android": "-",
|
||||
"ios": "-",
|
||||
"harmony": "-"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "-"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user