Files
EmailBill/Web/src/views/ClassificationEdit.vue
孙诚 c5c3b56200
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 24s
Docker Build & Deploy / Deploy to Production (push) Successful in 10s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
色彩调整
2026-01-13 17:00:44 +08:00

412 lines
8.5 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>
<div class="page-container-flex">
<van-nav-bar
:title="navTitle"
left-text="返回"
left-arrow
placeholder
@click-left="handleBack"
/>
<div class="scroll-content">
<!-- 第一层选择交易类型 -->
<div v-if="currentLevel === 0" class="level-container">
<van-cell-group inset>
<van-cell
v-for="type in typeOptions"
:key="type.value"
:title="type.label"
is-link
@click="handleSelectType(type.value)"
/>
</van-cell-group>
</div>
<!-- 第二层分类列表 -->
<div v-else class="level-container">
<!-- 面包屑导航 -->
<div class="breadcrumb">
<van-tag
type="primary"
closeable
style="margin-left: 16px;"
@close="handleBackToRoot"
>
{{ currentTypeName }}
</van-tag>
</div>
<!-- 分类列表 -->
<van-empty v-if="categories.length === 0" description="暂无分类" />
<van-cell-group v-else inset>
<van-swipe-cell v-for="category in categories" :key="category.id">
<van-cell
:title="category.name"
is-link
@click="handleEdit(category)"
/>
<template #right>
<van-button
square
type="danger"
text="删除"
@click="handleDelete(category)"
/>
</template>
</van-swipe-cell>
</van-cell-group>
</div>
<!-- 底部安全距离 -->
<div style="height: calc(80px + env(safe-area-inset-bottom, 0px))"></div>
<div class="bottom-button">
<!-- 新增分类按钮 -->
<van-button
type="primary"
size="large"
icon="plus"
@click="handleAddCategory"
>
新增分类
</van-button>
</div>
<!-- 新增分类对话框 -->
<van-dialog
v-model:show="showAddDialog"
title="新增分类"
@confirm="handleConfirmAdd"
@cancel="resetAddForm"
>
<van-form ref="addFormRef">
<van-field
v-model="addForm.name"
name="name"
label="分类名称"
placeholder="请输入分类名称"
:rules="[{ required: true, message: '请输入分类名称' }]"
/>
</van-form>
</van-dialog>
<!-- 编辑分类对话框 -->
<van-dialog
v-model:show="showEditDialog"
title="编辑分类"
show-cancel-button
@confirm="handleConfirmEdit"
>
<van-form ref="editFormRef">
<van-field
v-model="editForm.name"
name="name"
label="分类名称"
placeholder="请输入分类名称"
:rules="[{ required: true, message: '请输入分类名称' }]"
/>
</van-form>
</van-dialog>
<!-- 删除确认对话框 -->
<van-dialog
v-model:show="showDeleteConfirm"
title="删除分类"
message="删除后无法恢复,确定要删除吗?"
@confirm="handleConfirmDelete"
/>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import {
showSuccessToast,
showToast,
showLoadingToast,
closeToast
} from 'vant'
import {
getCategoryList,
createCategory,
deleteCategory,
updateCategory
} from '@/api/transactionCategory'
const router = useRouter()
// 交易类型选项
const typeOptions = [
{ value: 0, label: '支出' },
{ value: 1, label: '收入' },
{ value: 2, label: '不计收支' }
]
// 层级状态
const currentLevel = ref(0) // 0=类型选择, 1=分类管理
const currentType = ref(null) // 当前选中的交易类型
const currentTypeName = computed(() => {
const type = typeOptions.find(t => t.value === currentType.value)
return type ? type.label : ''
})
// 分类数据
const categories = ref([])
// 编辑对话框
const showAddDialog = ref(false)
const addFormRef = ref(null)
const addForm = ref({
name: ''
})
// 删除确认
const showDeleteConfirm = ref(false)
const deleteTarget = ref(null)
// 编辑对话框
const showEditDialog = ref(false)
const editFormRef = ref(null)
const editForm = ref({
id: 0,
name: ''
})
// 计算导航栏标题
const navTitle = computed(() => {
if (currentLevel.value === 0) {
return '编辑分类'
}
return currentTypeName.value
})
/**
* 选择交易类型,进入分类管理
*/
const handleSelectType = async (type) => {
currentType.value = type
currentLevel.value = 1
await loadCategories()
}
/**
* 加载分类列表
*/
const loadCategories = async () => {
try {
showLoadingToast({
message: '加载中...',
forbidClick: true,
duration: 0
})
const { success, data } = await getCategoryList(currentType.value)
if (success) {
categories.value = data || []
} else {
showToast('加载分类失败')
}
} catch (error) {
console.error('加载分类错误:', error)
showToast('加载分类失败: ' + (error.message || '未知错误'))
} finally {
closeToast()
}
}
/**
* 返回上一级
*/
const handleBack = () => {
if (currentLevel.value === 1) {
currentLevel.value = 0
currentType.value = null
categories.value = []
} else {
router.back()
}
}
/**
* 返回到根目录(类型选择)
*/
const handleBackToRoot = () => {
currentLevel.value = 0
currentType.value = null
categories.value = []
}
/**
* 新增分类
*/
const handleAddCategory = () => {
addForm.value = {
name: ''
}
showAddDialog.value = true
}
/**
* 确认新增
*/
const handleConfirmAdd = async () => {
try {
// 表单验证
await addFormRef.value?.validate()
showLoadingToast({
message: '创建中...',
forbidClick: true,
duration: 0
})
const { success, message } = await createCategory({
name: addForm.value.name,
type: currentType.value
})
if (success) {
showSuccessToast('创建成功')
showAddDialog.value = false
resetAddForm()
await loadCategories()
} else {
showToast(message || '创建失败')
}
} catch (error) {
console.error('创建失败:', error)
showToast('创建失败: ' + (error.message || '未知错误'))
} finally {
closeToast()
}
}
/**
* 编辑分类
*/
const handleEdit = (category) => {
editForm.value = {
id: category.id,
name: category.name
}
showEditDialog.value = true
}
/**
* 确认编辑
*/
const handleConfirmEdit = async () => {
try {
await editFormRef.value?.validate()
showLoadingToast({
message: '保存中...',
forbidClick: true,
duration: 0
})
const { success, message } = await updateCategory({
id: editForm.value.id,
name: editForm.value.name
})
if (success) {
showSuccessToast('保存成功')
showEditDialog.value = false
await loadCategories()
} else {
showToast(message || '保存失败')
}
} catch (error) {
console.error('保存失败:', error)
showToast('保存失败: ' + (error.message || '未知错误'))
} finally {
closeToast()
}
}
/**
* 删除分类
*/
const handleDelete = async (category) => {
deleteTarget.value = category
showDeleteConfirm.value = true
}
/**
* 确认删除
*/
const handleConfirmDelete = async () => {
if (!deleteTarget.value) return
try {
showLoadingToast({
message: '删除中...',
forbidClick: true,
duration: 0
})
const { success, message } = await deleteCategory(deleteTarget.value.id)
if (success) {
showSuccessToast('删除成功')
showDeleteConfirm.value = false
deleteTarget.value = null
await loadCategories()
} else {
showToast(message || '删除失败')
}
} catch (error) {
console.error('删除失败:', error)
showToast('删除失败: ' + (error.message || '未知错误'))
} finally {
closeToast()
}
}
/**
* 重置新增表单
*/
const resetAddForm = () => {
addForm.value = {
name: ''
}
}
onMounted(() => {
// 初始化时显示类型选择
currentLevel.value = 0
})
</script>
<style scoped>
.level-container {
min-height: calc(100vh - 50px);
margin-top: 16px;
}
.breadcrumb {
padding: 8px 0;
}
.breadcrumb .van-tag {
cursor: pointer;
}
/* 深色模式 */
/* @media (prefers-color-scheme: dark) {
.level-container {
background: var(--van-background);
}
} */
/* 设置页面容器背景色 */
:deep(.van-nav-bar) {
background: transparent !important;
}
</style>