提交 9486bf69 authored 作者: lidongxu's avatar lidongxu

feat(finance): 财务分析完成第一版本

完成
上级 e44d957a
...@@ -52,3 +52,21 @@ export const getFinanceListAPI = (data) => { ...@@ -52,3 +52,21 @@ export const getFinanceListAPI = (data) => {
} }
}) })
} }
export const getFinanceDetailAPI = (data) => {
return request({
url: '/bi/finance/cost/detail/list',
method: 'POST',
data: {
zbjQdType: data.brand,
flavor: data.taste,
specName: data.spec,
series: data.seriesPrdMap.map(o => o[0]),
goodsName: data.seriesPrdMap.map(o => o[1]),
startDate: parseTime(data.date[0], `{y}-{m}-{d}`),
endDate: parseTime(data.date[1], `{y}-{m}-{d}`),
pageNum: data.pageNum,
pageSize: data.pageSize
}
})
}
\ No newline at end of file
...@@ -98,56 +98,76 @@ ...@@ -98,56 +98,76 @@
@change="getList()"> @change="getList()">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item>
<el-button icon="Refresh"
@click="reset">
重置
</el-button>
</el-form-item>
</el-form> </el-form>
<!-- 操作工具 --> <!-- 操作工具 -->
<el-row :gutter="10" <el-row
class="mb8"> class="mb8">
<el-button icon="Refresh"
@click="reset"
v-show="showSearch">
重置
</el-button>
<right-toolbar v-model:showSearch="showSearch" <right-toolbar v-model:showSearch="showSearch"
@queryTable="getList" @queryTable="getList"
:columns="columns"> :columns="columns">
</right-toolbar> </right-toolbar>
</el-row> </el-row>
<!-- 数据 --> <!-- 数据 -->
<el-table :data="tableData" <el-table :data="tableList"
border> border
@row-click="rowClick">
<template v-for="item in columns"> <template v-for="item in columns">
<el-table-column v-if="item.visible" <el-table-column v-if="item.visible"
:key="item.prop" :key="item.prop"
:label="item.label" :label="item.label"
:prop="item.prop" :prop="item.prop"
:min-width="item.width"
:formatter="formatter"> :formatter="formatter">
</el-table-column> </el-table-column>
</template> </template>
</el-table> </el-table>
<!-- 订单详情 --> <!-- 订单详情 -->
<el-dialog v-model="detailVisible" <el-dialog v-model="detailVisible"
title="Shipping address" title="订单详情"
width="80%"> width="80%"
<el-table :data="detailTableData"> footer-class="dialog-footer">
<el-table-column property="date" <el-table :data="detailList"
label="Date" ref="detailTableRef"
width="150" /> border
<el-table-column property="name" :key="showOverFlowToolTip"
label="Name" height="100%"
width="200" /> scrollbar-always-on
<el-table-column property="address" :show-overflow-tooltip="showOverFlowToolTip"
label="Address" /> scrollbar-tabindex="0">
<el-table-column v-for="item in detailColumns"
:prop="item.prop"
:label="item.label"
:width="item.width"
:formatter="detailFormatter" />
</el-table> </el-table>
<template #footer>
<el-row>
<el-button class="semi-btn"
type="primary"
icon="SemiSelect"
@click="changeShowOver">
{{ showOverFlowToolTip ? '自然展示' : '强制一行' }}
</el-button>
<pagination :total="detailTotal"
v-model:page="detailQueryParams.pageNum"
v-model:limit="detailQueryParams.pageSize"
@pagination="getDetailList"></pagination>
</el-row>
</template>
</el-dialog> </el-dialog>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { getBrandListAPI, getTasteListAPI, getSpecListAPI, getSeriesListAPI, getProductListAPI, getFinanceListAPI } from '@/api' import { getBrandListAPI, getTasteListAPI, getSpecListAPI, getSeriesListAPI, getProductListAPI, getFinanceListAPI, getFinanceDetailAPI } from '@/api'
import { useDatePickerOptions } from '@/hooks' import { useDatePickerOptions } from '@/hooks'
import { formatNumberWithUnit } from '@/utils' import { formatNumberWithUnit, parseTime } from '@/utils'
const { lastPickerOptions: pickerOptions } = useDatePickerOptions() const { lastPickerOptions: pickerOptions } = useDatePickerOptions()
const showSearch = ref(true) // 搜索 const showSearch = ref(true) // 搜索
...@@ -158,21 +178,26 @@ const data = reactive({ ...@@ -158,21 +178,26 @@ const data = reactive({
brand: [], // 直播间 brand: [], // 直播间
taste: [], // 口味 taste: [], // 口味
spec: [], // 规格 spec: [], // 规格
// series: [], // 系列
// goods: [], // 商品
date: [], // 日期 date: [], // 日期
seriesPrdMap: [] // 系列商品 seriesPrdMap: [] // 系列商品
} },
detailQueryParams: { // 详情查询
pageNum: 1,
pageSize: 10
},
}) })
const { queryParams } = toRefs(data) const { queryParams, detailQueryParams } = toRefs(data)
const reset = () => { const reset = () => {
queryParams.value = { queryParams.value = {
brand: [], // 直播间 brand: [], // 直播间
taste: [], // 口味 taste: [], // 口味
spec: [], // 规格 spec: [], // 规格
date: [], // 日期 date: [], // 日期
seriesPrdMap: [] // 系列商品 seriesPrdMap: [], // 系列商品
pageNum: 1,
pageSize: 10
} }
getList() getList()
} }
...@@ -254,59 +279,69 @@ const columns = ref([ ...@@ -254,59 +279,69 @@ const columns = ref([
{ {
label: '直播间', label: '直播间',
prop: 'zbjQdType', prop: 'zbjQdType',
visible: true visible: true,
width: 140
}, },
{ {
label: '口味', label: '口味',
prop: 'flavorErp', prop: 'flavorErp',
visible: true visible: true,
width: 120
}, },
{ {
label: '规格', label: '规格',
prop: 'specNameErp', prop: 'specNameErp',
visible: true visible: true,
width: 140
}, },
{ {
label: '系列', label: '系列',
prop: 'a', prop: '',
visible: true visible: true,
width: 140
}, },
{ {
label: '商品', label: '商品',
prop: 'goodsName', prop: 'goodsName',
visible: true visible: true,
width: 140
}, },
{ {
label: '分摊后总价', label: '分摊后总价',
prop: 'shareAmountSum', prop: 'shareAmountSum',
visible: true visible: true,
width: 120
}, },
{ {
label: '实际成本', label: '实际成本',
prop: 'actualCostSum', prop: 'actualCostSum',
visible: true visible: true,
width: 120
}, },
{ {
label: '实际成本毛利', label: '实际成本毛利',
prop: 'actualCostGrossProfitSum', prop: 'actualCostGrossProfitSum',
visible: true visible: true,
width: 120
}, },
{ {
label: '标准成本', label: '标准成本',
prop: 'standardCostSum', prop: 'standardCostSum',
visible: true visible: true,
width: 120
}, },
{ {
label: '标准成本毛利', label: '标准成本毛利',
prop: 'standardCostGrossProfitSum', prop: 'standardCostGrossProfitSum',
visible: true visible: true,
width: 120
} }
]) ])
const tableData = ref([ const tableList = ref([
]) ])
const getList = async () => { const getList = async () => {
const res = await getFinanceListAPI(queryParams.value) const res = await getFinanceListAPI(queryParams.value)
tableData.value = res.data.list tableList.value = res.data.list
} }
getList() getList()
...@@ -319,86 +354,201 @@ const formatter = (row, column, value) => { ...@@ -319,86 +354,201 @@ const formatter = (row, column, value) => {
} }
// 详情数据 // 详情数据
const detailTableData = ref([]) const detailList = ref([])
const detailColumns = ref([ const detailColumns = ref([
{ {
label: '订单编号', label: '订单编号',
prop: 'id' prop: 'tradeNo',
width: 160
}, { }, {
label: '店铺名称', label: '店铺名称',
prop: 'name' prop: 'shopName',
}, width: 220
{ }, {
label: '原始单号', label: '原始单号',
prop: '' prop: 'srcTid',
width: 180
}, { }, {
label: '原始子单号', label: '原始子单号',
prop: '' prop: 'srcOid',
width: 180
}, { }, {
label: '订单状态', label: '订单状态',
prop: '' prop: 'tradeStatus',
width: 80
}, { }, {
label: '交易时间', label: '交易时间',
prop: '' prop: 'tradeTime',
width: 170
}, { }, {
label: '付款时间', label: '付款时间',
prop: '' prop: 'payTime',
width: 170
}, { }, {
label: '发货时间', label: '发货时间',
prop: '' prop: 'consignTime',
width: 170
}, { }, {
label: '省市县', label: '省市县',
prop: '' prop: 'receiverArea',
width: 170
}, { }, {
label: '备注', label: '备注',
prop: '' prop: 'remark',
width: 250
}, { }, {
label: '应收金额', label: '应收金额',
prop: '' prop: 'receivable',
width: 80
}, { }, {
label: '货品编号', label: '货品编号',
prop: '' prop: 'goodsNo',
width: 120
}, { }, {
label: '货品名称', label: '货品名称',
prop: '' prop: 'goodsName',
width: 250
}, { }, {
label: '规格名称', label: '规格名称',
prop: '' prop: 'specName'
}, { }, {
label: '分类', label: '分类',
prop: '' prop: 'goodsType',
width: 100
}, { }, {
label: '数量', label: '数量',
prop: '' prop: 'num'
}, { }, {
label: '优惠', label: '优惠',
prop: '' prop: 'discount'
}, { }, {
label: '分摊后总价', label: '分摊后总价',
prop: '' prop: 'shareAmount',
width: 120
}, { }, {
label: '拆自组合装', label: '拆自组合装',
prop: '' prop: 'suiteNo',
width: 200
}, { }, {
label: '组合装编码', label: '组合装编码',
prop: '' prop: 'suiteName',
width: 200
}, { }, {
label: '组合装数量', label: '组合装数量',
prop: '' prop: 'suiteNum',
width: 140
}, { }, {
label: '赠品方式', label: '赠品方式',
prop: '' prop: 'giftType',
width: 160
}, { }, {
label: '分销商名称', label: '分销商名称',
prop: '' prop: 'fenxiaoName',
width: 240
}, { }, {
label: '分销商编号', label: '分销商编号',
prop: '' prop: 'fenxiaoId',
width: 160
}, { }, {
label: '平台货品名称', label: '平台货品名称',
prop: '' prop: 'apiGoodsName',
width: 540
} }
]) ])
const detailTotal = ref(0)
const showOverFlowToolTip = ref(true) // 强制表格一行显示
const detailTableRef = ref(null)
// 订单状态
const orderStatus = {
4: "线下退款",
5: "已取消",
6: "待转预订单(待审核)",
7: "待转已完成",
10: "未付款",
12: "待尾款",
15: "等未付",
16: "延时审核",
19: "预订单前处理",
20: "审核前处理",
21: "自流转待发货",
23: "异常订单",
24: "换货预订单",
25: "待处理预订单",
27: "待分配预订单",
30: "待客审",
35: "待财审",
40: "审核中",
55: "已审核",
95: "已发货",
96: "成本确认(待录入计划成本,订单结算时有货品无计划成本)",
101: "已过账",
110: "已完成"
};
// 分类(货品类型)
const goodsType = {
1: "销售商品",
2: "原材料",
3: "包装",
4: "周转材料",
5: "虚拟商品",
6: "固定资产",
0: "其它"
};
// 赠品方式
const giftType = {
0: "非赠品",
1: "自动赠送",
2: "手工赠送",
4: "周期购赠送",
8: "平台赠送",
32: "阶梯满赠",
64: "CRM追加赠送",
128: "主品"
};
const rowClick = (row) => {
detailQueryParams.value = {
brand: row.zbjQdType && [row.zbjQdType], // 直播间
taste: row.flavorErp && [row.flavorErp], // 口味
spec: row.specNameErp && [row.specNameErp], // 规格
seriesPrdMap: [], // TODO:行里没有系列字段等会看下
date: queryParams.value.date, // 日期
pageNum: 1,
pageSize: 10
}
// 口味
row.flavorErp && (detailQueryParams.value.taste = [row.flavorErp])
// 规格
row.specNameErp && (detailQueryParams.value.spec = [row.specNameErp])
// 系列+商品
row.seriesId && (detailQueryParams.value.seriesPrdMap = [{ value: row.seriesId, label: row.seriesName }])
// 日期
detailQueryParams.value.date = queryParams.value.date
detailQueryParams.value.pageNum = 1
detailQueryParams.value.pageSize = 10
detailVisible.value = true
getDetailList()
}
const getDetailList = async () => {
const { data: { list, total } } = await getFinanceDetailAPI(detailQueryParams.value)
detailList.value = list
detailTotal.value = total
}
const detailFormatter = (row, column, value) => {
if (['tradeTime', 'payTime', 'consignTime'].includes(column.property)) {
return parseTime(value, '{y}-{m}-{d} {h}:{i}:{s}')
} else if (['tradeStatus'].includes(column.property)) {
return orderStatus[value]
} else if (['goodsType'].includes(column.property)) {
return goodsType[value]
} else if (['giftType'].includes(column.property)) {
return giftType[value]
}
return value
}
const changeShowOver = () => {
showOverFlowToolTip.value = !showOverFlowToolTip.value
}
</script> </script>
<style scoped <style scoped
...@@ -418,6 +568,22 @@ const detailColumns = ref([ ...@@ -418,6 +568,22 @@ const detailColumns = ref([
::v-deep(.el-cascader) { ::v-deep(.el-cascader) {
width: 460px !important; width: 460px !important;
} }
}
.dialog-footer {
.el-row {
display: flex;
justify-content: flex-end;
align-items: center;
.semi-btn {
margin-right: 20px;
}
.pagination-container {
margin: 0 !important;
height: auto !important;
}
}
} }
</style> </style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论