feat: 🚀 添加存储已存储金额

This commit is contained in:
Bunny 2024-11-29 16:56:28 +08:00
parent ed4233ee23
commit 3cea26c1f3
17 changed files with 193 additions and 27 deletions

View File

@ -3,6 +3,18 @@ import type { BaseResult, ResultTable } from '@/api/service/types';
/** 用户储值---获取用户储值列表 */
export const fetchGetSavingGoalList = (data: any) => {
data = {
userId: data.userId,
statusType: data.statusType,
savingGoalName: data.savingGoalName,
amount: data.amount,
amountDeposited: data.amountDeposited,
duration: data.duration,
startDuration: data.startDuration,
endDuration: data.endDuration,
pageSize: data.pageSize,
currentPage: data.currentPage,
};
return http.request<BaseResult<ResultTable>>('get', `savingGoal/getSavingGoalList/${data.currentPage}/${data.pageSize}`, { params: data });
};

View File

@ -3,7 +3,20 @@ import type { BaseResult, ResultTable } from '@/api/service/types';
/** 用户储值---获取用户储值列表 */
export const fetchGetUserSavingGoalList = (data: any) => {
return http.request<BaseResult<ResultTable>>('get', `savingGoal/noManage/getUserSavingGoalList/${data.currentPage}/${data.pageSize}`, { params: data });
data = {
statusType: data.statusType,
savingGoalName: data.savingGoalName,
amount: data.amount,
amountDeposited: data.amountDeposited,
duration: data.duration,
startDuration: data.startDuration,
endDuration: data.endDuration,
pageSize: data.pageSize,
currentPage: data.currentPage,
};
return http.request<BaseResult<ResultTable>>('get', `savingGoal/noManage/getUserSavingGoalList/${data.currentPage}/${data.pageSize}`, {
params: data,
});
};
/** 用户储值---添加用户储值 */

View File

@ -18,6 +18,7 @@ export const useSavingGoalStore = defineStore('savingGoalStore', {
statusType: undefined, // 完成状态
savingGoalName: undefined, // 储值目标名称
amount: undefined, // 目标金额
amountDeposited: undefined, // 已存入金额
duration: undefined, // 目标时长
startDuration: undefined, // 开始目标时长
endDuration: undefined, // 结束目标时长
@ -44,10 +45,6 @@ export const useSavingGoalStore = defineStore('savingGoalStore', {
// 整理请求参数
const data = { ...this.pagination, ...this.form };
delete data.pageSizes;
delete data.total;
delete data.background;
delete data.duration;
// 获取用户储值列表
const result = await fetchGetSavingGoalList(data);

View File

@ -24,6 +24,7 @@ export const useSavingGoalUserStore = defineStore('savingGoalUserStore', {
statusType: undefined, // 完成状态
savingGoalName: undefined, // 储值目标名称
amount: undefined, // 目标金额
amountDeposited: undefined, // 已存入金额
duration: getCurrentMouthDate(), // 目标时长
startDuration: undefined, // 开始目标时长
endDuration: undefined, // 结束目标时长
@ -50,10 +51,6 @@ export const useSavingGoalUserStore = defineStore('savingGoalUserStore', {
// 整理请求参数
const data = { ...this.pagination, ...this.form };
delete data.pageSizes;
delete data.total;
delete data.background;
delete data.duration;
// 获取用户储值列表
const result = await fetchGetUserSavingGoalList(data);
@ -65,12 +62,14 @@ export const useSavingGoalUserStore = defineStore('savingGoalUserStore', {
/** 添加用户储值 */
async addSavingGoal(data: any) {
data.amountDeposited = Number(data.amountDeposited) + Number(data.addAmount);
const result = await fetchAddUserSavingGoal(data);
return storeMessage(result);
},
/** 修改用户储值 */
async updateSavingGoal(data: any) {
data.amountDeposited = Number(data.amountDeposited) + Number(data.addAmount);
const result = await fetchUpdateUserSavingGoal(data);
return storeMessage(result);
},

View File

@ -64,7 +64,15 @@ onMounted(() => {
<el-form ref="formRef" :inline="true" :model="savingGoalUserStore.form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
<!-- 完成状态 -->
<el-form-item :label="$t('statusType')" prop="statusType">
<el-select v-model="savingGoalUserStore.form.statusType" :placeholder="$t('statusType')" class="!w-[180px]" clearable filterable remote remote-show-suffix>
<el-select
v-model="savingGoalUserStore.form.statusType"
:placeholder="$t('statusType')"
class="!w-[180px]"
clearable
filterable
remote
remote-show-suffix
>
<el-option v-for="item in savingGoal" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
@ -79,6 +87,16 @@ onMounted(() => {
<el-input v-model="savingGoalUserStore.form.amount" :placeholder="`${$t('input')}${$t('amount')}`" class="!w-[180px]" clearable />
</el-form-item>
<!-- 目标金额 -->
<el-form-item :label="$t('amountDeposited')" prop="amountDeposited">
<el-input
v-model="savingGoalUserStore.form.amountDeposited"
:placeholder="`${$t('input')}${$t('amountDeposited')}`"
class="!w-[180px]"
clearable
/>
</el-form-item>
<!-- 目标时长 -->
<el-form-item :label="$t('duration')" prop="duration">
<el-date-picker
@ -94,7 +112,9 @@ onMounted(() => {
<!-- 搜索和重置 -->
<el-form-item>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="savingGoalUserStore.loading" type="primary" @click="onSearch"> {{ $t('search') }} </el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="savingGoalUserStore.loading" type="primary" @click="onSearch">
{{ $t('search') }}
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> {{ $t('buttons.reset') }}</el-button>
</el-form-item>
</el-form>
@ -153,7 +173,9 @@ onMounted(() => {
</template>
<template #operation="{ row }">
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="onUpdate(row)"> {{ $t('modify') }} </el-button>
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="onUpdate(row)">
{{ $t('modify') }}
</el-button>
<el-popconfirm :title="`${$t('delete')}?`" @confirm="onDelete(row)">
<template #reference>
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary">

View File

@ -17,6 +17,10 @@ const props = withDefaults(defineProps<FormProps>(), {
savingGoalName: undefined,
//
amount: undefined,
//
amountDeposited: undefined,
//
addAmount: 0,
//
duration: undefined,
}),
@ -30,6 +34,18 @@ const userDataList = ref();
const loading = ref(false);
const adminUserStore = useAdminUserStore();
/** 已还金额自定义验证*/
const paidAmountValidator = (rule, value, callback) => {
const amountDeposited = Number(form.value.amountDeposited);
const addAmount = Number(form.value.addAmount);
//
if (amountDeposited + addAmount > form.value.amount) {
callback(new Error(`不能大于总金额`));
}
callback();
};
defineExpose({ formRef });
</script>
@ -52,6 +68,28 @@ defineExpose({ formRef });
<el-input v-model="form.amount" :min="0.01" :placeholder="$t('input') + $t('amount')" :step="0.01" autocomplete="off" type="number" />
</el-form-item>
<!-- 已存入金额 -->
<el-form-item
:label="$t('amountDeposited')"
:rules="[
{ required: true, message: `${$t('input')}${$t('amountDeposited')}`, trigger: 'blur' },
{ validator: paidAmountValidator, trigger: 'blur' },
]"
prop="amountDeposited"
>
<el-input
v-model="form.amountDeposited"
:min="0.01"
:placeholder="$t('input') + $t('amountDeposited')"
:step="0.01"
autocomplete="off"
class="w-[47%]"
type="number"
/>
<el-input v-model="form.addAmount" :min="0" :placeholder="$t('input')" :step="0.01" autocomplete="off" class="w-[48%]" type="number" />
</el-form-item>
<!-- 目标时长 -->
<el-form-item :label="$t('duration')" prop="duration">
<el-date-picker

View File

@ -24,6 +24,19 @@ export const columns: TableColumnList = [
);
},
},
// 已存入金额
{
label: $t('amountDeposited'),
prop: 'amountDeposited',
width: 150,
formatter({ amountDeposited }) {
return (
<ElText style={{ fontWeight: 800 }} type={'info'} size={'large'}>
{amountDeposited}
</ElText>
);
},
},
// 目标时长
{
label: $t('duration'),
@ -50,6 +63,8 @@ export const rules = reactive<FormRules>({
savingGoalName: [{ required: true, message: `${$t('input')}${$t('savingGoalName')}`, trigger: 'blur' }],
// 目标金额
amount: [{ required: true, message: `${$t('input')}${$t('amount')}`, trigger: 'blur' }],
// 已存入金额
amountDeposited: [{ required: true, message: `${$t('input')}${$t('amountDeposited')}`, trigger: 'blur' }],
// 目标时长
duration: [{ required: true, message: `${$t('input')}${$t('duration')}`, trigger: 'blur' }],
});

View File

@ -29,6 +29,7 @@ export function onAdd() {
statusType: undefined,
savingGoalName: undefined,
amount: undefined,
amountDeposited: undefined,
duration: undefined,
},
},
@ -64,6 +65,7 @@ export function onUpdate(row: any) {
statusType: row.statusType,
savingGoalName: row.savingGoalName,
amount: row.amount,
amountDeposited: row.amountDeposited,
duration: [row.startDuration, row.endDuration],
},
},

View File

@ -6,6 +6,10 @@ export interface FormItemProps {
savingGoalName: string;
// 目标金额
amount: any;
// 已存入金额
amountDeposited: any;
// 需要继续添加的金额
addAmount: any;
// 目标时长
duration: string;
// 开始目标时长

View File

@ -93,7 +93,15 @@ onMounted(() => {
<!-- 完成状态 -->
<el-form-item :label="$t('statusType')" prop="statusType">
<el-select v-model="savingGoalStore.form.statusType" :placeholder="$t('statusType')" class="!w-[180px]" clearable filterable remote remote-show-suffix>
<el-select
v-model="savingGoalStore.form.statusType"
:placeholder="$t('statusType')"
class="!w-[180px]"
clearable
filterable
remote
remote-show-suffix
>
<el-option v-for="item in savingGoal" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
@ -108,6 +116,11 @@ onMounted(() => {
<el-input v-model="savingGoalStore.form.amount" :placeholder="`${$t('input')}${$t('amount')}`" class="!w-[180px]" clearable />
</el-form-item>
<!-- 已存入金额 -->
<el-form-item :label="$t('amountDeposited')" prop="amountDeposited">
<el-input v-model="savingGoalStore.form.amountDeposited" :placeholder="`${$t('input')}${$t('amountDeposited')}`" class="!w-[180px]" clearable />
</el-form-item>
<!-- 目标时长 -->
<el-form-item :label="$t('duration')" prop="duration">
<el-date-picker
@ -123,7 +136,9 @@ onMounted(() => {
<!-- 搜索和重置 -->
<el-form-item>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="savingGoalStore.loading" type="primary" @click="onSearch"> {{ $t('search') }} </el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="savingGoalStore.loading" type="primary" @click="onSearch">
{{ $t('search') }}
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> {{ $t('buttons.reset') }}</el-button>
</el-form-item>
</el-form>
@ -182,7 +197,9 @@ onMounted(() => {
</template>
<template #operation="{ row }">
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="onUpdate(row)"> {{ $t('modify') }} </el-button>
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="onUpdate(row)">
{{ $t('modify') }}
</el-button>
<el-popconfirm :title="`${$t('delete')}?`" @confirm="onDelete(row)">
<template #reference>
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary">

View File

@ -18,6 +18,8 @@ const props = withDefaults(defineProps<FormProps>(), {
savingGoalName: undefined,
//
amount: undefined,
//
amountDeposited: undefined,
//
duration: undefined,
}),
@ -85,6 +87,18 @@ defineExpose({ formRef });
<el-input v-model="form.amount" :min="0.01" :placeholder="$t('input') + $t('amount')" :step="0.01" autocomplete="off" type="number" />
</el-form-item>
<!-- 已存入金额 -->
<el-form-item :label="$t('amountDeposited')" prop="amountDeposited">
<el-input
v-model="form.amountDeposited"
:min="0.01"
:placeholder="$t('input') + $t('amountDeposited')"
:step="0.01"
autocomplete="off"
type="number"
/>
</el-form-item>
<!-- 目标时长 -->
<el-form-item :label="$t('duration')" prop="duration">
<el-date-picker

View File

@ -24,6 +24,19 @@ export const columns: TableColumnList = [
);
},
},
// 已存入金额
{
label: $t('amountDeposited'),
prop: 'amountDeposited',
width: 150,
formatter({ amountDeposited }) {
return (
<ElText style={{ fontWeight: 800 }} type={'info'} size={'large'}>
{amountDeposited}
</ElText>
);
},
},
// 目标时长
{
label: $t('duration'),
@ -56,6 +69,8 @@ export const rules = reactive<FormRules>({
savingGoalName: [{ required: true, message: `${$t('input')}${$t('savingGoalName')}`, trigger: 'blur' }],
// 目标金额
amount: [{ required: true, message: `${$t('input')}${$t('amount')}`, trigger: 'blur' }],
// 已存入金额
amountDeposited: [{ required: true, message: `${$t('input')}${$t('amountDeposited')}`, trigger: 'blur' }],
// 目标时长
duration: [{ required: true, message: `${$t('input')}${$t('duration')}`, trigger: 'blur' }],
});

View File

@ -30,6 +30,7 @@ export function onAdd() {
statusType: undefined,
savingGoalName: undefined,
amount: undefined,
amountDeposited: undefined,
duration: undefined,
},
},
@ -66,6 +67,7 @@ export function onUpdate(row: any) {
statusType: row.statusType,
savingGoalName: row.savingGoalName,
amount: row.amount,
amountDeposited: row.amountDeposited,
duration: [row.startDuration, row.endDuration],
},
},

View File

@ -8,6 +8,8 @@ export interface FormItemProps {
savingGoalName: string;
// 目标金额
amount: any;
// 已存入金额
amountDeposited: any;
// 目标时长
duration: string;
// 开始目标时长

View File

@ -79,7 +79,7 @@ const form = reactive({
//
endDate: props.endDate,
pagination: {
pageSize: 10,
pageSize: 15,
currentPage: 1,
layout: 'prev, pager, next',
total: 1,

View File

@ -85,7 +85,14 @@ onMounted(() => {
</el-card>
</re-col>
<re-col v-motion :enter="{ opacity: 1, y: 0, transition: { delay: 400 } }" :initial="{ opacity: 0, y: 100 }" :value="18" :xs="24" class="mb-[18px]">
<re-col
v-motion
:enter="{ opacity: 1, y: 0, transition: { delay: 400 } }"
:initial="{ opacity: 0, y: 100 }"
:value="18"
:xs="24"
class="mb-[18px]"
>
<el-card class="bar-card" shadow="never">
<div class="flex justify-between">
<span class="text-md font-medium">{{ $t('analysisOverview') }}</span>
@ -136,8 +143,15 @@ onMounted(() => {
</re-col>
<!-- 数据统计表格 -->
<re-col v-motion :enter="{ opacity: 1, y: 0, transition: { delay: 560 } }" :initial="{ opacity: 0, y: 100 }" :value="24" :xs="24" class="mb-[18px]">
<el-card class="h-[580px]" shadow="never">
<re-col
v-motion
:enter="{ opacity: 1, y: 0, transition: { delay: 560 } }"
:initial="{ opacity: 0, y: 100 }"
:value="24"
:xs="24"
class="mb-[18px]"
>
<el-card class="h-[100%]" shadow="never">
<div class="flex justify-between">
<span class="text-md font-medium">{{ $t('dataStatistics') }}</span>
</div>

View File

@ -25,25 +25,24 @@ export const form = reactive({
/** 初始化数据 */
export const onSearch = async () => {
// 初始化请求数据,设置开始时间和结束时间范围
form.startDate = dayjs(form.dateRange[0]).format('YYYY-MM-DD');
form.endDate = dayjs(form.dateRange[1]).format('YYYY-MM-DD');
// 请求后端数据并判断是否成功
const result = await fetchHomeDatalist(form);
if (result.code !== 200) {
return;
}
chartData.value = [];
if (result.code !== 200) return;
// 顶部数据
chartData.value = [];
const homeCard = result.data?.homeCard;
const income = homeCard?.income?.amount ? homeCard?.income?.amount : 0;
const expend = homeCard?.expend?.amount ? homeCard?.expend?.amount : 0;
/* 支出百分比 */
// 支出百分比
const expendPercentValue = Number((expend / (income + expend)).toFixed(2)) * 100;
expendPercent.value = expendPercentValue ? expendPercentValue : 0;
// 收入和支出分析概览
/* 收入和支出分析概览 */
xAxis.value = result.data.homeOverview
.filter(item => item.type === 1)
.map(item => {
@ -53,13 +52,14 @@ export const onSearch = async () => {
incomeData.value = result.data.homeOverview.filter(item => item.type === 1).map(item => item.amount);
expendData.value = result.data.homeOverview.filter(item => item.type === -1).map(item => item.amount);
// 收入和支出排行榜
/* 收入和支出排行榜 */
homeRanks.value = result.data.homeRanks.map(item => {
const transactionDate = item.transactionDate;
const date = `${dayjs(transactionDate).format('YYYY-MM-DD')} ${days[dayjs(transactionDate).day()]}`;
return { date, amount: item.amount, name: item.categoryName, type: item.type };
});
/* 顶部卡片数据 */
homeCardFun(income, expend);
};