AI-accounting-soft-uniApp/pages/category/category.vue
2025-12-12 16:49:06 +08:00

338 lines
6.4 KiB
Vue
Raw Permalink 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 class="container">
<view class="header">
<text class="title">分类管理</text>
<button class="add-btn" @click="showAddModal = true">+ 添加</button>
</view>
<view class="tabs">
<view class="tab" :class="{ active: activeType === 1 }" @click="activeType = 1">
支出
</view>
<view class="tab" :class="{ active: activeType === 2 }" @click="activeType = 2">
收入
</view>
</view>
<view class="category-list">
<view v-for="category in filteredCategories" :key="category.id" class="category-item">
<text class="category-icon">{{ category.icon }}</text>
<text class="category-name">{{ category.name }}</text>
<view v-if="!category.userId" class="tag">系统</view>
<view v-else class="actions">
<text class="action-btn" @click="editCategory(category)">编辑</text>
<text class="action-btn delete" @click="deleteCategory(category.id)">删除</text>
</view>
</view>
</view>
<!-- 添加/编辑弹窗 -->
<view v-if="showAddModal || editingCategory" class="modal" @click="closeModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">{{ editingCategory ? '编辑分类' : '添加分类' }}</text>
<text class="close-btn" @click="closeModal">×</text>
</view>
<view class="modal-body">
<view class="form-item">
<text class="label">分类名称</text>
<input v-model="form.name" placeholder="请输入分类名称" class="input" />
</view>
<view class="form-item">
<text class="label">图标</text>
<input v-model="form.icon" placeholder="请输入图标(如:🍔)" class="input" />
</view>
<button class="submit-btn" @click="submitCategory">保存</button>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { getCategories, createCategory, updateCategory, deleteCategory as deleteCategoryApi } from '../../api/category'
const activeType = ref(1)
const categories = ref([])
const showAddModal = ref(false)
const editingCategory = ref(null)
const form = ref({
name: '',
icon: '📦',
type: 1
})
const filteredCategories = computed(() => {
return categories.value.filter(cat => cat.type === activeType.value)
})
const loadCategories = async () => {
try {
const data = await getCategories()
categories.value = data || []
} catch (error) {
console.error('加载分类失败', error)
}
}
const editCategory = (category) => {
editingCategory.value = category
form.value = {
name: category.name,
icon: category.icon,
type: category.type
}
}
const deleteCategory = async (id) => {
uni.showModal({
title: '确认删除',
content: '确定要删除这个分类吗?',
success: async (res) => {
if (res.confirm) {
try {
await deleteCategoryApi(id)
uni.showToast({
title: '删除成功',
icon: 'success'
})
loadCategories()
} catch (error) {
uni.showToast({
title: '删除失败',
icon: 'none'
})
}
}
}
})
}
const submitCategory = async () => {
if (!form.value.name) {
uni.showToast({
title: '请输入分类名称',
icon: 'none'
})
return
}
try {
form.value.type = activeType.value
if (editingCategory.value) {
await updateCategory(editingCategory.value.id, form.value)
uni.showToast({
title: '更新成功',
icon: 'success'
})
} else {
await createCategory(form.value)
uni.showToast({
title: '添加成功',
icon: 'success'
})
}
closeModal()
loadCategories()
} catch (error) {
uni.showToast({
title: editingCategory.value ? '更新失败' : '添加失败',
icon: 'none'
})
}
}
const closeModal = () => {
showAddModal.value = false
editingCategory.value = null
form.value = {
name: '',
icon: '📦',
type: 1
}
}
onMounted(() => {
loadCategories()
})
</script>
<style scoped>
.container {
min-height: 100vh;
background: #f5f5f5;
}
.header {
background: #fff;
padding: 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1rpx solid #eee;
}
.title {
font-size: 36rpx;
font-weight: bold;
}
.add-btn {
background: #667eea;
color: #fff;
padding: 10rpx 20rpx;
border-radius: 8rpx;
font-size: 26rpx;
border: none;
}
.tabs {
display: flex;
background: #fff;
margin-top: 20rpx;
padding: 10rpx;
}
.tab {
flex: 1;
text-align: center;
padding: 20rpx;
border-radius: 8rpx;
color: #666;
}
.tab.active {
background: #667eea;
color: #fff;
}
.category-list {
padding: 20rpx;
}
.category-item {
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
}
.category-icon {
font-size: 48rpx;
margin-right: 20rpx;
}
.category-name {
flex: 1;
font-size: 30rpx;
color: #333;
}
.tag {
background: #f0f0f0;
color: #999;
padding: 4rpx 12rpx;
border-radius: 4rpx;
font-size: 22rpx;
margin-right: 20rpx;
}
.actions {
display: flex;
gap: 20rpx;
}
.action-btn {
color: #667eea;
font-size: 26rpx;
}
.action-btn.delete {
color: #fa3534;
}
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
background: #fff;
border-radius: 12rpx;
width: 80%;
max-width: 600rpx;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
}
.modal-title {
font-size: 32rpx;
font-weight: bold;
}
.close-btn {
font-size: 48rpx;
color: #999;
}
.modal-body {
padding: 30rpx;
}
.form-item {
margin-bottom: 30rpx;
}
.label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 20rpx;
}
.input {
width: 100%;
padding: 20rpx;
background: #f8f8f8;
border-radius: 8rpx;
font-size: 28rpx;
}
.submit-btn {
width: 100%;
height: 88rpx;
background: #667eea;
color: #fff;
border-radius: 12rpx;
font-size: 32rpx;
border: none;
}
</style>