Initial project import

This commit is contained in:
2026-07-24 23:11:20 +08:00
commit 6396eabb87
372 changed files with 49682 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { api } from '../api'
import { message } from 'ant-design-vue'
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
interface Cat { id: number; name: string; iconKey: string; type: string; sortOrder: number; isDeleted: boolean }
const list = ref<Cat[]>([])
const loading = ref(true)
const modalVisible = ref(false)
const editing = ref<Cat | null>(null)
const form = ref({ name: '', iconKey: 'tag', type: 'expense' })
const iconOptions = [
{ value: 'food', label: '🍜 餐饮' }, { value: 'cup', label: '🥤 饮品' },
{ value: 'cart', label: '🛒 购物' }, { value: 'metro', label: '🚇 交通' },
{ value: 'house', label: '🏠 住房' }, { value: 'game', label: '🎮 娱乐' },
{ value: 'pill', label: '💊 医疗' }, { value: 'book', label: '📖 学习' },
{ value: 'shirt', label: '👕 服饰' }, { value: 'gift', label: '🎁 人情' },
{ value: 'plane', label: '✈️ 旅行' }, { value: 'tag', label: '🏷️ 其他' },
{ value: 'money', label: '💰 工资' }, { value: 'briefcase', label: '💼 兼职' },
{ value: 'chart', label: '📈 理财' }, { value: 'card', label: '💳 报销' },
{ value: 'sparkle', label: '✨ 奖金' },
]
const expenseCats = () => list.value.filter(c => c.type === 'Expense')
const incomeCats = () => list.value.filter(c => c.type === 'Income')
onMounted(refresh)
async function refresh() { loading.value = true; try { list.value = await api.sysCategories() } finally { loading.value = false } }
function openNew() { editing.value = null; form.value = { name: '', iconKey: 'tag', type: 'expense' }; modalVisible.value = true }
function openEdit(c: Cat) {
editing.value = c
form.value = { name: c.name, iconKey: c.iconKey, type: c.type === 'Income' ? 'income' : 'expense' }
modalVisible.value = true
}
async function save() {
const d = { name: form.value.name, iconKey: form.value.iconKey, type: form.value.type }
if (editing.value) await api.updateSysCategory(editing.value.id, d)
else await api.createSysCategory(d)
message.success(editing.value ? '已更新' : '已创建')
modalVisible.value = false
refresh()
}
async function del(id: number) { await api.deleteSysCategory(id); message.success('已删除(软删)'); refresh() }
</script>
<template>
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
<h2>系统默认分类</h2>
<a-button type="primary" @click="openNew"><PlusOutlined /> 新建分类</a-button>
</div>
<p style="color:#999;font-size:12px;margin-bottom:14px">
此处管理新用户注册时获得的默认分类删除后已分配用户的分类不受影响软删除仅对新用户隐藏
</p>
<a-row :gutter="16">
<a-col :span="12">
<a-card title="💸 支出分类" size="small">
<a-table :columns="[
{ title: '排序', dataIndex: 'sortOrder', width: 55 },
{ title: '图标', key: 'icon', width: 55 },
{ title: '名称', dataIndex: 'name', key: 'name' },
{ title: '', key: 'act', width: 90 },
]" :dataSource="expenseCats()" :loading="loading" rowKey="id" size="small" :pagination="{ pageSize: 10 }">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'icon'">
<span style="font-size:18px">{{ iconOptions.find(i=>i.value===record.iconKey)?.label?.split(' ')[0] || '🏷️' }}</span>
</template>
<template v-if="column.key === 'act'">
<a-button size="small" type="link" @click="openEdit(record)"><EditOutlined /></a-button>
<a-popconfirm title="确定软删除?" @confirm="del(record.id)">
<a-button size="small" type="link" danger><DeleteOutlined /></a-button>
</a-popconfirm>
</template>
</template>
</a-table>
</a-card>
</a-col>
<a-col :span="12">
<a-card title="💰 收入分类" size="small">
<a-table :columns="[
{ title: '排序', dataIndex: 'sortOrder', width: 55 },
{ title: '图标', key: 'icon', width: 55 },
{ title: '名称', dataIndex: 'name', key: 'name' },
{ title: '', key: 'act', width: 90 },
]" :dataSource="incomeCats()" :loading="loading" rowKey="id" size="small" :pagination="{ pageSize: 10 }">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'icon'">
<span style="font-size:18px">{{ iconOptions.find(i=>i.value===record.iconKey)?.label?.split(' ')[0] || '🏷️' }}</span>
</template>
<template v-if="column.key === 'act'">
<a-button size="small" type="link" @click="openEdit(record)"><EditOutlined /></a-button>
<a-popconfirm title="确定软删除?" @confirm="del(record.id)">
<a-button size="small" type="link" danger><DeleteOutlined /></a-button>
</a-popconfirm>
</template>
</template>
</a-table>
</a-card>
</a-col>
</a-row>
<a-modal v-model:open="modalVisible" :title="editing ? '编辑分类' : '新建系统分类'" @ok="save" :width="400">
<a-form layout="vertical" style="margin-top:8px">
<a-form-item label="分类名称"><a-input v-model:value="form.name" placeholder="如:宠物" /></a-form-item>
<a-form-item label="图标">
<a-select v-model:value="form.iconKey" :options="iconOptions" />
</a-form-item>
<a-form-item label="类型">
<a-radio-group v-model:value="form.type">
<a-radio value="expense">💸 支出</a-radio>
<a-radio value="income">💰 收入</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</a-modal>
</template>