费用管理

master
lzq 2026-02-27 08:48:13 +08:00
parent d29a165423
commit b59325da55
7 changed files with 173 additions and 120 deletions

View File

@ -59,7 +59,7 @@ import ATablePage, {
} from '@/components/a-page/a-table-page/ATablePage.tsx' } from '@/components/a-page/a-table-page/ATablePage.tsx'
import Strings from '@/common/utils/strings.ts' import Strings from '@/common/utils/strings.ts'
const driverFormIns = useTemplateRef<InstanceType<typeof DriverForm>>('driverForm') // const driverFormIns = useTemplateRef<InstanceType<typeof DriverForm>>('driverForm')
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage') const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')

View File

@ -74,7 +74,6 @@ const uploaderIns = useTemplateRef<InstanceType<typeof Uploader>>('uploader')
const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel') const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
const status = ref<'add' | 'modify'>('add') const status = ref<'add' | 'modify'>('add')
const formPanelProps = buildFormPanelProps<ProjectTypes.SearchProjectResult>({ const formPanelProps = buildFormPanelProps<ProjectTypes.SearchProjectResult>({
title: '',
detailsLoader(id?: string) { detailsLoader(id?: string) {
if (Strings.isBlank(id)) { if (Strings.isBlank(id)) {
status.value = 'add' status.value = 'add'
@ -84,7 +83,6 @@ const formPanelProps = buildFormPanelProps<ProjectTypes.SearchProjectResult>({
return ProjectApi return ProjectApi
.detail(id!) .detail(id!)
.then(res => { .then(res => {
console.log(res.data.contractStartDate, res.data.contractEndDate, [ Times.toDate(Times.parse(res.data.contractStartDate ?? '', FMT.date)), Times.toDate(Times.parse(res.data.contractEndDate ?? '', FMT.date)) ])
if (res.data.contractPicture != null) uploaderIns.value?.setDefaultFiles([ res.data.contractPicture ]) if (res.data.contractPicture != null) uploaderIns.value?.setDefaultFiles([ res.data.contractPicture ])
return { return {
...res.data, ...res.data,

View File

@ -3,54 +3,81 @@
ref="tablePage" ref="tablePage"
v-bind="tablePageProps"> v-bind="tablePageProps">
<template #simpleFormItem="formData"> <template #simpleFormItem="formData">
<ElFormItem>
<ElInput v-model="formData.customerId" placeholder="管理员名称"/>
</ElFormItem>
<ElFormItem>
<ElInput v-model="formData.orgId" placeholder="企业名称"/>
</ElFormItem>
<ElFormItem> <ElFormItem>
<ElInput v-model="formData.expenseItemName" placeholder="费用名称"/> <ElInput v-model="formData.expenseItemName" placeholder="费用名称"/>
</ElFormItem> </ElFormItem>
</template> </template>
<template #columns> <template #columns>
<ElTableColumn label="管理员名称" prop="userId"/> <!-- <ElTableColumn label="管理员名称" prop="userId"/> -->
<ElTableColumn label="企业名称" prop="customerId"/> <!-- <ElTableColumn label="企业名称" prop="customerId"/> -->
<ElTableColumn label="费用类型" prop="expenseItemCategory"/> <ElTableColumn label="费用类型" prop="expenseItemCategoryTxt"/>
<ElTableColumn label="付费项名称" prop="expenseItemName"/> <ElTableColumn label="付费项名称" prop="expenseItemName"/>
<ElTableColumn label="计费策略" prop="expenseStrategy"/> <ElTableColumn label="计费策略" prop="expenseStrategyTxt"/>
<ElTableColumn label="计量单位" prop="unit"/> <ElTableColumn label="计量单位" prop="unit"/>
<ElTableColumn label="税率" prop="taxRate"/> <ElTableColumn label="税率" prop="taxRate"/>
<ElTableColumn label="单价" prop="unitPrice"/> <ElTableColumn label="价格" prop="unitPrice">
<ElTableColumn label="起步价" prop="initialPrice"/> <template #default="{row}">
<ElTableColumn label="起步量" prop="initialQuantity"/> {{ row.unitPrice == null ? '-' : row.unitPrice + (row.expenseStrategy === expenseStrategy.DanJia || row.expenseStrategy === expenseStrategy.TanXing ? `元/${unit.txt(row.unit)}` : ``) }}
<ElTableColumn label="每档的量" prop="everyQuantity"/> </template>
<ElTableColumn label="是否可用" prop="canuse"/> </ElTableColumn>
<ElTableColumn label="起步价" prop="initialPrice">
<template #default="{row}">
{{ row.initialPrice == null ? '-' : row.initialPrice + unit.txt(row.unit) }}
</template>
</ElTableColumn>
<ElTableColumn label="起步量" prop="initialQuantity">
<template #default="{row}">
{{ row.initialQuantity == null ? '-' : row.initialQuantity + unit.txt(row.unit) }}
</template>
</ElTableColumn>
<ElTableColumn label="每档的量" prop="everyQuantity">
<template #default="{row}">
{{ row.everyQuantity == null ? '-' : row.everyQuantity + unit.txt(row.unit) }}
</template>
</ElTableColumn>
<ElTableColumn label="是否可用" prop="canuse" width="100">
<template #default="{row}">
<ElSwitch v-model="row.canuse" :disabled="appUserStore.isXiaoNa" @change="enableExpenseItemHandler($event as boolean,row.id)"/>
</template>
</ElTableColumn>
<ElTableColumn label="备注" prop="memo"/> <ElTableColumn label="备注" prop="memo"/>
</template> </template>
<ExpenseItemForm ref="expenseItemForm" :research="research"/> <ExpenseItemForm ref="expenseItemForm" :research="research"/>
<ExpenseItemDetail ref="expenseItemDetail"/> <!-- <ExpenseItemDetail ref="expenseItemDetail"/> -->
</ATablePage> </ATablePage>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import ExpenseItemApi from '@/pages/fin/expense-item/expense-item-api.ts' import ExpenseItemApi from '@/pages/fin/expense-item/expense-item-api.ts'
import ExpenseItemForm from '@/pages/fin/expense-item/ExpenseItemForm.vue' import ExpenseItemForm from '@/pages/fin/expense-item/ExpenseItemForm.vue'
import ExpenseItemDetail from '@/pages/fin/expense-item/ExpenseItemDetail.vue'
import ATablePage, { import ATablePage, {
type ATablePageInstance, type ATablePageInstance,
buildTablePageProps, buildTablePageProps,
} from '@/components/a-page/a-table-page/ATablePage.tsx' } from '@/components/a-page/a-table-page/ATablePage.tsx'
import {
expenseStrategy,
unit,
} from '@/pages/gds/goods/constants.ts'
import { useAppUserStore } from '@/common/app/app-user-store.ts'
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage') const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
const expenseItemFormIns = useTemplateRef<InstanceType<typeof ExpenseItemForm>>('expenseItemForm') const expenseItemFormIns = useTemplateRef<InstanceType<typeof ExpenseItemForm>>('expenseItemForm')
const expenseItemDetailIns = useTemplateRef<InstanceType<typeof ExpenseItemDetail>>('expenseItemDetail') // const expenseItemDetailIns = useTemplateRef<InstanceType<typeof ExpenseItemDetail>>('expenseItemDetail')
const appUserStore = useAppUserStore()
function research() { function research() {
tablePageIns.value?.doSearch() tablePageIns.value?.doSearch()
} }
function enableExpenseItemHandler(enable: boolean, id: string) {
ExpenseItemApi.enable({enable, id})
.then(() => {
ElMessage.success(enable ? '启用成功' : '禁用成功')
research()
})
}
const tablePageProps = buildTablePageProps<ExpenseItemTypes.SearchExpenseItemParam, ExpenseItemTypes.SearchExpenseItemResult>({ const tablePageProps = buildTablePageProps<ExpenseItemTypes.SearchExpenseItemParam, ExpenseItemTypes.SearchExpenseItemResult>({
pageLayout: { pageLayout: {
enableHighForm: false, enableHighForm: false,
@ -72,13 +99,13 @@ const tablePageProps = buildTablePageProps<ExpenseItemTypes.SearchExpenseItemPar
table: { table: {
actionColumn: { actionColumn: {
tableActions: [ tableActions: [
{ /* {
tooltip: '详情', tooltip: '详情',
icon: 'Postcard', icon: 'Postcard',
action({row}) { action({row}) {
expenseItemDetailIns.value?.open(row) expenseItemDetailIns.value?.open(row)
}, },
}, }, */
{ {
tooltip: '编辑', tooltip: '编辑',
icon: 'Edit', icon: 'Edit',
@ -87,7 +114,7 @@ const tablePageProps = buildTablePageProps<ExpenseItemTypes.SearchExpenseItemPar
expenseItemFormIns.value?.open(row) expenseItemFormIns.value?.open(row)
}, },
}, },
{ /* {
icon: 'Delete', icon: 'Delete',
loading: false, loading: false,
type: 'danger', type: 'danger',
@ -102,7 +129,7 @@ const tablePageProps = buildTablePageProps<ExpenseItemTypes.SearchExpenseItemPar
return true return true
}) })
}, },
}, }, */
], ],
}, },
}, },

View File

@ -4,68 +4,69 @@
v-bind="formPanelProps"> v-bind="formPanelProps">
<template #default="formData"> <template #default="formData">
<div class="form-items"> <div class="form-items">
<ElFormItem label="Id" prop="id"> <ElFormItem label="项目类型" prop="expenseItemCategory">
<ElInput v-model="formData.id" placeholder="Id"/> <ElSelect v-model="formData.expenseItemCategory">
<ElOption
v-for="item in expenseItemCategory"
:key="'expenseItemCategory'+item.val"
:label="item.txt"
:value="item.val"/>
</ElSelect>
</ElFormItem> </ElFormItem>
<ElFormItem label="归属用户 Id" prop="userId">
<ElInput v-model="formData.userId" placeholder="归属用户 Id"/> <ElFormItem v-if="formData.expenseItemCategory === 'ChanPin'" label="产品" prop="goodsId">
<GoodsDropTable v-model="formData.goodsId"/>
</ElFormItem> </ElFormItem>
<ElFormItem label="归属客户 Id" prop="customerId"> <ElFormItem v-else label="项目名称" prop="expenseItemName">
<ElInput v-model="formData.customerId" placeholder="归属客户 Id"/> <ElInput v-model="formData.expenseItemName" placeholder="项目名称"/>
</ElFormItem> </ElFormItem>
<ElFormItem label="归属组织 Id" prop="orgId"> <ElFormItem label="计费策略" prop="expenseStrategy">
<ElInput v-model="formData.orgId" placeholder="归属组织 Id"/> <ElRadioGroup v-model="formData.expenseStrategy">
<ElRadio v-for="it in expenseStrategy" :key="'expenseStrategy'+it.val" :value="it.val" border>{{ it.txt }}</ElRadio>
</ElRadioGroup>
</ElFormItem> </ElFormItem>
<ElFormItem label="产品 Id仅当项目类型为“产品”时有值" prop="goodsId"> <ElFormItem label="计量单位" prop="unit">
<ElInput v-model="formData.goodsId" placeholder="产品 Id仅当项目类型为“产品”时有值"/> <ElSelect v-model="formData.unit">
<ElOption
v-for="item in unit"
:key="'unit'+item.val"
:label="item.txt"
:value="item.val"/>
</ElSelect>
</ElFormItem> </ElFormItem>
<ElFormItem label="收费项目类型QiTa-->其他、ChanPin-->产品、YunFei-->运费" prop="expenseItemCategory"> <ElFormItem v-if="formData.expenseStrategy !== expenseStrategy.MianFei" label="税率" prop="taxRate">
<ElInput v-model="formData.expenseItemCategory" placeholder="收费项目类型QiTa-->其他、ChanPin-->产品、YunFei-->运费"/> <ElInputNumber v-model="formData.taxRate" :max="100" :min="0" :precision="2" :step="0.01" controls-position="right" placeholder="请输入税率">
<template #suffix>%</template>
</ElInputNumber>
</ElFormItem> </ElFormItem>
<ElFormItem label="付费项名称" prop="expenseItemName"> <ElFormItem v-if="formData.expenseStrategy === expenseStrategy.TanXing" label="起步价" prop="initialPrice">
<ElInput v-model="formData.expenseItemName" placeholder="付费项名称"/> <ElInputNumber v-model="formData.initialPrice" :min="0" :precision="2" :step="1" controls-position="right" placeholder="请输入起步价">
<template #suffix>/{{ unit.txt(formData.unit) }}</template>
</ElInputNumber>
</ElFormItem> </ElFormItem>
<ElFormItem label="计费策略字典代码expense_strategyMianFei-->免费、TanXing-->弹性、GuDing-->固定、DanJia-->单价" prop="expenseStrategy"> <ElFormItem v-if="formData.expenseStrategy === expenseStrategy.TanXing" label="起步量" prop="initialQuantity">
<ElInput v-model="formData.expenseStrategy" placeholder="计费策略字典代码expense_strategyMianFei-->免费、TanXing-->弹性、GuDing-->固定、DanJia-->单价"/> <ElInputNumber v-model="formData.initialQuantity" :min="0" :step="1" controls-position="right" placeholder="请输入起步量">
<template #suffix>{{ unit.txt(formData.unit) }}</template>
</ElInputNumber>
</ElFormItem> </ElFormItem>
<ElFormItem label="计量单位字典代码unitChe-->车、Fang-->方、GongLi-->公里、Dun-->吨" prop="unit"> <ElFormItem
<ElInput v-model="formData.unit" placeholder="计量单位字典代码unitChe-->车、Fang-->方、GongLi-->公里、Dun-->吨"/> v-if="formData.expenseStrategy !== expenseStrategy.MianFei"
:label="formData.expenseStrategy === expenseStrategy.TanXing?'每档单价':(formData.expenseStrategy === expenseStrategy.DanJia?'单价':'价格')"
prop="unitPrice">
<ElInputNumber v-model="formData.unitPrice" :min="0" :placeholder="`请输入${formData.expenseStrategy === expenseStrategy.TanXing?'每档单价':(formData.expenseStrategy === expenseStrategy.DanJia?'单价':'价格')}`" :precision="2" :step="1" controls-position="right">
<template #suffix>{{ (formData.expenseStrategy === expenseStrategy.DanJia || formData.expenseStrategy === expenseStrategy.TanXing ? `元/${unit.txt(formData.unit)}` : ``) }}</template>
</ElInputNumber>
</ElFormItem> </ElFormItem>
<ElFormItem label="税率" prop="taxRate"> <ElFormItem v-if="formData.expenseStrategy === expenseStrategy.TanXing" label="每档的量" prop="everyQuantity">
<ElInput v-model="formData.taxRate" placeholder="税率"/> <ElInputNumber v-model="formData.everyQuantity" :min="0" :step="1" controls-position="right" placeholder="请输入每档的量">
<template #suffix>{{ unit.txt(formData.unit) }}</template>
</ElInputNumber>
</ElFormItem> </ElFormItem>
<ElFormItem label="单价;单位:元,弹性模式-->每档价格" prop="unitPrice"> <ElFormItem label="是否可用" prop="canuse">
<ElInput v-model="formData.unitPrice" placeholder="单价;单位:元,弹性模式-->每档价格"/> <el-switch v-model="formData.canuse"/>
</ElFormItem>
<ElFormItem label="起步价;单位:元,<= 起步量 固定费用" prop="initialPrice">
<ElInput v-model="formData.initialPrice" placeholder="起步价;单位:元,<= 起步量 固定费用"/>
</ElFormItem>
<ElFormItem label="起步量" prop="initialQuantity">
<ElInput v-model="formData.initialQuantity" placeholder="起步量"/>
</ElFormItem>
<ElFormItem label="每档的量" prop="everyQuantity">
<ElInput v-model="formData.everyQuantity" placeholder="每档的量"/>
</ElFormItem>
<ElFormItem label="是否可用0-->否、1-->是" prop="canuse">
<ElInput v-model="formData.canuse" placeholder="是否可用0-->否、1-->是"/>
</ElFormItem> </ElFormItem>
<ElFormItem label="备注" prop="memo"> <ElFormItem label="备注" prop="memo">
<ElInput v-model="formData.memo" placeholder="备注"/> <ElInput v-model="formData.memo" placeholder="请输入备注"/>
</ElFormItem>
<ElFormItem label="创建人 Id sys_user.id" prop="creatorId">
<ElInput v-model="formData.creatorId" placeholder="创建人 Id sys_user.id"/>
</ElFormItem>
<ElFormItem label="修改人 Id sys_user.id" prop="modifierId">
<ElInput v-model="formData.modifierId" placeholder="修改人 Id sys_user.id"/>
</ElFormItem>
<ElFormItem label="创建时间" prop="createTime">
<ElInput v-model="formData.createTime" placeholder="创建时间"/>
</ElFormItem>
<ElFormItem label="修改时间" prop="modifyTime">
<ElInput v-model="formData.modifyTime" placeholder="修改时间"/>
</ElFormItem>
<ElFormItem label="是否删除; 0-->未删除、1-->已删除" prop="deleted">
<ElInput v-model="formData.deleted" placeholder="是否删除; 0-->未删除、1-->已删除"/>
</ElFormItem> </ElFormItem>
</div> </div>
</template> </template>
@ -79,6 +80,12 @@ import AFormPanel, {
buildFormPanelProps, buildFormPanelProps,
} from '@/components/a-form-panel/AFormPanel.tsx' } from '@/components/a-form-panel/AFormPanel.tsx'
import Strings from '@/common/utils/strings.ts' import Strings from '@/common/utils/strings.ts'
import {
expenseStrategy,
unit,
} from '@/pages/gds/goods/constants.ts'
import { expenseItemCategory } from '@/pages/fin/expense-item/constants.ts'
import GoodsDropTable from '@/pages/gds/goods/GoodsDropTable.vue'
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
research?: () => void research?: () => void
@ -89,11 +96,15 @@ const props = withDefaults(defineProps<{
const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel') const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
const status = ref<'add' | 'modify'>('add') const status = ref<'add' | 'modify'>('add')
const formPanelProps = buildFormPanelProps<ExpenseItemTypes.SearchExpenseItemResult>({ const formPanelProps = buildFormPanelProps<ExpenseItemTypes.SearchExpenseItemResult>({
title: status.value === 'add' ? '新建收费项目' : '修改收费项目信息',
detailsLoader(id?: string) { detailsLoader(id?: string) {
if (Strings.isBlank(id)) { if (Strings.isBlank(id)) {
status.value = 'add' status.value = 'add'
return Promise.resolve() return Promise.resolve({
expenseItemCategory: 'QiTa',
unit: 'Dun',
expenseStrategy: 'MianFei',
canuse: true,
})
} else { } else {
status.value = 'modify' status.value = 'modify'
return ExpenseItemApi return ExpenseItemApi
@ -112,31 +123,27 @@ const formPanelProps = buildFormPanelProps<ExpenseItemTypes.SearchExpenseItemRes
.then(props.research) .then(props.research)
} }
}, },
rules: { watchForm: {
id: [ {required: true, message: '请填写Id', trigger: 'blur'} ], formItems: [ 'expenseStrategy' ],
userId: [ {required: true, message: '请填写归属用户 Id', trigger: 'blur'} ], },
customerId: [ {required: true, message: '请填写归属客户 Id', trigger: 'blur'} ], rules: formData => {
orgId: [ {required: true, message: '请填写归属组织 Id', trigger: 'blur'} ], return {
goodsId: [ {required: true, message: '请填写产品 Id仅当项目类型为“产品”时有值', trigger: 'blur'} ], expenseItemCategory: [ {required: true, message: '请选择项目类型', trigger: 'blur'} ],
expenseItemCategory: [ {required: true, message: '请填写收费项目类型QiTa-->其他、ChanPin-->产品、YunFei-->运费', trigger: 'blur'} ], goodsId: [ {required: true, message: '请选择产品', trigger: 'blur'} ],
expenseItemName: [ {required: true, message: '请填写付费项名称', trigger: 'blur'} ], expenseItemName: [ {required: true, message: '请填写项目名称', trigger: 'blur'} ],
expenseStrategy: [ {required: true, message: '请填写计费策略字典代码expense_strategyMianFei-->免费、TanXing-->弹性、GuDing-->固定、DanJia-->单价', trigger: 'blur'} ], unit: [ {required: true, message: '请选择计量单位', trigger: 'blur'} ],
unit: [ {required: true, message: '请填写计量单位字典代码unitChe-->车、Fang-->方、GongLi-->公里、Dun-->吨', trigger: 'blur'} ], expenseStrategy: [ {required: true, message: '请填选择计费策略', trigger: 'blur'} ],
taxRate: [ {required: true, message: '请填写税率', trigger: 'blur'} ], taxRate: [ {required: true, message: '请填填写税率', trigger: 'blur'} ],
unitPrice: [ {required: true, message: '请填写单价;单位:元,弹性模式-->每档价格', trigger: 'blur'} ], unitPrice: [ {required: formData.expenseStrategy !== expenseStrategy.MianFei, message: `请填填写${formData.expenseStrategy === expenseStrategy.TanXing ? '每档单价' : (formData.expenseStrategy === expenseStrategy.DanJia ? '单价' : '价格')}`, trigger: 'blur'} ],
initialPrice: [ {required: true, message: '请填写起步价;单位:元,<= 起步量 固定费用', trigger: 'blur'} ], initialPrice: [ {required: formData.expenseStrategy === expenseStrategy.TanXing, message: '请填写起步价', trigger: 'blur'} ],
initialQuantity: [ {required: true, message: '请填写起步量', trigger: 'blur'} ], initialQuantity: [ {required: formData.expenseStrategy === expenseStrategy.TanXing, message: '请填写起步量', trigger: 'blur'} ],
everyQuantity: [ {required: true, message: '请填写每档的量', trigger: 'blur'} ], everyQuantity: [ {required: formData.expenseStrategy === expenseStrategy.TanXing, message: '请填写每档的量', trigger: 'blur'} ],
canuse: [ {required: true, message: '请填写是否可用0-->否、1-->是', trigger: 'blur'} ], }
memo: [ {required: true, message: '请填写备注', trigger: 'blur'} ],
creatorId: [ {required: true, message: '请填写创建人 Id sys_user.id', trigger: 'blur'} ],
modifierId: [ {required: true, message: '请填写修改人 Id sys_user.id', trigger: 'blur'} ],
createTime: [ {required: true, message: '请填写创建时间', trigger: 'blur'} ],
modifyTime: [ {required: true, message: '请填写修改时间', trigger: 'blur'} ],
deleted: [ {required: true, message: '请填写是否删除; 0-->未删除、1-->已删除', trigger: 'blur'} ],
}, },
}) })
watchEffect(() => {
formPanelProps.title = status.value === 'add' ? '新建收费项目' : '修改收费项目信息'
})
defineExpose({ defineExpose({
open(data?: ExpenseItemTypes.SearchExpenseItemResult) { open(data?: ExpenseItemTypes.SearchExpenseItemResult) {
formPanelIns.value?.open(data?.id) formPanelIns.value?.open(data?.id)

View File

@ -0,0 +1,18 @@
import { createEnum } from '@/common/utils/enums.ts'
const expenseItemCategoryList = [
{
val: 'QiTa',
txt: '其他',
},
{
val: 'ChanPin',
txt: '产品',
},
{
val: 'YunFei',
txt: '运费',
},
] as const
export const expenseItemCategory = createEnum(expenseItemCategoryList)

View File

@ -19,4 +19,7 @@ export default {
del(ids: string[]) { del(ids: string[]) {
return post('/expense_item/del', ids) return post('/expense_item/del', ids)
}, },
enable(param: { enable: boolean; id: string }) {
return get('/expense_item/enable', param)
},
} }

View File

@ -4,7 +4,7 @@ import GoodsApi from '@/pages/gds/goods/goods-api.ts'
import { bizType } from '@/pages/gds/goods-category/constants.ts' import { bizType } from '@/pages/gds/goods-category/constants.ts'
const props = defineProps<{ const props = defineProps<{
defaultBizType: typeof bizType[number]['val'] defaultBizType?: typeof bizType[number]['val']
}>() }>()
const model = defineModel<string | undefined | null>() const model = defineModel<string | undefined | null>()