li.shaoyi hace 11 meses
padre
commit
67bb8c8b2b

+ 4 - 4
src/filters/index.ts

@@ -213,12 +213,12 @@ export function formatDecimal(value: number | string, decimals = 2, round = true
  * @param value 
  * @param decimal 保留小数位
  */
-export function parsePercent(value = 0, decimal = 2) {
+export function parsePercent(value = 0, decimal = 2, round = false) {
     if (Number.isNaN(value)) {
         return '0%'
     }
     const num = new Decimal(value).times(100)
-    const res = formatDecimal(num.toNumber(), decimal, false)
+    const res = formatDecimal(num.toNumber(), decimal, round)
     return res + '%'
 }
 
@@ -227,11 +227,11 @@ export function parsePercent(value = 0, decimal = 2) {
  * @param value 
  * @param decimal 保留小数位
  */
-export function parseTenThousand(value = 0, decimal = 2) {
+export function parseTenThousand(value = 0, decimal = 2, round = false) {
     if (Number.isNaN(value)) {
         return '0‱'
     }
     const num = new Decimal(value).times(10000)
-    const res = formatDecimal(num.toNumber(), decimal, false)
+    const res = formatDecimal(num.toNumber(), decimal, round)
     return res + '‱'
 }

+ 3 - 1
src/packages/pc/views/investor/custom/tradecfg/components/edit/index.vue

@@ -105,6 +105,7 @@
 import { ref, PropType, computed, onMounted } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
 import { handleNoneValue } from '@/filters'
+import { getFeeAlgorithmName } from '@/constants/order'
 import { useEnum } from '@/hooks/enum'
 import { useRequest } from '@/hooks/request'
 import { traderPersonAdd, getInvestorTree, initInvestorPerson } from '@/services/api/investor'
@@ -184,7 +185,7 @@ const ruleColumns = computed<Model.TableColumn[]>(() => [
 
 const feeColumns = computed<Model.TableColumn[]>(() => [
     { field: 'tradefeename', label: 'investor.custom.tradecfg.edit.tradefeename' },
-    { field: 'feealgorithm', label: 'investor.custom.tradecfg.edit.feealgorithm', formatValue: (val) => val === 1 ? t('investor.custom.tradecfg.edit.feealgorithm1') : t('investor.custom.tradecfg.edit.feealgorithm2') },
+    { field: 'feealgorithm', label: 'investor.custom.tradecfg.edit.feealgorithm', formatValue: (val) => getFeeAlgorithmName(val) },
     { field: 'exchangevalue', label: 'investor.custom.tradecfg.edit.exchangevalue' },
     { field: 'dvalue', label: 'investor.custom.tradecfg.edit.dvalue', show: formData.value.usergroupid !== 0 },
     { field: 'memberminvalue', label: 'investor.custom.tradecfg.edit.memberminvalue' },
@@ -266,6 +267,7 @@ const onCancel = (isRefresh = false) => {
 onMounted(() => {
     const record = props.record
     if (record) {
+        console.log(record)
         // formData.value = {
         //     accountid: record.accountid,
         //     customertype: record.customertype,

+ 2 - 1
src/packages/pc/views/investor/custom/tradecfg/index.vue

@@ -107,6 +107,7 @@
 import { shallowRef, computed, nextTick, toRaw } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
 import { parseTenThousand, handleNoneValue } from '@/filters'
+import { getFeeAlgorithmName } from '@/constants/order'
 import { useEnum } from '@/hooks/enum'
 import { useRequest } from '@/hooks/request'
 import { useOperation } from '@/hooks/operation'
@@ -180,7 +181,7 @@ const ruleColumns = computed<Model.TableColumn[]>(() => [
 
 const feeColumns = computed<Model.TableColumn[]>(() => [
     { field: 'tradefeename', label: 'investor.custom.tradecfg.tradefeename' },
-    { field: 'feealgorithm', label: 'investor.custom.tradecfg.feealgorithm', formatValue: (val) => val === 1 ? '比率' : '固定值' },
+    { field: 'feealgorithm', label: 'investor.custom.tradecfg.feealgorithm', formatValue: (val) => getFeeAlgorithmName(val) },
     { field: 'exchangevalue', label: 'investor.custom.tradecfg.exchangevalue' },
     { field: 'dvalue', label: 'investor.custom.tradecfg.dvalue', show: qs.value.usergroupid !== 0 },
     { field: 'cvalue', label: 'investor.custom.tradecfg.cvalue' },

+ 219 - 1
src/packages/pc/views/report/goods/index.vue

@@ -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>

+ 10 - 8
src/packages/pc/views/report/institution/index.vue

@@ -2,11 +2,13 @@
 <template>
     <app-view>
         <template #header>
-            <app-filter :option="filterOption"  :rules="filterRules">
+            <app-filter :option="filterOption" :rules="filterRules">
                 <template #reckondate>
                     <el-form-item :label="t('report.investor.reckondate')" prop="reckondate">
-                        <el-date-picker :type="dateType" v-model="dateValue" :format="dateFormat" :value-format="dateFormat"
-                        :placeholder="t('common.pleasechoice')" :start-placeholder="t('common.start')" :end-placeholder="t('common.end')" @change="onDateChange" />
+                        <el-date-picker :type="dateType" v-model="dateValue" :format="dateFormat"
+                            :value-format="dateFormat" :placeholder="t('common.pleasechoice')"
+                            :start-placeholder="t('common.start')" :end-placeholder="t('common.end')"
+                            @change="onDateChange" />
                     </el-form-item>
                 </template>
                 <template #quarter="{ item }">
@@ -35,14 +37,14 @@
                 </template>
                 <template #inamount>
                     <el-form-item :label="t('report.investor.inamount')" prop="inamount">
-                        <el-input-number v-model="queryParams.inamount" :min="0" controls-position="right"
-                            :placeholder="t('report.investor.tips1')" style="width: 240px;" />
+                        <el-input-number v-model="queryParams.inamount" :min="0"
+                            :placeholder="t('report.investor.tips1')" />
                     </el-form-item>
                 </template>
                 <template #outamount>
                     <el-form-item :label="t('report.investor.outamount')" prop="outamount">
-                        <el-input-number v-model="queryParams.outamount" :min="0" controls-position="right"
-                            :placeholder="t('report.investor.tips1')" style="width: 240px;" />
+                        <el-input-number v-model="queryParams.outamount" :min="0"
+                            :placeholder="t('report.investor.tips1')" />
                     </el-form-item>
                 </template>
                 <template #roles>
@@ -200,7 +202,7 @@ const filterRules: FormRules = {
 
 const { queryParams, filterOption, getQueryParams, resetFilters } = useDataFilter<Model.InvestorReportReq>({
     filters: [
-       {
+        {
             field: 'cycletype',
             label: '报表类型',
             required: true,

+ 14 - 0
src/services/api/member/index.ts

@@ -104,4 +104,18 @@ export function organSonRecover(options: CommonFetchOptions<{ request: Model.org
  */
 export function organSonViewson(options: CommonFetchOptions<{ request: Model.organSonViewsonReq; response: Model.organSonViewsonRsp; }>) {
     return httpClient.commonRequest('/organSon/viewson', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->获取机构资料列表
+ */
+export function queryOrganDetailList(options: CommonFetchOptions<{ request: Model.OrganDetailListReq; response: Model.OrganDetailRsp[]; }>) {
+    return httpClient.commonRequest('/organDetail/query', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->获取机构资料详情信息
+ */
+export function queryOrganDetail(options: CommonFetchOptions<{ request: Model.OrganDetailReq; response: Model.OrganDetailRsp[]; }>) {
+    return httpClient.commonRequest('/organDetail/queryDetail', 'get', options)
 }

+ 72 - 0
src/types/model/member.d.ts

@@ -377,4 +377,76 @@ declare namespace Model {
         userinfoType: number; // userinfo – 用户类型
         wechat: string; // userinfo – 微信
     }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->获取机构资料列表 请求 */
+    interface OrganDetailListReq {
+        accountName?: string; // 机构
+        accountStatus?: number; // 机构状态
+        memberuserid?: number; // 一级机构代码
+        pageNum: number;
+        pageSize: number;
+        parentuserid?: number;
+        usertype?: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->获取机构资料详情信息 请求 */
+    interface OrganDetailReq {
+        areaId: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->获取机构资料详情信息 响应 */
+    interface OrganDetailRsp {
+        accountname: string; // 账户名称(机构名称)
+        accountstatus: number; // code areastatus 账户状态 - 1:待激活 2:待审核 3:待复审 4:正常 5:审核拒绝 6:停用(注销) 7:注销(删除)
+        applysrc: number; // 申请来源 - 1:管理端 2:终端
+        auditremark: string; // 审核备注
+        auditsrc: number; // 审核来源 - 1:管理端 2:终端
+        audittime: string; // 审核时间
+        audituserid: number; // 审核人
+        broker: number; // 所属经纪人ID(所属客户经理-千海金)
+        canceltime: string; // 销户时间
+        canceluserid: number; // 销户人
+        cancrossadd: number;
+        canrecommend: number; // 是否可推荐 - 0:不可 1;可 (是否推荐人)
+        contactname: string; // 联系人
+        createtime: string; // 创建时间
+        createtradedate: string; // 创建交易日(yyyyMMdd)
+        creatorid: number; // 创建人
+        creditquota: number; // 授信额度(金瑞)分拣室服务费(广钻)
+        curuserid: number;
+        hasauth: number; // 是否已实名认证 - 0:未认证 1:已认证 2:已提交(待审核) 3:已拒绝
+        hasuploaded: number; // 是否已同步(千海金) 0:未同步 1;已同步
+        isanonymous: number; // 是否匿名下单 - 0:否 1:是
+        maxLevel: number; // 子机构最大层级数
+        maxinvestornum: number; // 最大用户数(经纪会员下投资者个数)
+        memberuserid: number; // 所属会员ID
+        modifierid: number; // 修改人
+        modifyremark: string; // 变更备注
+        modifysrc: number; // 修改来源 - 1:管理端 2:终端
+        modifystatus: number; // 变更状态 1 未变更 2 变更中 3 变更待审核 4 变更待复核(投资者)
+        modifytime: string; // 修改时间
+        outeruserid: string; // 外部用户ID(千海金-外部门店ID)
+        parentid: number;
+        parenttopuser: string; // 上级顶级机构 [092=0,1时,默认为1, 092=2时若自已为顶级,则填入自己,自己不为顶级,填入ParentUserID的ParentTopUser]
+        parentuserid: number; // 所属机构ID
+        pathname: string; // 地址
+        reckonaccountid: number; // 默认结算资金账号ID(机构分润使用) 作废
+        refercount: number; // 推荐总人数
+        refereeuserid: number; // 推荐人ID
+        refernum: string; // 推荐码
+        roleIds: string;
+        rootuserid: number; // 根用户ID
+        secrefercount: number; // 间接推荐总人数
+        sjaccountno: string; // 送检账户(广钻)
+        subaccountlevel: number; // 子账户层数
+        subarealevel: number;
+        subarealevelpath: string; // 子机构层级路径(逗号分隔,首尾加逗号)
+        subjectid: number; // 所属部门(业务部门)
+        teammanageruserid: number; // 团队经理用户ID(千海金:门店代理)
+        uploadedtime: string; // 同步时间
+        userName: string;
+        userid: number; // 用户ID
+        userinfotype: number; // 所有者类型
+        usertype: number; // 账户类型 - 1:交易所 2:机构 3:会员子机构 4:经纪人 5:投资者 6:客户 7:企业成员(云平台)
+    }
 }