Authored by Bad

feat: 更新消息提示方式,优化用户交互体验

# 标题
VITE_APP_TITLE=鸿星健身管理系统
VITE_APP_TITLE=自己练管理系统
# 项目本地运行端口号
VITE_PORT=9008
... ...
... ... @@ -124,7 +124,6 @@ const formRules = reactive({
categoryId: [{ required: true, message: '请选择部位分类', trigger: 'change' }],
equipmentId: [{ required: true, message: '请选择用具分类', trigger: 'change' }],
exerciseType: [{ required: true, message: '请选择动作类型', trigger: 'change' }],
urlTutorial: [{ required: true, message: '请上传教程地址', trigger: 'blur' }],
stepDescription: [{ required: true, message: '请输入动作步骤', trigger: 'blur' }]
})
... ...
... ... @@ -85,7 +85,7 @@ const getList = async () => {
tableData.value = res.list || []
queryParams.total = res.total || 0
} catch (err) {
ElMessage.error('请求失败,请检查网络或接口')
message.error('请求失败,请检查网络或接口')
} finally {
loading.value = false
}
... ... @@ -111,17 +111,17 @@ const openDetailDialog = (row) => {
// ===================== 删除 =====================
const handleDelete = async (id) => {
try {
await ElMessageBox.confirm('确定要删除吗?', '提示', {
await message.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await stuTrainingRecordsApi.deleteStuTrainingRecordPage(id)
ElMessage.success('删除成功')
message.success('删除成功')
getList()
} catch (err) {
if (err !== 'cancel') {
ElMessage.error('删除失败')
message.error('删除失败')
}
}
}
... ...
... ... @@ -89,11 +89,11 @@
<script setup>
import { ref, onMounted, reactive, computed, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { SupersetsApi } from '@/api/store/training/Supersets'
import { ExercisesApi } from '@/api/store/training/pose'
import { dateFormatter } from '@/utils/formatTime'
const message = useMessage() // 消息弹窗
// ===================== 查询参数 =====================
const queryParams = reactive({
pageNo: 1,
... ... @@ -170,7 +170,7 @@ const loadExercisesList = async () => {
const res = await ExercisesApi.getExercisesList(false)
exercisesList.value = res || []
} catch (err) {
ElMessage.error('加载动作列表失败')
message.error('加载动作列表失败')
}
}
... ... @@ -187,7 +187,7 @@ const getList = async () => {
tableData.value = list
total.value = resTotal
} catch (err) {
ElMessage.error('获取超级组列表失败')
message.error('获取超级组列表失败')
} finally {
loading.value = false
}
... ... @@ -229,24 +229,24 @@ const handleEdit = async (row) => {
})
dialogVisible.value = true
} catch (err) {
ElMessage.error('加载编辑数据失败')
message.error('加载编辑数据失败')
}
}
// ===================== 删除 =====================
const handleDelete = async (row) => {
try {
await ElMessageBox.confirm(`确定要删除超级组「${row.name}」吗?`, '提示', {
await message.confirm(`确定要删除超级组「${row.name}」吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await SupersetsApi.deleteSupersets(row.id)
ElMessage.success('删除成功')
message.success('删除成功')
getList()
} catch (err) {
if (err !== 'cancel') {
ElMessage.error('删除失败')
message.error('删除失败')
}
}
}
... ... @@ -275,17 +275,17 @@ const submitForm = async () => {
}
if (isEdit.value) {
await SupersetsApi.updateSupersets(payload)
ElMessage.success('修改超级组成功!')
message.success('修改超级组成功!')
} else {
await SupersetsApi.createSupersets(payload)
ElMessage.success('新增超级组成功!')
message.success('新增超级组成功!')
}
dialogVisible.value = false
getList()
} catch (err) {
const msg = err?.response?.data?.msg || err?.message
if (msg && typeof msg !== 'object') {
ElMessage.error(msg)
message.error(msg)
}
}
}
... ...
... ... @@ -38,7 +38,7 @@
<el-table-column prop="name" label="文件夹名字" align="center" />
<el-table-column prop="cover" label="封面" align="center" min-width="120">
<template #default="scope">
<img class="cover-img" :src="scope.row.urlCover || lostImg" alt="模板封面" />
<img class="cover-img" :src="scope.row.urlCover" alt="模板封面" />
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" width="220" :formatter="dateFormatter" />
... ... @@ -103,9 +103,9 @@ import { ref, reactive, onMounted, watch } from 'vue'
import { dateFormatter } from '@/utils/formatTime'
import { templateCategorysApi } from '@/api/store/training/templateCategorys'
import { TrainingTemplatesApi } from '@/api/store/training/templates'
import lostImg from '@/assets/imgs/lost.png'
import { ElMessage, ElMessageBox } from 'element-plus'
const message= useMessage() // 消息弹窗
// ===================== 列表状态 =====================
const tableData = ref([])
const loading = ref(false)
... ... @@ -144,7 +144,7 @@ const loadTemplateList = async () => {
const res = await TrainingTemplatesApi.getTemplateList(false)
templateList.value = res || []
} catch {
ElMessage.error('加载模板列表失败')
message.error('加载模板列表失败')
}
}
... ... @@ -174,7 +174,7 @@ const getList = async () => {
tableData.value = res.list || []
queryParams.total = res.total || 0
} catch {
ElMessage.error('请求失败,请检查网络或接口')
message.error('请求失败,请检查网络或接口')
} finally {
loading.value = false
}
... ... @@ -238,13 +238,13 @@ const submitForm = async () => {
try {
if (isEdit.value) {
await templateCategorysApi.updateTemplateCategorys(payload)
ElMessage.success('编辑成功')
message.success('编辑成功')
} else {
await templateCategorysApi.createTemplateCategorys(payload)
ElMessage.success('新增成功')
message.success('新增成功')
}
} catch {
ElMessage.error('提交失败,请检查网络或接口')
message.error('提交失败,请检查网络或接口')
} finally {
loading.value = false
dialogVisible.value = false
... ... @@ -255,16 +255,16 @@ const submitForm = async () => {
// ===================== 删除 =====================
const handleDelete = async (id) => {
try {
await ElMessageBox.confirm('确定要删除吗?', '提示', {
await message.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await templateCategorysApi.deleteTemplateCategorys(id)
ElMessage.success('删除成功')
message.success('删除成功')
} catch (err) {
if (err !== 'cancel') {
ElMessage.error('删除失败,请检查网络或接口')
message.error('删除失败,请检查网络或接口')
}
} finally {
getList()
... ...
... ... @@ -97,13 +97,13 @@
</template>
<script setup>
import { ref, onMounted, reactive, nextTick, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Minus, Plus } from '@element-plus/icons-vue'
import { TrainingTemplatesApi } from '@/api/store/training/templates'
import { ExercisesApi } from '@/api/store/training/pose'
import ExerciseSetTable from '../templates/ExerciseSetTable.vue'
import { SupersetsApi } from '@/api/store/training/Supersets'
const message=useMessage() // 消息弹窗
// ==================== 常量定义 ====================
const UNIT_TYPE = { GROUP: 1, SUPERSET: 2 }
... ... @@ -169,7 +169,7 @@ const loadSuperGroupList = async () => {
superGroupList.value = res || []
} catch (err) {
console.error('加载超级组列表失败:', err)
ElMessage.error('加载超级组列表失败')
}
}
... ... @@ -179,7 +179,7 @@ const loadExercisesList = async () => {
exercisesList.value = res || []
} catch (err) {
console.error('加载动作列表失败:', err)
ElMessage.error('加载动作列表失败')
}
}
... ... @@ -217,7 +217,7 @@ const loadTemplateDetail = async (id) => {
})
} catch (err) {
console.error('获取模板详情失败:', err)
ElMessage.error('获取模板详情失败')
} finally {
loading.value = false
}
... ... @@ -256,21 +256,21 @@ const getExerciseName = (id) => {
const addUnit = () => {
formData.units.push(createDefaultUnit(formData.units.length + 1))
updateDynamicRules()
ElMessage.success('新增单元成功(可切换为超级组)')
message.success('新增单元成功(可切换为超级组)')
}
const delUnit = (unitIndex) => {
if (formData.units.length <= 1) {
ElMessage.warning('至少保留一个单元')
message.warning('至少保留一个单元')
return
}
ElMessageBox.confirm('确定要删除这个单元吗?', '提示', { type: 'warning' }).then(() => {
message.confirm('确定要删除这个单元吗?', '提示', { type: 'warning' }).then(() => {
formData.units.splice(unitIndex, 1)
formData.units.forEach((unit, index) => {
unit.sortOrder = index + 1
})
updateDynamicRules()
ElMessage.success('单元删除成功')
message.success('单元删除成功')
})
}
... ... @@ -313,7 +313,7 @@ const onSelectItem = async (unitIndex, selectId) => {
// ==================== 表单提交 ====================
const handleCancel = () => {
ElMessage.info('取消保存表单内容')
formRef.value?.resetFields()
Object.assign(formData, {
id: 0,
... ... @@ -333,13 +333,13 @@ const handleSubmit = async () => {
try {
await formRef.value.validate()
} catch {
ElMessage.error('请按照要求填写')
message.error('请按照要求填写')
return
}
const hasEmptyExercise = formData.units.some((unit) => !unit.exercises[0].exerciseId)
if (hasEmptyExercise) {
ElMessage.warning('请为所有动作组选择动作名称')
message.warning('请为所有动作组选择动作名称')
return
}
... ... @@ -378,11 +378,11 @@ const handleSubmit = async () => {
} else {
await TrainingTemplatesApi.createTrainingTemplates(submitData)
}
ElMessage.success('模板保存成功!')
message.success('模板保存成功!')
router.back()
} catch (err) {
console.error('保存失败:', err?.message || err)
ElMessage.error(`保存失败:${err?.message || '网络/服务异常'}`)
} finally {
loading.value = false
}
... ...
... ... @@ -41,7 +41,7 @@
<template #default="scope">
<div class="cover-wrapper">
<!-- 优先显示行数据封面,无则显示占位图 -->
<img class="cover-img" :src="scope.row.urlCover || lostImg" alt="模板封面" align="center" />
<img class="cover-img" :src="scope.row.urlCover" alt="模板封面" align="center" />
</div>
</template>
</el-table-column>
... ... @@ -71,15 +71,14 @@
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, onMounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import lostImg from '@/assets/imgs/lost.png'
import { Search, Refresh, Plus } from '@element-plus/icons-vue'
import { TrainingTemplatesApi } from '@/api/store/training/templates'
import { dateFormatter } from '@/utils/formatTime'
import { watch } from 'vue'
const message = useMessage()
// 路由实例
const router = useRouter()
const route = useRoute()
... ... @@ -129,7 +128,7 @@ const fetchList = async () => {
tableData.value = res.list || []
pagination.total = res.total || 0
} catch (err) {
ElMessage.error('获取数据失败')
tableData.value = []
pagination.total = 0
} finally {
... ... @@ -163,24 +162,19 @@ const handleEdit = (row: any) => {
}
// 删除
const handleDelete = (row: any) => {
ElMessageBox.confirm(
message.delConfirm(
`确定要删除模板「${row.name}」吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(async () => {
try {
await TrainingTemplatesApi.deleteTrainingTemplates(row.id)
ElMessage.success('删除成功!')
message.success('删除成功!')
fetchList() // 删除后刷新列表
} catch (err) {
ElMessage.error('删除失败')
console.log('删除失败', err)
}
}).catch(() => {
ElMessage.info('已取消删除')
message.info('已取消删除')
})
}
... ...
... ... @@ -72,11 +72,11 @@
<script setup lang="ts">
import { ref, reactive, onMounted, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Search, Refresh } from '@element-plus/icons-vue'
import { dateFormatter } from '@/utils/formatTime'
import { EquipmentsApi, EquipmentsVO } from '@/api/store/training/tool'
const message = useMessage()
//处理弹窗的参数
const loading = ref(false)
const tableData = ref<EquipmentsVO[]>([])
... ... @@ -129,7 +129,7 @@ const getList = async () => {
console.log('用具分类分页接口返回数据:', res)
} catch (err) {
console.error('❌ 请求失败:', err)
ElMessage.error('请求失败,请检查网络或接口')
} finally {
loading.value = false
}
... ... @@ -192,15 +192,15 @@ const submitForm = async () => {
if (isEdit.value) {
// 编辑逻辑
await EquipmentsApi.updateEquipments({ id: formData.id, name: formData.toolName })
ElMessage.success('编辑成功')
message.success('编辑成功')
} else {
// 新增逻辑(调用新增接口)
await EquipmentsApi.createEquipments({ id: formData.id, name: formData.toolName })
ElMessage.success('新增成功')
message.success('新增成功')
}
} catch (error) {
console.error('❌ 提交失败:', error)
ElMessage.error('提交失败,请检查网络或接口')
} finally {
loading.value = false
dialogVisible.value = false
... ... @@ -212,15 +212,11 @@ const submitForm = async () => {
// 处理删除
const handleDelete = async (id: number) => {
try {
await ElMessageBox.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await message.delConfirm('确定要删除吗?')
// 能走到这里,说明用户点了确定
await EquipmentsApi.deleteEquipments(id)
ElMessage.success('删除成功')
message.success('删除成功')
} catch (err: any) {
// --------------------------
// 关键:判断是不是用户点击了取消
... ... @@ -232,7 +228,7 @@ const handleDelete = async (id: number) => {
// 只有真正的请求错误才走这里
console.error('❌ 请求失败:', err)
ElMessage.error('请求失败,请检查网络或接口')
} finally {
getList() // 刷新列表
}
... ...
... ... @@ -112,10 +112,10 @@
<script setup>
import { ref, reactive, watch, onMounted, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { TrainingTemplatesApi } from '@/api/store/training/templates'
import { trainingPlanApi } from '@/api/store/training/trainingPlan'
const message = useMessage()
// ==================== Props & Emits ====================
const props = defineProps({
visible: { type: Boolean, default: false },
... ... @@ -227,7 +227,7 @@ const initEdit = async () => {
isEdit.value = true
const res = await trainingPlanApi.getTrainingPlanDetail(props.formData.id)
if (!res || !res.id) {
ElMessage.error('获取计划详情失败')
message.error('获取计划详情失败')
return
}
SonFormData.value = res
... ... @@ -276,7 +276,7 @@ const loadTemplateList = async () => {
const res = await TrainingTemplatesApi.getTrainingTemplatesPage({ pageNo: 1, pageSize: 100 })
templateList.value = res.list || []
if (templateList.value.length === 0) {
ElMessage.warning('暂无可用训练模板,请先创建模板')
message.warning('暂无可用训练模板,请先创建模板')
}
}
... ... @@ -291,7 +291,7 @@ const loadTemplateDetail = async (index, templateId) => {
})
templateDetailMap.value[index] = res
} catch (err) {
ElMessage.error('获取模板' + (index + 1) + '详情失败')
console.log('获取模板详情失败', err)
} finally {
templateLoading.value[index] = false
}
... ... @@ -358,11 +358,11 @@ const handleSubmit = async () => {
} else {
await trainingPlanApi.createTrainingPlan(SonFormData.value)
}
ElMessage.success(isEdit.value ? '编辑成功' : '创建成功')
message.success(isEdit.value ? '编辑成功' : '创建成功')
dialogVisible.value = false
emit('submit')
} catch (err) {
ElMessage.error((isEdit.value ? '编辑' : '创建') + '失败')
console.log('提交失败', err)
} finally {
loading.value = false
}
... ...
... ... @@ -65,7 +65,7 @@
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { trainingPlanApi } from '@/api/store/training/trainingPlan'
import TrainingPlanDialog from './trainingPlanDialog.vue'
... ... @@ -75,7 +75,7 @@ import { dateFormatter } from '@/utils/formatTime'
const DIFFICULTY_MAP = { 1: '初阶', 2: '中阶', 3: '高阶' }
const TARGET_PEOPLE_MAP = { 1: '不限', 2: '青少年', 3: '成年人', 4: '中年人', 5: '运动损伤' }
const TRAINING_SCENE_MAP = { 1: '不限', 2: '健身房', 3: '仅哑铃', 4: '仅哑铃 + 杠铃' }
const message = useMessage()
// ==================== 查询参数 ====================
const queryParams = reactive({
pageNo: 1,
... ... @@ -112,7 +112,7 @@ const getList = async () => {
tableData.value = res.list || []
queryParams.total = res.total || 0
} catch (err) {
ElMessage.error('请求失败,请检查网络或接口')
console.error('获取训练计划列表失败', err)
} finally {
loading.value = false
}
... ... @@ -159,17 +159,13 @@ const handleEdit = (row) => {
// ==================== 删除 ====================
const handleDelete = async (id) => {
try {
await ElMessageBox.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await message.delConfirm('确定要删除吗?')
await trainingPlanApi.deleteTrainingPlan(id)
ElMessage.success('删除成功')
message.success('删除成功')
getList()
} catch (err) {
if (err !== 'cancel') {
ElMessage.error('删除失败')
message.error('删除失败')
}
}
}
... ...