|
|
@@ -1,7 +1,225 @@
|
|
|
<!-- 报表查询-商品交易报表 -->
|
|
|
<template>
|
|
|
- <app-view></app-view>
|
|
|
+ <app-view>
|
|
|
+ <template #header>
|
|
|
+ <app-filter :option="filterOption">
|
|
|
+ <template #reckondate="{ item }">
|
|
|
+ <el-form-item :label="item.label" prop="reckondate">
|
|
|
+ <el-date-picker :type="dateType" v-model="item.value" :format="dateFormat"
|
|
|
+ :value-format="dateFormat" placeholder="请选择" />
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ <template #quarter="{ item }">
|
|
|
+ <el-form-item :label="item.label" prop="quarter"
|
|
|
+ v-if="queryParams.cycletype === ReportType.Quarter">
|
|
|
+ <el-select v-model="item.value">
|
|
|
+ <el-option v-for="option in getQuarterList()" :key="option.value" :label="option.label"
|
|
|
+ :value="option.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <template v-else>
|
|
|
+ {{ (item.value = undefined) }}
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </app-filter>
|
|
|
+ </template>
|
|
|
+ <app-table :data="dataList" :columns="tableColumns" :loading="loading" :highlight-current-row="false"
|
|
|
+ :span-method="objectSpanMethod" :row-style="rowStyle">
|
|
|
+ <template #headerLeft>
|
|
|
+ <app-operation :data-list="getActionButtons(['report_goods_export'])"
|
|
|
+ @click="(code: string) => openComponent(code)" />
|
|
|
+ </template>
|
|
|
+ </app-table>
|
|
|
+ <component :is="componentMap.get(componentId)" v-bind="{ record, queryParams }" @closed="closeComponent"
|
|
|
+ v-if="componentId" />
|
|
|
+ </app-view>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
+import { shallowRef, computed } from 'vue'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import { formatDate, parsePercent, handleNumberValue } from '@/filters'
|
|
|
+import { useDataFilter } from '@/hooks/datatable-v2'
|
|
|
+import { useRequest } from '@/hooks/request'
|
|
|
+import { useOperation } from '@/hooks/operation'
|
|
|
+import { ReportType, getReportTypeList, getQuarterList } from '@/constants/report'
|
|
|
+import { dayGoodsCountReportQuery } from '@/services/api/report'
|
|
|
+import AppTable from '@pc/components/base/table/index.vue'
|
|
|
+import AppOperation from '@pc/components/base/operation/index.vue'
|
|
|
+import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
|
|
|
+
|
|
|
+const { componentMap, componentId, record, openComponent, closeComponent, getActionButtons } = useOperation<Model.DayGoodsCountReportRsp>({
|
|
|
+ onClose: () => onSearch()
|
|
|
+})
|
|
|
+
|
|
|
+const { data, loading, run } = useRequest(dayGoodsCountReportQuery, {
|
|
|
+ manual: true,
|
|
|
+ onError: (err) => {
|
|
|
+ ElMessage.error(err)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const dataList = computed<Model.DayGoodsCount[]>(() => {
|
|
|
+ if (data.value) {
|
|
|
+ const values: Model.DayGoodsCount[][] = Object.values(data.value)
|
|
|
+
|
|
|
+ values.forEach((arr) => {
|
|
|
+ const item = {
|
|
|
+ goodsname: '汇总',
|
|
|
+ holdaccountcount: 0,
|
|
|
+ marketid: 0,
|
|
|
+ marketname: '',
|
|
|
+ markettradeqty: 0,
|
|
|
+ orderaccountcount: 0,
|
|
|
+ totalcharge: 0,
|
|
|
+ totalholdqty: 0,
|
|
|
+ totalinterest: 0,
|
|
|
+ totalorderqty: 0,
|
|
|
+ tradeaccountcount: 0,
|
|
|
+ tradeamount: 0,
|
|
|
+ tradelot: 0,
|
|
|
+ tradeqty: arr.reduce((pre, cur) => pre + cur.tradeqty, 0)
|
|
|
+ }
|
|
|
+
|
|
|
+ arr.forEach((e) => {
|
|
|
+ e.markettradeqty = item.tradeqty ? e.tradeqty / item.tradeqty : 0
|
|
|
+
|
|
|
+ item.holdaccountcount += e.holdaccountcount
|
|
|
+ item.markettradeqty += e.markettradeqty
|
|
|
+ item.orderaccountcount += e.orderaccountcount
|
|
|
+ item.totalcharge += e.totalcharge
|
|
|
+ item.totalholdqty += e.totalholdqty
|
|
|
+ item.totalinterest += e.totalinterest
|
|
|
+ item.totalorderqty += e.totalorderqty
|
|
|
+ item.tradeaccountcount += e.tradeaccountcount
|
|
|
+ item.tradeamount += e.tradeamount
|
|
|
+ item.tradelot += e.tradelot
|
|
|
+ })
|
|
|
+
|
|
|
+ arr.push(item)
|
|
|
+ })
|
|
|
+
|
|
|
+ return values.flat()
|
|
|
+ }
|
|
|
+ return []
|
|
|
+})
|
|
|
+
|
|
|
+const tableColumns = shallowRef<Model.TableColumn[]>([
|
|
|
+ { field: 'marketname', label: '市场' },
|
|
|
+ { field: 'goodsname', label: '商品/代码' },
|
|
|
+ { field: 'totalorderqty', label: '总委托量' },
|
|
|
+ { field: 'tradeqty', label: '总成交量' },
|
|
|
+ { field: 'totalholdqty', label: '总持仓量' },
|
|
|
+ { field: 'tradelot', label: '总成交笔数' },
|
|
|
+ { field: 'tradeamount', label: '总成交金额', decimal: 2 },
|
|
|
+ { field: 'totalcharge', label: '总手续费', decimal: 2 },
|
|
|
+ { field: 'totalinterest', label: '总递延费', decimal: 2 },
|
|
|
+ { field: 'orderaccountcount', label: '委托账户数' },
|
|
|
+ { field: 'tradeaccountcount', label: '成交账户数' },
|
|
|
+ { field: 'holdaccountcount', label: '持仓账户数' },
|
|
|
+ { field: 'markettradeqty', label: '成交市场占比', formatValue: (val) => val ? parsePercent(val, 2, true) : handleNumberValue() }
|
|
|
+])
|
|
|
+
|
|
|
+// 日期类型
|
|
|
+const dateType = computed(() => {
|
|
|
+ switch (queryParams.value.cycletype) {
|
|
|
+ case ReportType.Week:
|
|
|
+ return 'week'
|
|
|
+ case ReportType.Month:
|
|
|
+ return 'month'
|
|
|
+ case ReportType.Quarter:
|
|
|
+ case ReportType.Year:
|
|
|
+ return 'year'
|
|
|
+ default:
|
|
|
+ return 'date'
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 日期格式
|
|
|
+const dateFormat = computed(() => {
|
|
|
+ switch (queryParams.value.cycletype) {
|
|
|
+ case ReportType.Month:
|
|
|
+ return 'YYYYMM'
|
|
|
+ case ReportType.Quarter:
|
|
|
+ case ReportType.Year:
|
|
|
+ return 'YYYY'
|
|
|
+ default:
|
|
|
+ return 'YYYYMMDD'
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 计算行合并值
|
|
|
+const rowSpanMap = computed(() => {
|
|
|
+ const arr: number[] = []
|
|
|
+ Object.values(data.value ?? {}).forEach((e, i) => {
|
|
|
+ if (i === 0) {
|
|
|
+ arr[0] = e.length
|
|
|
+ } else {
|
|
|
+ const n = arr.length - 1 // 获取数组最后的索引位置
|
|
|
+ const preRowSpan = arr[n] // 获取数组最后元素的值
|
|
|
+ arr[preRowSpan + n] = e.length // 计算出需要合并的第 n 行元素
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return arr
|
|
|
+})
|
|
|
+
|
|
|
+const objectSpanMethod = (data: { rowIndex: number; columnIndex: number; }) => {
|
|
|
+ if (data.columnIndex === 0) {
|
|
|
+ return {
|
|
|
+ rowspan: rowSpanMap.value[data.rowIndex] ?? 0,
|
|
|
+ colspan: 1,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 计算汇总样式
|
|
|
+const rowStyleMap = computed(() => {
|
|
|
+ const arr: boolean[] = []
|
|
|
+ Object.values(data.value ?? {}).forEach((e, i) => {
|
|
|
+ if (i === 0) {
|
|
|
+ arr[e.length - 1] = true
|
|
|
+ } else {
|
|
|
+ const n = arr.length - 1 // 获取数组最后的索引位置
|
|
|
+ arr[n + e.length] = true // 计算出需要样式的第 n 行元素
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return arr
|
|
|
+})
|
|
|
+
|
|
|
+const rowStyle = (data: { rowIndex: number; }) => {
|
|
|
+ if (rowStyleMap.value[data.rowIndex]) {
|
|
|
+ return 'background-color: #f0f9f3;'
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const { queryParams, filterOption, getQueryParams, resetFilters } = useDataFilter<Model.DayGoodsCountReportReq>({
|
|
|
+ filters: [
|
|
|
+ {
|
|
|
+ field: 'cycletype',
|
|
|
+ label: '报表类型',
|
|
|
+ value: 0,
|
|
|
+ options: () => getReportTypeList()
|
|
|
+ },
|
|
|
+ {
|
|
|
+ field: 'reckondate',
|
|
|
+ label: '日期',
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ field: 'quarter',
|
|
|
+ label: '季度',
|
|
|
+ required: true
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ buttons: [
|
|
|
+ { label: '查询', className: 'el-button--primary', onClick: () => onSearch() },
|
|
|
+ { label: '重置', className: 'el-button--primary', validateEvent: false, onClick: () => resetFilters() }
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+const onSearch = () => {
|
|
|
+ const qs = getQueryParams()
|
|
|
+ qs.reckondate = formatDate(qs.reckondate, dateFormat.value) // 处理日期格式
|
|
|
+ run(qs)
|
|
|
+}
|
|
|
</script>
|