li.shaoyi 1 gadu atpakaļ
vecāks
revīzija
1d0c6f1ef5
34 mainītis faili ar 1782 papildinājumiem un 379 dzēšanām
  1. 0 17
      src/business/admin/index.ts
  2. 0 0
      src/packages/pc/assets/themes/base/iconfont.less
  3. 6 0
      src/packages/pc/assets/themes/default/variable.less
  4. 1 0
      src/packages/pc/assets/themes/global/global.less
  5. 23 19
      src/packages/pc/components/layouts/header/index.less
  6. 23 6
      src/packages/pc/components/layouts/header/index.vue
  7. 0 8
      src/packages/pc/views/home/main/index.vue
  8. 6 0
      src/packages/pc/views/investor/custom/tradecfg/index.vue
  9. 52 0
      src/packages/pc/views/investor/manage/user/components/account/details/index.vue
  10. 91 0
      src/packages/pc/views/investor/manage/user/components/account/edit/index.vue
  11. 111 0
      src/packages/pc/views/investor/manage/user/components/account/index.vue
  12. 50 0
      src/packages/pc/views/investor/manage/user/components/cancel/index.vue
  13. 122 0
      src/packages/pc/views/investor/manage/user/components/config/index.vue
  14. 50 0
      src/packages/pc/views/investor/manage/user/components/delete/index.vue
  15. 289 0
      src/packages/pc/views/investor/manage/user/components/edit/index.vue
  16. 50 0
      src/packages/pc/views/investor/manage/user/components/login/delete/index.vue
  17. 53 0
      src/packages/pc/views/investor/manage/user/components/login/details/index.vue
  18. 128 0
      src/packages/pc/views/investor/manage/user/components/login/index.vue
  19. 53 0
      src/packages/pc/views/investor/manage/user/components/login/lock/index.vue
  20. 62 0
      src/packages/pc/views/investor/manage/user/components/login/log/index.vue
  21. 50 0
      src/packages/pc/views/investor/manage/user/components/login/password/index.vue
  22. 50 0
      src/packages/pc/views/investor/manage/user/components/login/recover/index.vue
  23. 50 0
      src/packages/pc/views/investor/manage/user/components/recover/index.vue
  24. 14 3
      src/packages/pc/views/investor/manage/user/index.vue
  25. 1 1
      src/packages/pc/views/report/account/index.vue
  26. 66 104
      src/packages/pc/views/report/broker/index.vue
  27. 72 97
      src/packages/pc/views/report/investor/index.vue
  28. 24 24
      src/packages/pc/views/report/profitshare/index.vue
  29. 34 52
      src/packages/pc/views/report/trade/index.vue
  30. 79 2
      src/services/api/investor/index.ts
  31. 10 2
      src/services/api/report/index.ts
  32. 129 13
      src/types/model/investor.d.ts
  33. 31 31
      src/types/model/report.d.ts
  34. 2 0
      src/types/model/user.d.ts

+ 0 - 17
src/business/admin/index.ts

@@ -1,17 +0,0 @@
-import { reactive } from 'vue'
-
-export function useAdmin() {
-    const admin = reactive({
-        avatar: '',
-        realName: '',
-    })
-
-    const logout = () => {
-        console.log('退出')
-    }
-
-    return {
-        admin,
-        logout
-    }
-}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/packages/pc/assets/themes/base/iconfont.less


+ 6 - 0
src/packages/pc/assets/themes/default/variable.less

@@ -62,6 +62,12 @@
             width: 180px;
         }
 
+        .el-input-number {
+            .el-input {
+                width: inherit;
+            }
+        }
+
         .el-range-editor {
             width: 300px;
         }

+ 1 - 0
src/packages/pc/assets/themes/global/global.less

@@ -78,4 +78,5 @@
 
 .g-text-message {
     font-size: 16px;
+    line-height: normal;
 }

+ 23 - 19
src/packages/pc/components/layouts/header/index.less

@@ -19,34 +19,38 @@
         display: flex;
         align-items: center;
 
-        .iconbar {
-            display: flex;
-            align-items: center;
-            gap: 20px;
+        [class^='g-icon'] {
+            cursor: pointer;
 
-            [class^='g-icon'] {
-                cursor: pointer;
+            &:before {
+                font-size: 22px;
+            }
+        }
 
-                &:before {
-                    font-size: 22px;
-                }
+        .g-icon {
+            &--notice::before {
+                content: var(--icon-notice);
             }
 
-            .g-icon {
-                &--notice::before {
-                    content: var(--icon-notice);
-                }
+            &--minimize::before {
+                content: var(--icon-minimize);
+            }
 
-                &--minimize::before {
-                    content: var(--icon-minimize);
-                }
+            &--maximize::before {
+                content: var(--icon-maximize);
+            }
 
-                &--maximize::before {
-                    content: var(--icon-maximize);
-                }
+            &--language::before {
+                content: var(--icon-language);
             }
         }
 
+        .iconbar {
+            display: flex;
+            align-items: center;
+            gap: 20px;
+        }
+
         .user-dropdown {
             margin-left: 20px;
 

+ 23 - 6
src/packages/pc/components/layouts/header/index.vue

@@ -21,9 +21,19 @@
                 <span class="g-icon--maximize" @click="setFullSreen" v-else></span>
             </div>
             <el-dropdown class="user-dropdown" trigger="click">
+                <span class="g-icon--language"></span>
+                <template #dropdown>
+                    <el-dropdown-menu>
+                        <template v-for="item in getLanguageList()" :key="item.value">
+                            <el-dropdown-item @click="switchLanguage(item.value)">{{ item.label }}</el-dropdown-item>
+                        </template>
+                    </el-dropdown-menu>
+                </template>
+            </el-dropdown>
+            <el-dropdown class="user-dropdown" trigger="click">
                 <span class="user-dropdown__link">
-                    <img class="g-image--avatar" :src="admin.avatar" :title="admin.realName" />
-                    <span v-if="!globalStore.isMobile">{{ admin.realName }}</span>
+                    <span>{{ userStore.userInfo.username }}</span>
+                    <span>({{ userStore.userInfo.logincode }})</span>
                     <el-icon class="el-icon--right">
                         <arrow-down />
                     </el-icon>
@@ -42,13 +52,14 @@
 <script lang="ts" setup>
 import { ref, onMounted } from 'vue'
 import { ArrowRight, Key, SwitchButton, ArrowDown } from '@element-plus/icons-vue'
-import { useGlobalStore } from '@/stores'
-import { useAdmin } from '@/business/admin'
+import { getLanguageList, Language } from '@/constants/language'
+import { useGlobalStore, useUserStore, i18n } from '@/stores'
+import { localData } from '@/stores/storage'
 import eventBus from '@/services/bus'
 
-const { admin } = useAdmin();
 const globalStore = useGlobalStore()
-const fullScreen = ref(false);
+const userStore = useUserStore()
+const fullScreen = ref(false)
 
 // 全屏
 const setFullSreen = () => {
@@ -60,6 +71,12 @@ const exitFullSreen = () => {
     document.exitFullscreen();
 }
 
+// 切换语言
+const switchLanguage = (lange: Language) => {
+    i18n.global.locale = lange
+    localData.setValue('appLanguage', lange)
+}
+
 onMounted(() => {
     // 监听全屏变化
     window.addEventListener('fullscreenchange', () => {

+ 0 - 8
src/packages/pc/views/home/main/index.vue

@@ -1,8 +0,0 @@
-<template>
-    <app-view class="home-main">
-        首页
-    </app-view>
-</template>
-
-<script lang="ts" setup>
-</script>

+ 6 - 0
src/packages/pc/views/investor/custom/tradecfg/index.vue

@@ -38,6 +38,9 @@
         <template v-if="data">
             <app-table-details title="基本信息" :data="data" :label-width="160" :cell-props="detailProps" :column="3" />
             <app-table :data="data.druleList" :columns="ruleColumns">
+                <template #headerLeft>
+                    <b>交易规则</b>
+                </template>
                 <!-- 商品设置值 -->
                 <template #paramvalue="{ row }">
                     <span v-if="row.ruleid === 105">{{ feetypeEnum.getEnumTypeName(row.paramvalue) }}</span>
@@ -59,6 +62,9 @@
                 </template>
             </app-table>
             <app-table :data="data.dfeeList" :columns="feeColumns">
+                <template #headerLeft>
+                    <b>交易服务费</b>
+                </template>
                 <!-- 商品设置值 -->
                 <template #exchangevalue="{ row }">
                     <template v-if="row.feealgorithm">

+ 52 - 0
src/packages/pc/views/investor/manage/user/components/account/details/index.vue

@@ -0,0 +1,52 @@
+<!-- 交易商管理-交易商管理-交易商管理-资金账户-详情 -->
+<template>
+    <app-drawer title="详情" width="900" v-model:show="show" :refresh="refresh">
+        <app-table-details :data="selectedItem" :label-width="140" :cell-props="detailProps" :column="2" />
+        <template #footer>
+            <el-button @click="onCancel(false)">关闭</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { useEnum } from '@/hooks/enum'
+import { CellProp } from '@pc/components/base/table-details/types'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.ShowAccountRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+
+const mainaccounttypeEnum = useEnum('mainaccounttype') // 账户类型
+const tradestatusEnum = useEnum('traderstatus') // 交易状态
+const flagEnum = useEnum('flag') // 变动标志
+
+const detailProps: CellProp[] = [
+    { prop: 'accountid', label: '账户编号:' },
+    { prop: 'accountname', label: '所属交易商:' },
+    { prop: 'ismain', label: '是否母账户:', formatValue: (val) => mainaccounttypeEnum.getEnumTypeName(val) },
+    { prop: 'parentaccountid', label: '所属母账户:', show: props.selectedItem.ismain === 0 },
+    { prop: 'relateduserid', label: '关联用户:' },
+    { prop: 'changeflag', label: '变动标志:', formatValue: (val) => flagEnum.getEnumTypeName(val) },
+    { prop: 'tradestatus', label: '交易状态:', formatValue: (val) => tradestatusEnum.getEnumTypeName(val) },
+    { prop: 'currentbalance', label: '期末余额:' },
+    { prop: 'freezemargin', label: '冻结保证金:' },
+    { prop: 'usedmargin', label: '占用保证金:' },
+    { prop: 'freezecharge', label: '服务费冻结:' },
+    { prop: 'outamountfreeze', label: '出金冻结:' },
+    { prop: 'outthreshold', label: '出金阈值:' },
+]
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+</script>

+ 91 - 0
src/packages/pc/views/investor/manage/user/components/account/edit/index.vue

@@ -0,0 +1,91 @@
+<!-- 交易商管理-交易商管理-交易商管理-资金账户-编辑 -->
+<template>
+    <app-drawer title="编辑" width="480" v-model:show="show" :refresh="refresh" :loading="loading">
+        <el-form ref="formRef" class="el-form--vertical" label-width="100px" :model="formData" :rules="formRules"
+            :show-message="false">
+            <el-form-item label="资金账户">
+                {{ selectedItem.accountid }}
+            </el-form-item>
+            <el-form-item label="交易状态" prop="tradestatus">
+                <el-select v-model="formData.tradestatus">
+                    <el-option v-for="item in tradestatusEnum.getEnumOptions([1, 4, 5])" :key="item.value"
+                        :label="item.label" :value="item.value" />
+                </el-select>
+            </el-form-item>
+            <el-form-item label="内外部">
+                {{ accounttypeEnum.getEnumTypeName(selectedItem.taaccounttype) }}
+            </el-form-item>
+            <el-form-item label="币种">
+                {{ currencyEnum.getEnumTypeName(selectedItem.currencyid) }}
+            </el-form-item>
+            <el-form-item label="出金阈值" prop="outthreshold">
+                <el-input-number v-model="formData.outthreshold" placeholder="请输入" :min="0" />
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType, toRaw } from 'vue'
+import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { useEnum } from '@/hooks/enum'
+import { investorAccountEdit } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.ShowAccountRsp>,
+        required: true
+    }
+})
+
+const accounttypeEnum = useEnum('accounttype') // 内/外部
+const tradestatusEnum = useEnum('traderstatus') // 交易状态
+const currencyEnum = useEnum('currency') // 币种
+
+const formRef = ref<FormInstance>()
+const show = ref(true)
+const refresh = ref(false)
+const loading = ref(false)
+
+const formData = ref<Model.InvestorAccountEditReq>({
+    accountid: props.selectedItem.accountid,
+    outthreshold: props.selectedItem.outthreshold,
+    parentaccountid: props.selectedItem.parentaccountid,
+    tradestatus: props.selectedItem.tradestatus
+})
+
+// 表单验证规则
+const formRules: FormRules = {
+    tradestatus: [{ required: true }],
+    outthreshold: [{ required: true }],
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            const rawData = toRaw(formData.value)
+            loading.value = true
+            investorAccountEdit({
+                data: rawData
+            }).then(() => {
+                ElMessage.success('保存成功')
+                onCancel(true)
+            }).catch((err) => {
+                ElMessage.error('保存失败:' + err)
+            }).finally(() => {
+                loading.value = false
+            })
+        }
+    })
+}
+</script>

+ 111 - 0
src/packages/pc/views/investor/manage/user/components/account/index.vue

@@ -0,0 +1,111 @@
+<!-- 交易商管理-交易商管理-交易商管理-资金账户 -->
+<template>
+    <teleport to="#appPageTeleport">
+        <app-view>
+            <template #header>
+                <app-filter :option="filterOption" />
+            </template>
+            <app-table :data="dataList" :columns="tableColumns">
+                <template #headerLeft>
+                    <span>[{{ record.accountName }}]的资金账户</span>
+                </template>
+                <template #headerRight>
+                    <div style="display: flex;">
+                        <el-button @click="emit('closed')">关闭</el-button>
+                    </div>
+                </template>
+                <!-- 操作 -->
+                <template #operate="{ row }">
+                    <el-button size="small" icon="Search" @click="showComponent('Details', row)" circle plain />
+                    <el-button size="small" icon="Edit" @click="showComponent('Edit', row)" circle plain />
+                </template>
+                <template #footer>
+                    <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                        @change="onSearch" />
+                </template>
+            </app-table>
+            <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ selectedItem }"
+                @closed="closeComponent" v-if="componentId" />
+        </app-view>
+    </teleport>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType, defineAsyncComponent } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useEnum } from '@/hooks/enum'
+import { useDataFilter } from '@/hooks/datatable-v2'
+import { useComponent } from '@/hooks/component'
+import { useRequest } from '@/hooks/request'
+import { showAccount } from '@/services/api/investor'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.InvestorListRsp>,
+        required: true
+    }
+})
+
+const componentMap = new Map<string, unknown>([
+    ['Details', defineAsyncComponent(() => import('./details/index.vue'))], // 详情
+    ['Edit', defineAsyncComponent(() => import('./edit/index.vue'))], // 修改
+])
+
+const emit = defineEmits(['closed'])
+const selectedItem = ref<Model.ShowAccountRsp>()
+
+const accounttypeEnum = useEnum('accounttype') // 内/外部
+const tradestatusEnum = useEnum('traderstatus') // 交易状态
+const currencyEnum = useEnum('currency') // 币种
+
+const { filterOption, getQueryParams, resetFilters } = useDataFilter<Model.ShowAccountReq>()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => run())
+
+const { dataList, total, pageSize, pageIndex, run } = useRequest(showAccount, {
+    params: {
+        pageNum: 1,
+        pageSize: 20,
+        userid: props.record.userId,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = ref<Model.TableColumn[]>([
+    { field: 'accountid', label: '资金账户' },
+    { field: 'taaccounttype', label: '内/外部', formatValue: (val) => accounttypeEnum.getEnumTypeName(val) },
+    { field: 'relateduserid', label: '关联账户' },
+    { field: 'tradestatus', label: '交易状态', formatValue: (val) => tradestatusEnum.getEnumTypeName(val) },
+    { field: 'currencyid', label: '币种', formatValue: (val) => currencyEnum.getEnumTypeName(val) },
+    { field: 'cur_risk_rate', label: '风险率(%)' },
+    { field: 'operate', label: '操作', fixed: 'right' }
+])
+
+filterOption.items = [
+    {
+        key: 'accountid',
+        label: '资金账户',
+        placeholder: '请输入资金账户ID'
+    },
+]
+
+filterOption.buttons = [
+    { label: '查询', className: 'el-button--primary', validateEvent: true, onClick: () => onSearch() },
+    { label: '重置', className: 'el-button--primary', onClick: () => resetFilters() }
+]
+
+const onSearch = (clear = false) => {
+    const qs = getQueryParams(clear)
+    run(qs)
+}
+
+const showComponent = (code: string, row?: Model.ShowAccountRsp) => {
+    selectedItem.value = row
+    openComponent(code)
+}
+</script>

+ 50 - 0
src/packages/pc/views/investor/manage/user/components/cancel/index.vue

@@ -0,0 +1,50 @@
+<!-- 交交易商管理-交易商管理-交易商管理-撤回 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">确认撤回变更?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { investorRebackChange } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.InvestorListRsp>,
+        required: true
+    }
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    investorRebackChange({
+        data: {
+            areaid: props.record.userId
+        }
+    }).then(() => {
+        ElMessage.success('撤回成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('撤回失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 122 - 0
src/packages/pc/views/investor/manage/user/components/config/index.vue

@@ -0,0 +1,122 @@
+<!-- 交易商管理-交易商管理-交易商管理-查询个性化设置 -->
+<template>
+    <app-drawer :title="`会员/交易商:${record.accountName}`" width="900" v-model:show="show" :loading="loading" :refresh="refresh">
+        <app-filter :option="filterOption" />
+        <template v-if="data">
+            <app-table-details title="保证金" :data="data" :label-width="160" :cell-props="detailProps" :column="3" />
+            <app-table :data="data.extendRule" :columns="ruleColumns">
+                <template #headerLeft>
+                    <b>交易规则</b>
+                </template>
+                <!-- 值 -->
+                <template #paramvalue="{ row }">
+                    <span v-if="row.ruleid === 105">{{ feetypeEnum.getEnumTypeName(row.paramvalue) }}</span>
+                    <span v-else-if="[107, 108, 110, 1111].includes(row.ruleid)">{{ row.paramvalue * 100 }}</span>
+                    <span v-else>{{ row.paramvalue || 0 }}</span>
+                </template>
+            </app-table>
+            <app-table :data="data.extendFee" :columns="feeColumns">
+                <template #headerLeft>
+                    <b>交易费用</b>
+                </template>
+            </app-table>
+        </template>
+        <template #footer>
+            <el-button @click="onCancel(false)">关闭</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType, computed } from 'vue'
+import { parsePercent } from '@/filters'
+import { useEnum } from '@/hooks/enum'
+import { showAccount, accountQuery } from '@/services/api/investor'
+import { useRequest } from '@/hooks/request'
+import { CellProp } from '@pc/components/base/table-details/types'
+import { useDataFilter } from '@/hooks/datatable-v2'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.InvestorListRsp>,
+        required: true
+    }
+})
+
+const show = ref(true)
+const refresh = ref(false)
+
+const feetypeEnum = useEnum('feetype')
+
+const { filterOption, getQueryParams, resetFilters } = useDataFilter<Model.AccountQueryReq>()
+
+const { dataList } = useRequest(showAccount, {
+    params: {
+        userid: props.record.userId,
+    }
+})
+
+const { data, loading, run } = useRequest(accountQuery, {
+    manual: true
+})
+
+const detailProps = computed<CellProp[]>(() => {
+    const { tradeProperty } = data.value ?? {}
+    return [
+        { prop: 'marginalgorithm', label: '保证金计算方式:', formatValue: (val) => val === 1 ? '比率' : '固定值' },
+        { prop: 'deposit', label: '定金:', formatValue: () => '100%', show: tradeProperty === 2 },
+        { prop: 'marketmarginvalue', label: '即市保证金:', formatValue: (val) => parsePercent(val), show: tradeProperty === 1 },
+        { prop: 'reckonmarginvalue', label: '结算保证金值:', formatValue: (val) => parsePercent(val), show: tradeProperty === 1 },
+        { prop: 'lockmarginvalue', label: '锁仓保证金', formatValue: (val) => parsePercent(val), show: tradeProperty === 3 },
+    ]
+})
+
+const ruleColumns = computed<Model.TableColumn[]>(() => [
+    { field: 'rulename', label: '扩展项' },
+    { field: 'paramvalue', label: '值' },
+])
+
+const feeColumns = computed<Model.TableColumn[]>(() => [
+    { field: 'feename', label: '费用项' },
+    { field: 'feealgorithm', label: '费用算法', formatValue: (val) => val === 1 ? '比率(‱)' : '固定值' },
+    { field: 'exchangevalue', label: '平台设置值' },
+    { field: 'memberdefaultvalue', label: '会员设置值' },
+])
+
+filterOption.items = [
+    {
+        key: 'accountid',
+        label: '资金账户',
+        options: () => dataList.value.map((e) => ({
+            label: e.accountid.toString(),
+            value: e.accountid
+        })),
+        required: true
+    },
+    {
+        key: 'goodsid',
+        label: '商品',
+        placeholder: '请输入商品ID',
+        required: true
+    },
+]
+
+filterOption.buttons = [
+    { label: '查询', className: 'el-button--primary', validateEvent: true, onClick: () => onSearch() },
+    { label: '重置', className: 'el-button--primary', onClick: () => resetFilters() }
+]
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSearch = () => {
+    const qs = getQueryParams()
+    run(qs)
+}
+</script>

+ 50 - 0
src/packages/pc/views/investor/manage/user/components/delete/index.vue

@@ -0,0 +1,50 @@
+<!-- 交交易商管理-交易商管理-交易商管理-注销 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">确认注销该交易商?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { investorLogOff } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.InvestorListRsp>,
+        required: true
+    }
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    investorLogOff({
+        data: {
+            areaid: props.record.userId
+        }
+    }).then(() => {
+        ElMessage.success('注销成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('注销失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 289 - 0
src/packages/pc/views/investor/manage/user/components/edit/index.vue

@@ -0,0 +1,289 @@
+<!-- 交易商管理-交易商管理-交易商管理-编辑 -->
+<template>
+    <app-drawer title="编辑" width="900" v-model:show="show" :refresh="refresh" :loading="loading">
+        <el-form ref="formRef" class="el-form--horizontal" label-width="140px" :model="formData.userinfoDetailVo"
+            :rules="formRules" :show-message="false">
+            <fieldset class="g-fieldset el-form--horizontal">
+                <legend class="g-fieldset__legend">基本信息</legend>
+                <el-form-item label="交易商代码" prop="userId">
+                    {{ formData.userAccountDetailVo.userId }}
+                </el-form-item>
+                <el-form-item label="交易商名称" prop="accountName">
+                    <el-input v-model="formData.userAccountDetailVo.accountName" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="所属会员" prop="memberUserName">
+                    {{ formData.userAccountDetailVo.memberUserName }}
+                </el-form-item>
+                <el-form-item label="所属机构" prop="parentuserid">
+                    <app-select-member v-model="formData.userAccountDetailVo.parentuserid" usertype="3"
+                        placeholder="代码或名称模糊匹配" />
+                </el-form-item>
+                <el-form-item label="推荐人" prop="refereeUserName">
+                    {{ handleNoneValue(formData.userAccountDetailVo.refereeUserName) }}
+                </el-form-item>
+                <el-form-item label="是否认证" prop="isAuth">
+                    <el-radio-group v-model="formData.userAccountDetailVo.isAuth">
+                        <template v-for="item in getUserInfoTypeList()" :key="item.value">
+                            <el-radio :label="item.label" :value="item.value" />
+                        </template>
+                    </el-radio-group>
+                </el-form-item>
+            </fieldset>
+            <fieldset class="g-fieldset el-form--horizontal">
+                <legend class="g-fieldset__legend">{{ isPerson ? '个人' : '企业' }}资料</legend>
+                <el-form-item label="证件类型" prop="cardTypeId">
+                    <app-enum code="certypeperson" v-model="formData.userinfoDetailVo.cardTypeId" v-if="isPerson" />
+                    <app-enum code="certypecompany" v-model="formData.userinfoDetailVo.cardTypeId" v-else />
+                </el-form-item>
+                <el-form-item label="证件号码" prop="cardNum">
+                    <el-input v-model="formData.userinfoDetailVo.cardNum" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <template v-if="!isPerson">
+                    <el-form-item label="企业名称" prop="customerName">
+                        <el-input v-model="formData.userinfoDetailVo.customerName" maxlength="50" placeholder="请输入" />
+                    </el-form-item>
+                    <el-form-item label="企业性质" prop="bizNature" v-if="!isPerson">
+                        <app-enum code="biznature" v-model="formData.userinfoDetailVo.bizNature" :empty-values="[0]" />
+                    </el-form-item>
+                    <el-form-item label="法人姓名" prop="legalPersonName">
+                        <el-input v-model="formData.userinfoDetailVo.legalPersonName" maxlength="50"
+                            placeholder="请输入" />
+                    </el-form-item>
+                    <el-form-item label="联系人" prop="contactName">
+                        <el-input v-model="formData.userinfoDetailVo.contactName" maxlength="50" placeholder="请输入" />
+                    </el-form-item>
+                </template>
+                <el-form-item label="性别" prop="sex">
+                    <el-radio-group v-model="formData.userinfoDetailVo.sex">
+                        <template v-for="item in getGenderList()" :key="item.value">
+                            <el-radio :label="item.label" :value="item.value" />
+                        </template>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item label="所属公司" prop="company" v-if="isPerson">
+                    <el-input v-model="formData.userinfoDetailVo.company" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="手机号" prop="mobile">
+                    <el-input type="number" v-model="formData.userinfoDetailVo.mobile" maxlength="50"
+                        placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="联系电话" prop="telPhone">
+                    <el-input type="number" v-model="formData.userinfoDetailVo.telPhone" maxlength="50"
+                        placeholder="请输入" />
+                </el-form-item>
+                <el-form-item class="el-form-item--row" label="地区" prop="region">
+                    <app-region class="el-form-item--col" v-model:province="formData.userinfoDetailVo.provinceid"
+                        v-model:city="formData.userinfoDetailVo.cityid"
+                        v-model:district="formData.userinfoDetailVo.districtid" />
+                </el-form-item>
+                <el-form-item class="el-form-item--row" label="地址" prop="address">
+                    <el-input v-model="formData.userinfoDetailVo.address" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="邮政编码" prop="postalCode">
+                    <el-input v-model="formData.userinfoDetailVo.postalCode" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="邮箱" prop="email">
+                    <el-input v-model="formData.userinfoDetailVo.email" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item class="el-form-item--row" label="微信" prop="wechat">
+                    <el-input v-model="formData.userinfoDetailVo.wechat" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <template v-if="isPerson">
+                    <el-form-item label="证件照正面" prop="cardFrontPhotoUrl">
+                        <app-upload v-model="uploadFiles.cardFrontPhotoUrl" :file-types="['image']"
+                            type-message="请选择正确的图片类型" />
+                    </el-form-item>
+                    <el-form-item label="证件照反面" prop="cardBackPhotoUrl">
+                        <app-upload v-model="uploadFiles.cardBackPhotoUrl" :file-types="['image']"
+                            type-message="请选择正确的图片类型" />
+                    </el-form-item>
+                </template>
+                <template v-else>
+                    <el-form-item label="营业执照" prop="cardFrontPhotoUrl">
+                        <app-upload v-model="uploadFiles.cardFrontPhotoUrl" :file-types="['image']"
+                            type-message="请选择正确的图片类型" />
+                    </el-form-item>
+                    <el-form-item label="手持证件照" prop="halfBodyPhotoUrl">
+                        <app-upload v-model="uploadFiles.halfBodyPhotoUrl" :file-types="['image']"
+                            type-message="请选择正确的图片类型" />
+                    </el-form-item>
+                    <el-form-item label="法人身份证正面" prop="legalCardFrontPhotoUrl">
+                        <app-upload v-model="uploadFiles.legalCardFrontPhotoUrl" :file-types="['image']"
+                            type-message="请选择正确的图片类型" />
+                    </el-form-item>
+                    <el-form-item label="法人身份证反面" prop="legalCardFrontPhotoUrl">
+                        <app-upload v-model="uploadFiles.legalCardFrontPhotoUrl" :file-types="['image']"
+                            type-message="请选择正确的图片类型" />
+                    </el-form-item>
+                    <el-form-item label="法人授权书" prop="otherUrl">
+                        <app-upload v-model="uploadFiles.otherUrl" :file-types="['image']" type-message="请选择正确的图片类型" />
+                    </el-form-item>
+                </template>
+                <el-form-item class="el-form-item--row" label="备注" prop="remark">
+                    <el-input type="textarea" v-model="formData.userinfoDetailVo.remark" maxlength="200" :rows="2"
+                        placeholder="请输入" />
+                </el-form-item>
+            </fieldset>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)">关闭</el-button>
+            <el-button type="primary" @click="onSubmit">提交审核</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, PropType, onMounted, computed } from 'vue'
+import { ElMessage, FormInstance, FormRules, UploadUserFile } from 'element-plus'
+import { handleNoneValue } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { investorEdit, queryInvestorListDetail } from '@/services/api/investor'
+import { getUserInfoTypeList, getGenderList, UserInfoType } from '@/constants/member'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppUpload from '@pc/components/base/upload/index.vue'
+import AppEnum from '@pc/components/modules/enum/index.vue'
+import AppRegion from '@pc/components/modules/region/index.vue'
+import AppSelectMember from '@pc/components/modules/select-member/index.vue'
+import service from '@/services'
+import { decryptAES } from '@/services/crypto'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.InvestorListRsp>
+    }
+})
+
+const formRef = ref<FormInstance>()
+const show = ref(true)
+const refresh = ref(false)
+
+const uploadFiles = reactive<{
+    cardFrontPhotoUrl: UploadUserFile[];
+    cardBackPhotoUrl: UploadUserFile[];
+    legalCardFrontPhotoUrl: UploadUserFile[];
+    legalCardBackPhotoUrl: UploadUserFile[];
+    halfBodyPhotoUrl: UploadUserFile[];
+    otherUrl: UploadUserFile[];
+}>({
+    cardFrontPhotoUrl: [],
+    cardBackPhotoUrl: [],
+    halfBodyPhotoUrl: [],
+    legalCardFrontPhotoUrl: [],
+    legalCardBackPhotoUrl: [],
+    otherUrl: []
+})
+
+// 是否个人
+const isPerson = computed(() => formData.value.userinfoDetailVo.userinfoType === UserInfoType.Personal)
+
+const formData = ref<Model.InvestorEditReq>({
+    userAccountDetailVo: {},
+    userinfoDetailVo: {}
+})
+
+const getUploadFiles = (value?: string) => {
+    const paths = value ? value.split(',') : []
+    return paths.map((url) => {
+        const urlObj = new URL(url, service.getConfig('apiUrl'))
+        const name = urlObj.pathname.split('/').pop()
+        return {
+            name: name ?? urlObj.href,
+            url: urlObj.href,
+            response: {
+                data: [{ filePath: value }]
+            }
+        }
+    })
+}
+
+const { loading, run } = useRequest(queryInvestorListDetail, {
+    manual: true,
+    onSuccess: ((res) => {
+        const { userinfoDetailVo } = res.data.oldResult
+
+        userinfoDetailVo.cardNum = decryptAES(userinfoDetailVo.cardNum)
+        userinfoDetailVo.mobile = decryptAES(userinfoDetailVo.mobile)
+        userinfoDetailVo.telPhone = decryptAES(userinfoDetailVo.telPhone)
+        userinfoDetailVo.wechat = decryptAES(userinfoDetailVo.wechat)
+        userinfoDetailVo.email = decryptAES(userinfoDetailVo.email)
+
+        uploadFiles.cardFrontPhotoUrl = getUploadFiles(userinfoDetailVo.cardFrontPhotoUrl)
+        uploadFiles.cardBackPhotoUrl = getUploadFiles(userinfoDetailVo.cardBackPhotoUrl)
+        uploadFiles.legalCardFrontPhotoUrl = getUploadFiles(userinfoDetailVo.legalCardFrontPhotoUrl)
+        uploadFiles.legalCardBackPhotoUrl = getUploadFiles(userinfoDetailVo.legalCardBackPhotoUrl)
+        uploadFiles.otherUrl = getUploadFiles(userinfoDetailVo.otherUrl)
+
+        formData.value = res.data.oldResult
+    }),
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+// 表单验证规则
+const formRules: FormRules = {
+    accountName: [{ 
+        required: true,
+        validator: (rule, value, callback) => {
+            if (formData.value.userAccountDetailVo.accountName) {
+                callback()
+            } else {
+                callback(new Error('请输入交易商名称'))
+            }
+        },
+     }],
+    cardTypeId: [{ required: true }],
+    cardNum: [{ required: true }],
+    mobile: [{ required: true }]
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+// 更新上传文件到表单中
+const updateUploadFiles = (uploadFiles: UploadUserFile[]) => {
+    return uploadFiles.map((e) => {
+        const res = e.response as { data: { filePath: string }[] }
+        return res.data.map((e) => e.filePath)
+    }).join(',')
+}
+
+const onSubmit = () => {
+    const rawData = { ...formData.value }
+    rawData.userAccountDetailVo.modifyStatus = 3
+    rawData.userinfoDetailVo.cardFrontPhotoUrl = updateUploadFiles(uploadFiles.cardFrontPhotoUrl)
+    rawData.userinfoDetailVo.cardBackPhotoUrl = updateUploadFiles(uploadFiles.cardBackPhotoUrl)
+    rawData.userinfoDetailVo.halfBodyPhotoUrl = updateUploadFiles(uploadFiles.halfBodyPhotoUrl)
+    rawData.userinfoDetailVo.legalCardFrontPhotoUrl = updateUploadFiles(uploadFiles.legalCardFrontPhotoUrl)
+    rawData.userinfoDetailVo.legalCardBackPhotoUrl = updateUploadFiles(uploadFiles.legalCardBackPhotoUrl)
+    rawData.userinfoDetailVo.otherUrl = updateUploadFiles(uploadFiles.otherUrl)
+
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            loading.value = true
+            investorEdit({
+                data: rawData
+            }).then(() => {
+                ElMessage.success('保存成功')
+                onCancel(true)
+            }).catch((err) => {
+                ElMessage.error('保存失败:' + err)
+            }).finally(() => {
+                loading.value = false
+            })
+        }
+    })
+}
+
+onMounted(() => {
+    const record = props.record
+    if (record) {
+        run({
+            userid: record.userId,
+            modifyFlag: record.modifyStatus
+        })
+    }
+})
+</script>

+ 50 - 0
src/packages/pc/views/investor/manage/user/components/login/delete/index.vue

@@ -0,0 +1,50 @@
+<!-- 交易商管理-交易商管理-交易商管理-登录账户-注销停用 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">确认将账户停用?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { deleteAccount } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.InvestorLoginListRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    deleteAccount({
+        data: {
+            loginid: props.selectedItem.loginid
+        }
+    }).then(() => {
+        ElMessage.success('停用成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('停用失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 53 - 0
src/packages/pc/views/investor/manage/user/components/login/details/index.vue

@@ -0,0 +1,53 @@
+<!-- 交易商管理-交易商管理-交易商管理-登录账户-详情 -->
+<template>
+    <app-drawer title="详情" width="480" v-model:show="show" :refresh="refresh">
+        <app-table-details :data="data" :label-width="140" :cell-props="detailProps">
+            <template #loginid>
+                {{ `${data?.loginid}(${data?.bindname})` }}
+            </template>
+        </app-table-details>
+        <template #footer>
+            <el-button @click="onCancel(false)">关闭</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { decryptAES } from '@/services/crypto'
+import { useRequest } from '@/hooks/request'
+import { queryUserAuthInfo } from '@/services/api/investor'
+import { CellProp } from '@pc/components/base/table-details/types'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.InvestorLoginListRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+
+const { data } = useRequest(queryUserAuthInfo, {
+    params: {
+        loginid: props.selectedItem.loginid
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const detailProps: CellProp[] = [
+    { prop: 'loginid', label: '登录账号:' },
+    { prop: 'authid', label: '手机号:', formatValue: (val) => decryptAES(val) },
+]
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+</script>

+ 128 - 0
src/packages/pc/views/investor/manage/user/components/login/index.vue

@@ -0,0 +1,128 @@
+<!-- 交易商管理-交易商管理-交易商管理-登录账户 -->
+<template>
+    <teleport to="#appPageTeleport">
+        <app-view>
+            <template #header>
+                <app-filter :option="filterOption" />
+            </template>
+            <app-table :data="dataList" :columns="tableColumns">
+                <template #headerRight>
+                    <div style="display: flex;">
+                        <el-button @click="emit('closed')">关闭</el-button>
+                    </div>
+                </template>
+                <!-- 操作 -->
+                <template #operate="{ row }">
+                    <el-button size="small" icon="Document" @click="showComponent('Log', row)" circle plain />
+                    <template v-if="row.loginstatus === 1">
+                        <el-button size="small" icon="Key" @click="showComponent('Password', row)" circle plain />
+                        <el-button size="small" icon="Lock" @click="showComponent('Lock', row)" circle plain />
+                        <el-button size="small" icon="SwitchButton" @click="showComponent('Delete', row)" circle plain
+                            v-if="userStore.userInfo.releType === 1" />
+                    </template>
+                    <el-button size="small" icon="RefreshLeft" @click="showComponent('Recover', row)" circle plain
+                        v-if="userStore.userInfo.releType === 1 && row.loginstatus === 3" />
+                    <el-button size="small" icon="Unlock" @click="showComponent('Lock', row)" circle plain
+                        v-if="row.loginstatus === 2" />
+                    <el-button size="small" icon="Iphone" @click="showComponent('Details', row)" circle plain
+                        v-if="row.loginstatus === 1" />
+                </template>
+                <template #footer>
+                    <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                        @change="onSearch" />
+                </template>
+            </app-table>
+            <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ selectedItem }"
+                @closed="closeComponent" v-if="componentId" />
+        </app-view>
+    </teleport>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType, defineAsyncComponent } from 'vue'
+import { ElMessage } from 'element-plus'
+import { formatDate } from '@/filters'
+import { useEnum } from '@/hooks/enum'
+import { useDataFilter } from '@/hooks/datatable-v2'
+import { useComponent } from '@/hooks/component'
+import { useRequest } from '@/hooks/request'
+import { queryInvestorLoginList } from '@/services/api/investor'
+import { useUserStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.InvestorListRsp>,
+        required: true
+    }
+})
+
+const componentMap = new Map<string, unknown>([
+    ['Log', defineAsyncComponent(() => import('./log/index.vue'))], // 登录日志
+    ['Password', defineAsyncComponent(() => import('./password/index.vue'))], // 重置密码
+    ['Lock', defineAsyncComponent(() => import('./lock/index.vue'))], // 锁定/解锁
+    ['Delete', defineAsyncComponent(() => import('./delete/index.vue'))], // 注销停用
+    ['Recover', defineAsyncComponent(() => import('./recover/index.vue'))], // 恢复
+    ['Details', defineAsyncComponent(() => import('./details/index.vue'))], // 详情
+])
+
+const emit = defineEmits(['closed'])
+
+const userStore = useUserStore()
+
+const selectedItem = ref<Model.InvestorLoginListRsp>()
+
+const loginstatusEnum = useEnum('loginstatus') // 账号状态
+
+const { filterOption, getQueryParams, resetFilters } = useDataFilter<Model.InvestorLoginListReq>()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => run())
+
+const { dataList, total, pageSize, pageIndex, run } = useRequest(queryInvestorLoginList, {
+    params: {
+        pageNum: 1,
+        pageSize: 20,
+        userid: props.record.userId
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = ref<Model.TableColumn[]>([
+    { field: 'loginid', label: '登录账户' },
+    { field: 'loginstatus', label: '账号状态', formatValue: (val) => loginstatusEnum.getEnumTypeName(val) },
+    { field: 'modifytime', label: '修改时间', formatValue: (val) => formatDate(val) },
+    { field: 'modifiername', label: '修改人' },
+    { field: 'operate', label: '操作', fixed: 'right' }
+])
+
+filterOption.items = [
+    {
+        key: 'loginid',
+        label: '登录账户',
+    },
+    {
+        key: 'loginstatus',
+        label: '账户状态',
+        options: () => loginstatusEnum.getEnumOptions()
+    },
+]
+
+filterOption.buttons = [
+    { label: '查询', className: 'el-button--primary', validateEvent: true, onClick: () => onSearch() },
+    { label: '重置', className: 'el-button--primary', onClick: () => resetFilters() }
+]
+
+const onSearch = (clear = false) => {
+    const qs = getQueryParams(clear)
+    run(qs)
+}
+
+const showComponent = (code: string, row?: Model.InvestorLoginListRsp) => {
+    selectedItem.value = row
+    openComponent(code)
+}
+</script>

+ 53 - 0
src/packages/pc/views/investor/manage/user/components/login/lock/index.vue

@@ -0,0 +1,53 @@
+<!-- 交易商管理-交易商管理-交易商管理-登录账户-锁定 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message" v-if="selectedItem.loginstatus === 1">确认锁定该账户?</div>
+        <div class="g-text-message" v-else>确认解锁该账户?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { lockAccount } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.InvestorLoginListRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    const { loginid, loginstatus } = props.selectedItem
+    loading.value = true
+    lockAccount({
+        data: {
+            loginid,
+            status: loginstatus === 1 ? 2 : 1
+        }
+    }).then(() => {
+        ElMessage.success(loginstatus === 1 ? '锁定成功' : '解锁成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error((loginstatus === 1 ? '锁定失败:' : '解锁失败:') + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 62 - 0
src/packages/pc/views/investor/manage/user/components/login/log/index.vue

@@ -0,0 +1,62 @@
+<!-- 交易商管理-交易商管理-交易商管理-登录账户-登录流水 -->
+<template>
+    <app-drawer title="登录流水" width="960" v-model:show="show" :refresh="refresh">
+        <app-table :data="dataList" :columns="tableColumns">
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="run" />
+            </template>
+        </app-table>
+        <template #footer>
+            <el-button @click="onCancel(false)">关闭</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { formatDate } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { queryLoginLog } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.InvestorLoginListRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+
+const { dataList, total, pageSize, pageIndex, run } = useRequest(queryLoginLog, {
+    params: {
+        pageNum: 1,
+        pageSize: 20,
+        loginid: props.selectedItem.loginid
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { field: 'loginflowno', label: '登录流水号' },
+    { field: 'operatetime', label: '登录时间', formatValue: (val) => formatDate(val) },
+    { field: 'loginip', label: '登录IP' },
+    { field: 'clienttype', label: '客户端类型' },
+    { field: 'softversion', label: '软件版本' },
+    { field: 'loginretcode', label: '登录结果' },
+    { field: 'funcode', label: '登录/登出' },
+    { field: 'operatetype', label: '操作类型' },
+])
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+</script>

+ 50 - 0
src/packages/pc/views/investor/manage/user/components/login/password/index.vue

@@ -0,0 +1,50 @@
+<!-- 交易商管理-交易商管理-交易商管理-登录账户-重置密码 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">确认将密码重置?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { resetPwd } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.InvestorLoginListRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    resetPwd({
+        data: {
+            loginid: props.selectedItem.loginid
+        }
+    }).then(() => {
+        ElMessage.success('重置成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('重置失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 50 - 0
src/packages/pc/views/investor/manage/user/components/login/recover/index.vue

@@ -0,0 +1,50 @@
+<!-- 交易商管理-交易商管理-交易商管理-登录账户-恢复 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">确认恢复账户?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { restoreAccount } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.InvestorLoginListRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    restoreAccount({
+        data: {
+            loginid: props.selectedItem.loginid
+        }
+    }).then(() => {
+        ElMessage.success('恢复成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('恢复失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 50 - 0
src/packages/pc/views/investor/manage/user/components/recover/index.vue

@@ -0,0 +1,50 @@
+<!-- 交易商管理-交易商管理-交易商管理-恢复 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">确认恢复该交易商?<br />相关登录账户的账号状态在登录账户中另行恢复。</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { investorRecover } from '@/services/api/investor'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.InvestorListRsp>,
+        required: true
+    }
+})
+
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    investorRecover({
+        data: {
+            areaid: props.record.userId
+        }
+    }).then(() => {
+        ElMessage.success('恢复成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('恢复失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 14 - 3
src/packages/pc/views/investor/manage/user/index.vue

@@ -47,7 +47,7 @@ const modifystatusEnum = useEnum('modifystatus')
 
 const { filterOptons, getQueryParams } = useDataFilter<Model.InvestorListReq>()
 
-const { componentMap, componentId, record, openComponent, closeComponent, getFilteredButtons } = useOperation<Model.InvestorRsp>({
+const { componentMap, componentId, record, openComponent, closeComponent, getFilteredButtons } = useOperation<Model.InvestorListRsp>({
     onClose: () => onSearch()
 })
 
@@ -75,7 +75,7 @@ const tableColumns = shallowRef<Model.TableColumn[]>([
     { field: 'modifyTime', label: '最后更新时间', formatValue: (val) => formatDate(val) },
     { field: 'auditTime', label: '审核时间', formatValue: (val) => formatDate(val) },
     { field: 'cancelTime', label: '销户时间', formatValue: (val) => formatDate(val) },
-    { field: 'operate', label: '操作', fixed: 'right' }
+    { field: 'operate', label: '操作', fixed: 'right', width: 260 }
 ])
 
 filterOptons.inputList = [
@@ -103,7 +103,18 @@ filterOptons.buttonList = [
 
 // 处理操作按钮
 const handleOperateButtons = (row: Model.InvestorListRsp) => {
-    return getFilteredButtons(['investor_manage_user_details'])
+    const buttons = ['investor_manage_user_details']
+    if (row.accountStatus === 6) {
+        buttons.push('investor_manage_user_recover')
+    } else {
+        if ([3, 4].includes(row.modifyStatus)) {
+            buttons.push('investor_manage_user_cancel')
+        } else {
+            buttons.push('investor_manage_user_modify')
+        }
+        buttons.push('investor_manage_user_config', 'investor_manage_user_account', 'investor_manage_user_login', 'investor_manage_user_delete')
+    }
+    return getFilteredButtons(buttons)
 }
 
 const onSearch = (clear = false) => {

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

@@ -12,7 +12,7 @@
                 </el-form-item>
                 <el-form-item label="日期" prop="cycletime">
                     <el-date-picker :type="dateType" v-model="params.cycletime" :format="dateFormat"
-                        :value-format="dateFormat" />
+                        :value-format="dateFormat" placeholder="请选择" />
                 </el-form-item>
                 <el-form-item label="季度" prop="quarter" v-if="params.cycletype === ReportType.Quarter">
                     <el-select v-model="params.quarter">

+ 66 - 104
src/packages/pc/views/report/broker/index.vue

@@ -2,51 +2,38 @@
 <template>
     <app-view>
         <template #header>
-            <el-form ref="formRef" class="el-form--filter" :model="queryParams" :rules="formRules" :show-message="false">
-            <el-form-item label="报表类型" prop="cycletype">
-                    <el-select v-model="queryParams.cycletype">
+            <el-form ref="formRef" class="el-form--filter" :model="queryParams" :rules="formRules"
+                :show-message="false">
+                <el-form-item label="报表类型" prop="cycletype">
+                    <el-select v-model="queryParams.cycletype" @change="onTypeChange">
                         <el-option v-for="item in getReportTypeList()" :key="item.value" :label="item.label"
                             :value="item.value" />
                     </el-select>
                 </el-form-item>
-                <el-form-item label="开始日期" prop="reckondate">
-                    <el-date-picker :type="dateType" v-model="queryParams.reckondate" :format="dateFormat"
-                    :value-format="dateFormat" placeholder="请选择日期" @change="onReckonDateChange" />
+                <el-form-item label="日期" prop="reckondate">
+                    <el-date-picker :type="dateType" v-model="dateValue" :format="dateFormat" :value-format="dateFormat"
+                        placeholder="请选择" start-placeholder="开始" end-placeholder="结束" @change="onDateChange" />
                 </el-form-item>
-                <el-form-item label="结束日期" prop="reckondateend">
-                    <el-date-picker :type="dateType" v-model="queryParams.reckondateend" :format="dateFormat"
-                    :value-format="dateFormat" placeholder="请选择日期" @change="onReckonEndDateChange"/>
-                </el-form-item>
-                <el-form-item label="开始季度" prop="quarter" v-if="queryParams.cycletype === ReportType.Quarter">
-                    <el-select v-model="queryParams.quarter">
-                        <el-option v-for="item in getQuarterList()" :key="item.value" :label="item.label"
-                            :value="item.value" />
+                <el-form-item label="季度" prop="quarter" v-if="queryParams.cycletype === ReportType.Quarter">
+                    <el-select v-model="queryParams.quarter" @change="onQuarterChange">
+                        <template v-for="item in getQuarterList()" :key="item.value">
+                            <el-option :label="item.label" :value="item.value" />
+                        </template>
                     </el-select>
                 </el-form-item>
-                <el-form-item label="开始季度" prop="quarter" v-if="queryParams.cycletype === ReportType.Quarter">
-                    <el-select v-model="queryParams.quarterend">
-                        <el-option v-for="item in getQuarterList()" :key="item.value" :label="item.label"
-                            :value="item.value" />
-                    </el-select>
-                </el-form-item>
-                <el-form-item label="资金账户" prop="accountid">
-                    <app-select-account v-model="queryParams.accountid" @change="onAccountChange" />
+                <el-form-item label="所属机构" prop="accountid">
+                    <app-select-account v-model="queryParams.accountid" />
                 </el-form-item>
                 <el-form-item label="是否包含子机构" prop="isson">
-                    <el-checkbox v-model="isson" size="small" />
+                    <el-switch v-model="queryParams.type" active-value="1" inactive-value="0" />
                 </el-form-item>
                 <el-form-item>
-                    <el-button type="primary" @click="onSearch">查询</el-button>
-                    <el-button type="primary" @click="onSearch(false)">重置</el-button>
+                    <el-button type="primary" @click="onSearch(false)">查询</el-button>
+                    <el-button type="primary" @click="onSearch(true)">重置</el-button>
                 </el-form-item>
             </el-form>
-            <div class="report-account__info" v-if="selectedAccount">
-                <span>账户:{{ selectedAccount.relatedname }}</span>
-                <span>资金账户:{{ selectedAccount.accountid }}</span>
-                <span>登录账号:{{ selectedAccount.invloginids }}</span>
-            </div>
         </template>
-        <app-table :data="dataList" showIndex :columns="tableColumns" :loading="loading">
+        <app-table :data="dataList" :columns="tableColumns" :loading="loading">
             <template #headerLeft>
                 <app-operation :data-list="getFilteredButtons(['query_report_broker_export'])"
                     @click="openComponentOnClick" />
@@ -62,28 +49,23 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, ref, computed } from 'vue'
+import { ref, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
 import { useRequest } from '@/hooks/request'
 import { orgReportQuery } from '@/services/api/report'
 import { useOperation } from '@/hooks/operation'
-import { formatDate } from '@/filters'
-import { useUserStore } from '@/stores'
 import { getReportTypeList, ReportType, getQuarterList } from '@/constants/report'
 import AppTable from '@pc/components/base/table/index.vue'
 import AppPagination from '@pc/components/base/pagination/index.vue'
 import AppOperation from '@pc/components/base/operation/index.vue'
 import AppSelectAccount from '@pc/components/modules/select-account/index.vue'
 
-const userStore = useUserStore()
-const formRef = shallowRef<FormInstance>()
-const isson = ref(true)
-const selectedAccount = shallowRef<Model.TAAccountChildrenSelectRsp>()
+const formRef = ref<FormInstance>()
+const dateValue = ref<string[] | string>([])
 
 const queryParams = ref<Partial<Model.OrgReportQueryReq>>({
-    orgztypes: userStore.userInfo.orgztypes,
     cycletype: 0,
-    type: isson.value ? 1 : 0
+    type: 0
 })
 
 const { componentMap, componentId, record, openComponent, closeComponent, getFilteredButtons } = useOperation<Model.OrgReportQueryRsp>({
@@ -94,9 +76,7 @@ const { dataList, total, pageSize, pageIndex, loading, run } = useRequest(orgRep
     manual: true,
     params: {
         pageNum: 1,
-        pageSize: 20,
-        orgztypes: userStore.userInfo.orgztypes,
-        type: isson.value ? 1 : 0
+        pageSize: 20
     },
     onError: (err) => {
         ElMessage.error(err)
@@ -109,12 +89,13 @@ const dateType = computed(() => {
         case ReportType.Week:
             return 'week'
         case ReportType.Month:
-            return 'month'
+            return 'monthrange'
         case ReportType.Quarter:
-        case ReportType.Year:
             return 'year'
+        case ReportType.Year:
+            return 'yearrange'
         default:
-            return 'date'
+            return 'daterange'
     }
 })
 
@@ -122,55 +103,21 @@ const dateType = computed(() => {
 const dateFormat = computed(() => {
     switch (queryParams.value.cycletype) {
         case ReportType.Month:
-            return 'YYYY-MM'
+            return 'YYYYMM'
         case ReportType.Quarter:
         case ReportType.Year:
             return 'YYYY'
         default:
-            return 'YYYY-MM-DD'
+            return 'YYYYMMDD'
     }
 })
 
-const onReckonDateChange = () => {
-    const reckondate = queryParams.value.reckondate
-    if (reckondate) {
-        switch (queryParams.value.cycletype) {
-            case ReportType.Month:
-            queryParams.value.reckondate = formatDate(reckondate, 'YYYY-MM')
-                break
-            case ReportType.Quarter:
-            case ReportType.Year:
-            queryParams.value.reckondate = formatDate(reckondate, 'YYYY')
-                break
-            default:
-            queryParams.value.reckondate = formatDate(reckondate, 'YYYY-MM-DD')
-        }
-    }   
-}
-
-const onReckonEndDateChange = () => {
-    const reckondateend = queryParams.value.reckondateend
-    if (reckondateend) {
-        switch (queryParams.value.cycletype) {
-            case ReportType.Month:
-            queryParams.value.reckondateend = formatDate(reckondateend, 'YYYY-MM')
-                break
-            case ReportType.Quarter:
-            case ReportType.Year:
-            queryParams.value.reckondateend = formatDate(reckondateend, 'YYYY')
-                break
-            default:
-            queryParams.value.reckondateend = formatDate(reckondateend, 'YYYY-MM-DD')
-        }
-    }
-}
-
-const tableColumns = shallowRef<Model.TableColumn[]>([
+const tableColumns = ref<Model.TableColumn[]>([
     { field: 'cycleTime', label: '日期' },
     { field: 'accountName', label: '经纪会员' },
-    { field: 'investorTotalNum', label: '交易商开户数量' },
-    { field: 'investorTrialNum', label: '交易商开户待初审数量' },
-    { field: 'investorRetrialNum', label: '交易商开户待复审数量' },
+    { field: 'investorTotalNum', label: '交易商开户数量', width: 160 },
+    { field: 'investorTrialNum', label: '交易商开户待初审数量', width: 180 },
+    { field: 'investorRetrialNum', label: '交易商开户待复审数量', width: 180 },
     { field: 'investorAmount', label: '期末余额' },
     { field: 'investorusedmargin', label: '占用保证金' },
     { field: 'investorClosePl', label: '转让损益' },
@@ -185,24 +132,47 @@ const tableColumns = shallowRef<Model.TableColumn[]>([
 // 表单验证规则
 const formRules: FormRules = {
     reckondate: [{ required: true }],
-    reckondateend: [{ required: true }],
+    quarter: [{ required: true }],
+}
+
+// 选择类型
+const onTypeChange = (value: number) => {
+    if (value === ReportType.Week || value === ReportType.Quarter) {
+        dateValue.value = ''
+    } else {
+        dateValue.value = []
+    }
+    queryParams.value.reckondate = undefined
+    queryParams.value.reckondateend = undefined
+    queryParams.value.quarter = undefined
+    queryParams.value.quarterend = undefined
+}
+
+// 选择日期
+const onDateChange = () => {
+    if (Array.isArray(dateValue.value)) {
+        const [startDate, endDate] = dateValue.value
+        queryParams.value.reckondate = startDate
+        queryParams.value.reckondateend = endDate
+    } else {
+        queryParams.value.reckondate = dateValue.value
+        queryParams.value.reckondateend = dateValue.value
+    }
 }
 
-const onAccountChange = (item?: Model.TAAccountChildrenSelectRsp) => {
-    selectedAccount.value = item
+// 选择季度
+const onQuarterChange = (value: number) => {
+    queryParams.value.quarterend = value
 }
 
 const onSearch = (clear = false) => {
-    if (!clear) {
+    if (clear) {
         queryParams.value = {
             cycletype: 0,
-            reckondate: '',
-            reckondateend: '',
-            type: isson.value ? 1 : 0,
-            orgztypes: userStore.userInfo.orgztypes
+            type: 0
         }
+        dateValue.value = []
     } else {
-        queryParams.value.type = isson.value ? 1 : 0
         formRef.value?.validate((valid) => {
             if (valid) {
                 run(queryParams.value)
@@ -212,14 +182,6 @@ const onSearch = (clear = false) => {
 }
 
 const openComponentOnClick = (code: string) => {
-    processRequiredParams(() => openComponent(code))
+    openComponent(code)
 }
-
-// 处理请求参数
-const processRequiredParams = (callback: (params: Model.OrgReportQueryReq) => void, clear = false) => {
-    queryParams.value.type = isson.value ? 1 : 0
-    queryParams.value.orgztypes = userStore.userInfo.orgztypes
-    onSearch(!clear)
-}
-
 </script>

+ 72 - 97
src/packages/pc/views/report/investor/index.vue

@@ -2,54 +2,52 @@
 <template>
     <app-view>
         <template #header>
-            <el-form ref="formRef" class="el-form--filter" :model="queryParams" :rules="formRules" :show-message="false">
+            <el-form ref="formRef" class="el-form--filter" :model="queryParams" :rules="formRules"
+                :show-message="false">
                 <el-form-item label="报表类型" prop="cycletype">
-                    <el-select v-model="queryParams.cycletype">
+                    <el-select v-model="queryParams.cycletype" @change="onTypeChange">
                         <el-option v-for="item in getReportTypeList()" :key="item.value" :label="item.label"
                             :value="item.value" />
                     </el-select>
                 </el-form-item>
-                <el-form-item label="开始日期" prop="reckondate">
-                    <el-date-picker :type="dateType" v-model="queryParams.reckondate" :format="dateFormat"
-                    :value-format="dateFormat" placeholder="请选择日期" @change="onReckonDateChange" />
+                <el-form-item label="日期" prop="reckondate">
+                    <el-date-picker :type="dateType" v-model="dateValue" :format="dateFormat" :value-format="dateFormat"
+                        placeholder="请选择" start-placeholder="开始" end-placeholder="结束" @change="onDateChange" />
                 </el-form-item>
-                <el-form-item label="结束日期" prop="reckondateend">
-                    <el-date-picker :type="dateType" v-model="queryParams.reckondateend" :format="dateFormat"
-                    :value-format="dateFormat" placeholder="请选择日期" @change="onReckonEndDateChange" />
-                </el-form-item>
-                <el-form-item label="开始季度" prop="quarter" v-if="queryParams.cycletype === ReportType.Quarter">
-                    <el-select v-model="queryParams.quarter">
-                        <el-option v-for="item in getQuarterList()" :key="item.value" :label="item.label"
-                            :value="item.value" />
+                <el-form-item label="季度" prop="quarter" v-if="queryParams.cycletype === ReportType.Quarter">
+                    <el-select v-model="queryParams.quarter" @change="onQuarterChange">
+                        <template v-for="item in getQuarterList()" :key="item.value">
+                            <el-option :label="item.label" :value="item.value" />
+                        </template>
                     </el-select>
                 </el-form-item>
-                <el-form-item label="开始季度" prop="quarter" v-if="queryParams.cycletype === ReportType.Quarter">
-                    <el-select v-model="queryParams.quarterend">
-                        <el-option v-for="item in getQuarterList()" :key="item.value" :label="item.label"
-                            :value="item.value" />
-                    </el-select>
+                <el-form-item label="交易商" prop="accountid">
+                    <el-input v-model="queryParams.accountid" placeholder="请输入交易商ID" />
                 </el-form-item>
-                <el-form-item label="资金账户" prop="accountid">
-                    <app-select-account v-model="queryParams.accountid" @change="onAccountChange" />
+                <el-form-item label="所属会员" prop="memberid">
+                    <el-input v-model="queryParams.memberid" placeholder="请输入会员ID" />
+                </el-form-item>
+                <el-form-item label="所属子机构" prop="subareaid">
+                    <el-input v-model="queryParams.subareaid" placeholder="请输入子机构ID" />
+                </el-form-item>
+                <el-form-item label="所属经纪人" prop="brokerid">
+                    <el-input v-model="queryParams.brokerid" placeholder="请输入经纪人ID" />
                 </el-form-item>
                 <el-form-item label="入金金额" prop="inamount">
-                    <el-input-number v-model="queryParams.inamount" maxlength="50" placeholder="查询大于等于此数值的数据" />
+                    <el-input-number v-model="queryParams.inamount" :min="0" controls-position="right"
+                        placeholder="查询大于等于此数值的数据" style="width: 240px;" />
                 </el-form-item>
                 <el-form-item label="出金金额" prop="outamount">
-                    <el-input-number v-model="queryParams.outamount" maxlength="50" placeholder="查询大于等于此数值的数据" />
+                    <el-input-number v-model="queryParams.outamount" :min="0" controls-position="right"
+                        placeholder="查询大于等于此数值的数据" style="width: 240px;" />
                 </el-form-item>
                 <el-form-item>
-                    <el-button type="primary" @click="onSearch">查询</el-button>
-                    <el-button type="primary" @click="onSearch(false)">重置</el-button>
+                    <el-button type="primary" @click="onSearch(false)">查询</el-button>
+                    <el-button type="primary" @click="onSearch(true)">重置</el-button>
                 </el-form-item>
             </el-form>
-            <div class="report-account__info" v-if="selectedAccount">
-                <span>账户:{{ selectedAccount.relatedname }}</span>
-                <span>资金账户:{{ selectedAccount.accountid }}</span>
-                <span>登录账号:{{ selectedAccount.invloginids }}</span>
-            </div>
         </template>
-        <app-table :data="dataList" showIndex :columns="tableColumns" :loading="loading">
+        <app-table :data="dataList" :columns="tableColumns" :loading="loading">
             <template #headerLeft>
                 <app-operation :data-list="getFilteredButtons(['query_report_investor_export'])"
                     @click="openComponentOnClick" />
@@ -65,25 +63,20 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, ref, computed } from 'vue'
+import { ref, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
 import { useRequest } from '@/hooks/request'
 import { investorReportQuery } from '@/services/api/report'
-import { formatDate } from '@/filters'
 import { useOperation } from '@/hooks/operation'
-import { useUserStore } from '@/stores'
 import { getReportTypeList, ReportType, getQuarterList } from '@/constants/report'
 import AppTable from '@pc/components/base/table/index.vue'
 import AppPagination from '@pc/components/base/pagination/index.vue'
 import AppOperation from '@pc/components/base/operation/index.vue'
-import AppSelectAccount from '@pc/components/modules/select-account/index.vue'
 
-const formRef = shallowRef<FormInstance>()
-const userStore = useUserStore()
-const selectedAccount = shallowRef<Model.TAAccountChildrenSelectRsp>()
+const formRef = ref<FormInstance>()
+const dateValue = ref<string[] | string>([])
 
 const queryParams = ref<Partial<Model.InvestorReportReq>>({
-    orgztypes: userStore.userInfo.orgztypes,
     cycletype: 0
 })
 
@@ -94,10 +87,8 @@ const { componentMap, componentId, record, openComponent, closeComponent, getFil
 const { dataList, total, pageSize, pageIndex, loading, run } = useRequest(investorReportQuery, {
     manual: true,
     params: {
-        cycletype: 0,
         pageNum: 1,
-        pageSize: 20,
-        orgztypes: userStore.userInfo.orgztypes
+        pageSize: 20
     },
     onError: (err) => {
         ElMessage.error(err)
@@ -110,12 +101,13 @@ const dateType = computed(() => {
         case ReportType.Week:
             return 'week'
         case ReportType.Month:
-            return 'month'
+            return 'monthrange'
         case ReportType.Quarter:
-        case ReportType.Year:
             return 'year'
+        case ReportType.Year:
+            return 'yearrange'
         default:
-            return 'date'
+            return 'daterange'
     }
 })
 
@@ -123,51 +115,17 @@ const dateType = computed(() => {
 const dateFormat = computed(() => {
     switch (queryParams.value.cycletype) {
         case ReportType.Month:
-            return 'YYYY-MM'
+            return 'YYYYMM'
         case ReportType.Quarter:
         case ReportType.Year:
             return 'YYYY'
         default:
-            return 'YYYY-MM-DD'
+            return 'YYYYMMDD'
     }
 })
 
-const onReckonDateChange = () => {
-    const reckondate = queryParams.value.reckondate
-    if (reckondate) {
-        switch (queryParams.value.cycletype) {
-            case ReportType.Month:
-            queryParams.value.reckondate = formatDate(reckondate, 'YYYY-MM')
-                break
-            case ReportType.Quarter:
-            case ReportType.Year:
-            queryParams.value.reckondate = formatDate(reckondate, 'YYYY')
-                break
-            default:
-            queryParams.value.reckondate = formatDate(reckondate, 'YYYY-MM-DD')
-        }
-    }   
-}
-
-const onReckonEndDateChange = () => {
-    const reckondateend = queryParams.value.reckondateend
-    if (reckondateend) {
-        switch (queryParams.value.cycletype) {
-            case ReportType.Month:
-            queryParams.value.reckondateend = formatDate(reckondateend, 'YYYY-MM')
-                break
-            case ReportType.Quarter:
-            case ReportType.Year:
-            queryParams.value.reckondateend = formatDate(reckondateend, 'YYYY')
-                break
-            default:
-            queryParams.value.reckondateend = formatDate(reckondateend, 'YYYY-MM-DD')
-        }
-    }
-}
-
-const tableColumns = shallowRef<Model.TableColumn[]>([
-    { field: 'reckondate', label: '日期', formatValue:((val) => formatDate(val)) },
+const tableColumns = ref<Model.TableColumn[]>([
+    { field: 'reckondate', label: '日期' },
     { field: 'loginids', label: '登录账号' },
     { field: 'accountid', label: '资金账户' },
     { field: 'accountname', label: '账户名称' },
@@ -196,18 +154,42 @@ const formRules: FormRules = {
     reckondateend: [{ required: true }],
 }
 
-const onAccountChange = (item?: Model.TAAccountChildrenSelectRsp) => {
-    selectedAccount.value = item
+// 选择类型
+const onTypeChange = (value: number) => {
+    if (value === ReportType.Week || value === ReportType.Quarter) {
+        dateValue.value = ''
+    } else {
+        dateValue.value = []
+    }
+    queryParams.value.reckondate = undefined
+    queryParams.value.reckondateend = undefined
+    queryParams.value.quarter = undefined
+    queryParams.value.quarterend = undefined
+}
+
+// 选择日期
+const onDateChange = () => {
+    if (Array.isArray(dateValue.value)) {
+        const [startDate, endDate] = dateValue.value
+        queryParams.value.reckondate = startDate
+        queryParams.value.reckondateend = endDate
+    } else {
+        queryParams.value.reckondate = dateValue.value
+        queryParams.value.reckondateend = dateValue.value
+    }
+}
+
+// 选择季度
+const onQuarterChange = (value: number) => {
+    queryParams.value.quarterend = value
 }
 
 const onSearch = (clear = false) => {
-    if (!clear) {
+    if (clear) {
         queryParams.value = {
-            cycletype: 0,
-            reckondate: '',
-            reckondateend: '',
-            orgztypes: userStore.userInfo.orgztypes
+            cycletype: 0
         }
+        dateValue.value = []
     } else {
         formRef.value?.validate((valid) => {
             if (valid) {
@@ -218,13 +200,6 @@ const onSearch = (clear = false) => {
 }
 
 const openComponentOnClick = (code: string) => {
-    processRequiredParams(() => openComponent(code))
+    openComponent(code)
 }
-
-// 处理请求参数
-const processRequiredParams = (callback: (params: Model.InvestorReportReq) => void, clear = false) => {
-    queryParams.value.orgztypes = userStore.userInfo.orgztypes
-    onSearch(!clear)
-}
-
 </script>

+ 24 - 24
src/packages/pc/views/report/profitshare/index.vue

@@ -5,14 +5,14 @@
             <el-form ref="formRef" class="el-form--filter" :model="queryParams" :rules="formRules"
                 :show-message="false">
                 <el-form-item label="报表类型" prop="cycletype">
-                    <el-select v-model="queryParams.cycletype" @change="onTypeChange">
+                    <el-select v-model="queryParams.cycletype">
                         <el-option v-for="item in getReportTypeList()" :key="item.value" :label="item.label"
                             :value="item.value" />
                     </el-select>
                 </el-form-item>
                 <el-form-item label="日期" prop="tradedate">
                     <el-date-picker :type="dateType" v-model="queryParams.tradedate" :format="dateFormat"
-                        :value-format="dateFormat" placeholder="请选择日期" />
+                        placeholder="请选择" />
                 </el-form-item>
                 <el-form-item label="季度" prop="quarter" v-if="queryParams.cycletype === ReportType.Quarter">
                     <el-select v-model="queryParams.quarter">
@@ -29,7 +29,7 @@
                 </el-form-item>
             </el-form>
         </template>
-        <app-table :data="dataList" showIndex :columns="tableColumns" :loading="loading">
+        <app-table :data="dataList" :columns="tableColumns" :loading="loading">
             <template #headerLeft>
                 <app-operation :data-list="getFilteredButtons(['query_order_institutionsumm_export'])"
                     @click="openComponentOnClick" />
@@ -45,7 +45,7 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, computed, ref } from 'vue'
+import { computed, ref } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
 import { useEnum } from '@/hooks/enum'
 import { useRequest } from '@/hooks/request'
@@ -59,7 +59,7 @@ import AppOperation from '@pc/components/base/operation/index.vue'
 
 const roleTypeEnum = useEnum('roleType') // 角色
 
-const formRef = shallowRef<FormInstance>()
+const formRef = ref<FormInstance>()
 
 const queryParams = ref<Partial<Model.ShareAmountQueryReq>>({
     cycletype: 0,
@@ -110,24 +110,7 @@ const dateFormat = computed(() => {
     }
 })
 
-const onTypeChange = (value: ReportType) => {
-    const dateValue = queryParams.value.tradedate
-    if (dateValue) {
-        switch (value) {
-            case ReportType.Month:
-                queryParams.value.tradedate = formatDate(dateValue, 'YYYYMM')
-                break
-            case ReportType.Quarter:
-            case ReportType.Year:
-                queryParams.value.tradedate = formatDate(dateValue, 'YYYY')
-                break
-            default:
-                queryParams.value.tradedate = formatDate(dateValue, 'YYYYMMDD')
-        }
-    }
-}
-
-const tableColumns = shallowRef<Model.TableColumn[]>([
+const tableColumns = ref<Model.TableColumn[]>([
     { field: 'areatype', label: '角色', formatValue: (val) => roleTypeEnum.getEnumTypeName(val) },
     { field: 'areaaccountid', label: '结算资金账户' },
     { field: 'goodsname', label: '商品/市场' },
@@ -143,6 +126,17 @@ const formRules: FormRules = {
     quarter: [{ required: true }],
 }
 
+// 处理日期格式
+const formatDateByCycleType = () => {
+    const dateValue = queryParams.value.tradedate
+
+    if (queryParams.value.cycletype !== ReportType.Quarter) {
+        queryParams.value.quarter = undefined
+    }
+
+    queryParams.value.tradedate = formatDate(dateValue, dateFormat.value)
+}
+
 const onSearch = (clear = false) => {
     if (clear) {
         queryParams.value = {
@@ -152,6 +146,7 @@ const onSearch = (clear = false) => {
     } else {
         formRef.value?.validate((valid) => {
             if (valid) {
+                formatDateByCycleType()
                 run(queryParams.value)
             }
         })
@@ -159,6 +154,11 @@ const onSearch = (clear = false) => {
 }
 
 const openComponentOnClick = (code: string) => {
-    openComponent(code)
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            formatDateByCycleType()
+            openComponent(code)
+        }
+    })
 }
 </script>

+ 34 - 52
src/packages/pc/views/report/trade/index.vue

@@ -2,16 +2,17 @@
 <template>
     <app-view>
         <template #header>
-            <el-form ref="formRef" class="el-form--filter" :model="queryParams" :rules="formRules" :show-message="false" >
+            <el-form ref="formRef" class="el-form--filter" :model="queryParams" :rules="formRules"
+                :show-message="false">
                 <el-form-item label="报表类型" prop="cycletype">
-                    <el-select v-model="queryParams.cycletype" >
+                    <el-select v-model="queryParams.cycletype">
                         <el-option v-for="item in getReportTypeList()" :key="item.value" :label="item.label"
                             :value="item.value" />
                     </el-select>
                 </el-form-item>
                 <el-form-item label="日期" prop="cycletime">
                     <el-date-picker :type="dateType" v-model="queryParams.cycletime" :format="dateFormat"
-                    :value-format="dateFormat" placeholder="请选择日期" @change="onTypeChange"/>
+                        placeholder="请选择" />
                 </el-form-item>
                 <el-form-item label="季度" prop="quarter" v-if="queryParams.cycletype === ReportType.Quarter">
                     <el-select v-model="queryParams.quarter">
@@ -19,21 +20,16 @@
                             :value="item.value" />
                     </el-select>
                 </el-form-item>
-                <el-form-item label="资金账户" prop="accountid">
-                    <app-select-account v-model="queryParams.userid" @change="onAccountChange" />
+                <el-form-item label="推荐账户" prop="userid">
+                    <el-input v-model="queryParams.userid" placeholder="请输入账户ID" />
                 </el-form-item>
                 <el-form-item>
-                    <el-button type="primary" @click="onSearch">查询</el-button>
-                    <el-button type="danger" @click="onSearch(false)">重置</el-button>
+                    <el-button type="primary" @click="onSearch(false)">查询</el-button>
+                    <el-button type="primary" @click="onSearch(true)">重置</el-button>
                 </el-form-item>
             </el-form>
-            <div class="report-account__info" v-if="selectedAccount">
-                <span>账户:{{ selectedAccount.relatedname }}</span>
-                <span>资金账户:{{ selectedAccount.accountid }}</span>
-                <span>登录账号:{{ selectedAccount.invloginids }}</span>
-            </div>
         </template>
-        <app-table :data="dataList" showIndex :columns="tableColumns" :loading="loading">
+        <app-table :data="dataList" :columns="tableColumns" :loading="loading">
             <template #headerLeft>
                 <app-operation :data-list="getFilteredButtons(['query_report_trade_export'])"
                     @click="openComponentOnClick" />
@@ -51,22 +47,20 @@
 <script lang="ts" setup>
 import { shallowRef, ref, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { formatDate } from '@/filters'
 import { useRequest } from '@/hooks/request'
 import { queryTrade } from '@/services/api/report'
-import { formatDate } from '@/filters'
 import { useOperation } from '@/hooks/operation'
-import { getReportTypeList, ReportType, getQuarterList  } from '@/constants/report'
+import { getReportTypeList, ReportType, getQuarterList } from '@/constants/report'
 import AppTable from '@pc/components/base/table/index.vue'
 import AppPagination from '@pc/components/base/pagination/index.vue'
 import AppOperation from '@pc/components/base/operation/index.vue'
-import AppSelectAccount from '@pc/components/modules/select-account/index.vue'
+
+const formRef = shallowRef<FormInstance>()
 
 const queryParams = ref<Partial<Model.TradeReq>>({
-    cycletype: 0,
-    cycletime: ''
+    cycletype: 0
 })
-const formRef = shallowRef<FormInstance>()
-const selectedAccount = shallowRef<Model.TAAccountChildrenSelectRsp>()
 
 const { componentMap, componentId, record, openComponent, closeComponent, getFilteredButtons } = useOperation<Model.TradeRsp>({
     onClose: () => onSearch()
@@ -77,8 +71,6 @@ const { dataList, total, pageSize, pageIndex, loading, run } = useRequest(queryT
     params: {
         pageNum: 1,
         pageSize: 20,
-        cycletype: 0,
-        cycletime: ''
     },
     onError: (err) => {
         ElMessage.error(err)
@@ -114,27 +106,6 @@ const dateFormat = computed(() => {
     }
 })
 
-const onTypeChange = (value: ReportType) => {
-    const dateValue = queryParams.value.cycletime
-    if (dateValue) {
-        switch (value) {
-            case ReportType.Month:
-            queryParams.value.cycletime = formatDate(dateValue, 'YYYY-MM')
-                break
-            case ReportType.Quarter:
-            case ReportType.Year:
-            queryParams.value.cycletime = formatDate(dateValue, 'YYYY')
-                break
-            default:
-            queryParams.value.cycletime = formatDate(dateValue, 'YYYY-MM-DD')
-        }
-    }
-}
-
-const onAccountChange = (item?: Model.TAAccountChildrenSelectRsp) => {
-    selectedAccount.value = item
-}
-
 const tableColumns = shallowRef<Model.TableColumn[]>([
     { field: 'goodsname', label: '商品代码/名称	' },
     { field: 'marketname', label: '市场' },
@@ -149,17 +120,29 @@ const tableColumns = shallowRef<Model.TableColumn[]>([
 // 表单验证规则
 const formRules: FormRules = {
     cycletime: [{ required: true }],
+    userid: [{ required: true }],
+}
+
+// 处理日期格式
+const formatDateByCycleType = () => {
+    const dateValue = queryParams.value.cycletime
+
+    if (queryParams.value.cycletype !== ReportType.Quarter) {
+        queryParams.value.quarter = undefined
+    }
+
+    queryParams.value.cycletime = formatDate(dateValue, dateFormat.value)
 }
 
 const onSearch = (clear = false) => {
-    if (!clear) {
+    if (clear) {
         queryParams.value = {
             cycletype: 0,
-            cycletime: '',
         }
     } else {
         formRef.value?.validate((valid) => {
             if (valid) {
+                formatDateByCycleType()
                 run(queryParams.value)
             }
         })
@@ -167,12 +150,11 @@ const onSearch = (clear = false) => {
 }
 
 const openComponentOnClick = (code: string) => {
-    processRequiredParams(() => openComponent(code))
-}
-
-// 处理请求参数
-const processRequiredParams = (callback: (params: Model.TradeReq) => void, clear = false) => {
-    onSearch(!clear)
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            formatDateByCycleType()
+            openComponent(code)
+        }
+    })
 }
-
 </script>

+ 79 - 2
src/services/api/investor/index.ts

@@ -53,14 +53,14 @@ export function investorExport(options: CommonFetchOptions<{ response: string; }
 /**
  * 交易商管理-->交易商管理-->查询个性化设置
  */
-export function accountQuery(options: CommonFetchOptions<{ request: Model.AccountQueryReq; response: Model.AccountQueryRsp; }> = {}) {
+export function accountQuery(options: CommonFetchOptions<{ request: Model.AccountQueryReq; response: Model.AccountQueryRsp; }>) {
     return httpClient.commonRequest('/investor/accountQuery', 'get', options)
 }
 
 /**
  * 交易商管理-->交易商管理-->登录账户列表查询-->注销停用
  */
-export function deleteAccount(options: CommonFetchOptions<{ request: Model.DeleteAccountReq; }> = {}) {
+export function deleteAccount(options: CommonFetchOptions<{ request: Model.DeleteAccountReq; }>) {
     return httpClient.commonRequest('/investor/deleteAccount', 'get', options)
 }
 
@@ -202,4 +202,81 @@ export function deleteTraderConfig(options: CommonFetchOptions<{ request: Partia
  */
 export function tradeConfigView(options: CommonFetchOptions<{ request: Model.TradeConfigViewReq; response: Model.TradeConfigViewRsp; }>) {
     return httpClient.commonRequest('/investor/tradeConfigView', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->修改
+ */
+export function investorEdit(options: CommonFetchOptions<{ request: Model.InvestorEditReq; }>) {
+    return httpClient.commonRequest('/investor/investorEdit', 'post', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->撤回变更
+ */
+export function investorRebackChange(options: CommonFetchOptions<{ request: Model.InvestorRebackChangeReq; }>) {
+    return httpClient.commonRequest('/investor/rebackChange', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->注销
+ */
+export function investorLogOff(options: CommonFetchOptions<{ request: Model.InvestorLogOffReq; }>) {
+    return httpClient.commonRequest('/investor/logOff', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->恢复
+ */
+export function investorRecover(options: CommonFetchOptions<{ request: Model.InvestorRecoverReq; }>) {
+    return httpClient.commonRequest('/investor/recover', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->资金账户-->修改
+ */
+export function investorAccountEdit(options: CommonFetchOptions<{ request: Model.InvestorAccountEditReq; }>) {
+    return httpClient.commonRequest('/investor/edit', 'post', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->登录账户列表查询
+ */
+export function queryInvestorLoginList(options: CommonFetchOptions<{ request: Model.InvestorLoginListReq; response: Model.InvestorLoginListRsp; }>) {
+    return httpClient.commonRequest('/investor/queryInvestor', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->登录账户列表查询-->查看登录流水
+ */
+export function queryLoginLog(options: CommonFetchOptions<{ request: Model.LoginLogReq; response: Model.LoginLogRsp; }>) {
+    return httpClient.commonRequest('/investor/queryLoginLog', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->登录账户列表查询-->查看手机号
+ */
+export function queryUserAuthInfo(options: CommonFetchOptions<{ request: Model.UserAuthInfoReq; response: Model.UserAuthInfoRsp; }>) {
+    return httpClient.commonRequest('/investor/queryUserAuthInfo', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->登录账户列表查询-->账号锁定、解锁
+ */
+export function lockAccount(options: CommonFetchOptions<{ request: Model.LockAccountReq; }>) {
+    return httpClient.commonRequest('/investor/lockAccount', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->登录账户列表查询-->重置密码
+ */
+export function resetPwd(options: CommonFetchOptions<{ request: Model.ResetPwdReq; }>) {
+    return httpClient.commonRequest('/investor/resetPwd', 'get', options)
+}
+
+/**
+ * 交易商管理-->交易商管理-->登录账户列表查询-->恢复
+ */
+export function restoreAccount(options: CommonFetchOptions<{ request: Model.RestoreAccountReq; }>) {
+    return httpClient.commonRequest('/investor/restoreAccount', 'get', options)
 }

+ 10 - 2
src/services/api/report/index.ts

@@ -7,7 +7,11 @@ const userStore = useUserStore()
 /**
  * 报表管理-->经纪会员报表
  */
-export function orgReportQuery(options: CommonFetchOptions<{ request: Model.OrgReportQueryReq; response: Model.OrgReportQueryRsp[]; }>) {
+export function orgReportQuery(options: CommonFetchOptions<{ request: Partial<Model.OrgReportQueryReq>; response: Model.OrgReportQueryRsp[]; }>) {
+    options.data = {
+        orgztypes: userStore.userInfo.orgztypes,
+        ...options.data
+    }
     return httpClient.commonRequest('/reportForm/orgReportQuery', 'get', options)
 }
 
@@ -89,6 +93,10 @@ export function accountppQuery(options: CommonFetchOptions<{ request: Model.Taac
 /**
  * 报表管理-->交易商资金报表
  */
-export function investorReportQuery(options: CommonFetchOptions<{ request: Model.InvestorReportReq; response: Model.InvestorReportRsp; }>) {
+export function investorReportQuery(options: CommonFetchOptions<{ request: Partial<Model.InvestorReportReq>; response: Model.InvestorReportRsp; }>) {
+    options.data = {
+        orgztypes: userStore.userInfo.orgztypes,
+        ...options.data
+    }
     return httpClient.commonRequest('/reportForm/investorReportQuery', 'get', options)
 }

+ 129 - 13
src/types/model/investor.d.ts

@@ -80,9 +80,10 @@ declare namespace Model {
     interface DetailResult {
         userAccountDetailVo: {
             accountName: string; // userAccount – 交易商名称/申请人()
-            accountStatus: number; // userAccount – 机构状态
-            auditAccountName: string; // userAccount – 审核人时间
-            auditTime: string; // userAccount – 审核人
+            accountStatus: number; // userAccount – 机构状态/modifyStatus == 2,3,4 不展示
+            auditAccountName: string; // userAccount – 审核人/modifyStatus == 2,3,4 不展示
+            auditTime: string; // userAccount – 审核人时间/modifyStatus == 2,3,4 不展示
+            auditremark: string;
             borkerName: string; // userAccount – 经纪人/为空不展示
             createName: string; // userAccount – 开户人/ openmode == 1 展示,openmode != 1 展示申请人accountName
             createTime: string; // userAccount – 开户时间
@@ -93,41 +94,57 @@ declare namespace Model {
             modifyStatus: number; // userAccount – 变更状态/固定用before
             modifyTime: string; // userAccount – 修改时间/固定用before
             parentUserName: string; // userAccount – 所属机构
+            parentuserid: number;
             refereeUserName: string; // userAccount – 推荐人/为空不展示
+            refereeuserid: number;
             userId: number; // userAccount – 交易商代码
+            usertype: number;
         };
         userinfoDetailVo: {
-            address: string; // userinfo – 通讯地址
+            address: string; // userinfo – 通讯地址/pathName+address
+            attachment1: string;
+            attachment2: string;
             bankAccount: string; // userinfo – 银行账户/银行卡信息 bankname!=NULL 展示
             bankCardFrontPhotoUrl: string; // userinfo – 银行卡正面/银行卡信息 bankname!=NULL 展示
             bankName: string; // userinfo – 银行名称/银行卡信息 bankname!=NULL 展示
-            bizNature: string; // userinfo – 企业性质/userinfotype ==2 展示
+            bankid: string;
+            bizNature: number; // userinfo – 企业性质/userinfotype ==2 展示
             cardBackPhotoUrl: string; // userinfo – 证件照反面/为空不展示
             cardFrontPhotoUrl: string; // userinfo – userinfotype = 1证件照正面 / userinfotype = 2营业执照
             cardNum: string; // userinfo – 证件号码
             cardTypeId: number; // userinfo – 证件类型/code-certificatetype
+            cityid: number;
             company: string; // userinfo – 所属公司
             contactName: string; // userinfo – 联系人/userinfotype ==2 展示
             customerName: string; // userinfo – 企业名称/userinfotype ==2 展示
+            districtid: number;
             email: string; // userinfo – 邮箱
             halfBodyPhotoUrl: string; // userinfo – 手持证件照/为空不展示
             legalCardBackPhotoUrl: string; // userinfo – 法人身份证背面照/userinfotype ==2 展示
             legalCardFrontPhotoUrl: string; // userinfo – 法人身份证正面照/userinfotype ==2 展示
             legalPersonName: string; // userinfo – 法人姓名/userinfotype ==2 展示
             mobile: string; // userinfo – 手机号
-            needInvoice: number; // userinfo – 是否需要发票/modifyStatus == 1 展示
+            needInvoice: number; // userinfo – 是否需要发票/modifyStatus == 2,3,4 不展示
             openMode: number; // userinfo – 开户方式
             otherUrl: string; // userinfo – 法人授权书/userinfotype ==2 展示
             pathName: string; // userinfo – 通迅地址
             postalCode: string; // userinfo – 邮政编码
+            provinceid: number;
+            qq: string;
             remark: string; // userinfo – 备注
-            sex: string; // userinfo – 性别
+            sex: number; // userinfo – 性别
             telPhone: string; // userinfo – 联系电话
             userinfoType: number; // userinfo – 用户类型
             wechat: string; // userinfo – 微信
         };
     }
 
+    /** 交易商管理-->交易商管理-->修改 请求 */
+    interface InvestorEditReq {
+        userAccountDetailVo: Partial<DetailResult['userAccountDetailVo']>;
+        userinfoDetailVo: Partial<DetailResult['userinfoDetailVo']>;
+    }
+
     /** 交易商管理-->开户管理-->交易商初审/复审 请求 */
     interface InvestorProcessReq {
         auditflag: number; // 审核标志 0拒绝 1通过
@@ -140,9 +157,9 @@ declare namespace Model {
     /** 交易商管理-->交易商管理-->查询个性化设置 请求 */
     interface AccountQueryReq {
         // accountid
-        accountid?: number;
+        accountid: number;
         // goodsid
-        goodsid?: number;
+        goodsid: number;
     }
 
     /** 交易商管理-->交易商管理-->查询个性化设置 响应 */
@@ -176,7 +193,7 @@ declare namespace Model {
     /** 交易商管理-->交易商管理-->登录账户列表查询-->注销停用 请求 */
     interface DeleteAccountReq {
         // loginid
-        loginid?: number;
+        loginid: number;
     }
 
     /** 交易商管理-->交易商管理-->资金账户、资金账户详情(userid不传) 请求 */
@@ -211,9 +228,7 @@ declare namespace Model {
         changeflag: number
         // 账户状态变更时间
         changetime: string
-        children: {
-            [string]: [string]
-        }[]
+        children: ShowAccountRsp[]
         // 今日平仓盈亏
         closepl: number
         // 今日授信减少
@@ -781,4 +796,105 @@ declare namespace Model {
         ruletype: number; // 参数类型 -1.保证金类 2.交易规则 3.交易费用
         usergroupid: number; // 用户分组ID(0的为会员默认设置)
     }
+
+    /** 交易商管理-->交易商管理-->撤回变更 请求 */
+    interface InvestorRebackChangeReq {
+        areaid: number;
+    }
+
+    /** 交易商管理-->交易商管理-->注销 请求 */
+    interface InvestorLogOffReq {
+        areaid: number;
+    }
+
+    /** 交易商管理-->交易商管理-->恢复 请求 */
+    interface InvestorRecoverReq {
+        areaid: number;
+    }
+
+    /** 交易商管理-->交易商管理-->资金账户-->修改 请求 */
+    interface InvestorAccountEditReq {
+        accountid: number; // accountid
+        outthreshold: number; // 出金阈值
+        parentaccountid: number; // 默认0
+        tradestatus: number; // 交易状态 1正常 4禁止建仓(人工受限) 5 禁止交易(人工冻结)
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询 请求 */
+    interface InvestorLoginListReq {
+        loginid?: string; // 登入账户
+        loginstatus?: number; // 账户状态 loginstatus
+        loginusertype?: number;
+        pageNum: number;
+        pageSize: number;
+        userid: number;
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询 响应 */
+    interface InvestorLoginListRsp {
+        loginid: number; // 登录账户
+        loginstatus: number; // 账号状态
+        modifiername: string; // 修改人
+        modifytime: string; // 修改时间
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询-->查看登录流水 请求 */
+    interface LoginLogReq {
+        loginid: number; // 登入账户
+        pageNum: number;
+        pageSize: number;
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询-->查看登录流水 响应 */
+    interface LoginLogRsp {
+        authid: string; // 三方认证ID
+        authtype: number; // 三方认证类型 - 1:微信 2:支付宝
+        clienttype: number; // 客户端类型 - 0:保留为未填终端类型 1:PC管理端 2:PC交易端 3:手机客户端安卓 4:网页客户端 5:微信客户端 6:手机客户端苹果 7:网上开户客户端 8:无效终端编号 9:报价终端(中江)
+        deviceid: string; // 登录设备信息
+        environmentinfo: string; // 登录软件环境信息
+        funcode: number; // 功能号
+        loginflowno: number; // 登录流水号(AutoID)
+        loginid: number; // 登陆账号
+        loginip: string; // 登录IP地址
+        loginport: number; // 登录端口
+        loginretcode: number; // 登录结果-0:成功、非0均为失败
+        logintype: number; // 登录类型 - 1:账号登录 2:手机号登录 3:三方登录
+        operatetime: string; // 操作时间
+        operatetype: number; // 操作类型-1:人工操作、2:系统操作
+        remark: string; // 备注
+        softversion: string; // 软件版本
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询-->查看手机号 请求 */
+    interface UserAuthInfoReq {
+        loginid: number;
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询-->查看手机号 响应 */
+    interface UserAuthInfoRsp {
+        authid: string; // 三方认证IID - 手机号时存储加密串
+        authname: string; // 三方认证I昵称
+        authtype: number; // 三方认证类型 - 1:微信 2:支付宝 3:手机号 4:管理员账号
+        bindname: string;
+        isvalid: number; // 是否有效 - 0:无效 1:有效
+        loginid: number; // 登陆账号
+        opentype: string;
+        userid: number; // 用户ID
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询-->账号锁定、解锁 请求 */
+    interface LockAccountReq {
+        loginid: number;
+        status: number;
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询-->重置密码 请求 */
+    interface ResetPwdReq {
+        loginid: number;
+    }
+
+    /** 交易商管理-->交易商管理-->登录账户列表查询-->恢复 请求 */
+    interface RestoreAccountReq {
+        loginid: number;
+    }
 }

+ 31 - 31
src/types/model/report.d.ts

@@ -13,18 +13,18 @@ declare namespace Model {
 
     /** 报表管理-->经纪会员报表 请求 */
     interface OrgReportQueryReq {
-        accountid?: number  // 所属机构
-        changeflag?: number
-        cycletype?: number  // 报表类型
+        accountid: number  // 所属机构
+        changeflag: number
+        cycletype: number  // 报表类型
         orgztypes: string  // 管理员所属机构角色类型
-        pageNum?: number  // 页码
-        pageSize?: number  // 页大小
-        quarter?: number // 开始季度
-        quarterend?: number // 结束季度
-        reckondate?: string // 开始时间
-        reckondateend?: string // 结束时间
-        type?: number // 是否包括子机构 0否 1是
-        userid?: number
+        pageNum: number  // 页码
+        pageSize: number  // 页大小
+        quarter: number // 开始季度
+        quarterend: number // 结束季度
+        reckondate: string // 开始时间
+        reckondateend: string // 结束时间
+        type: number // 是否包括子机构 0否 1是
+        userid: number
     }
 
     /** 报表管理-->经纪会员报表 响应 */
@@ -278,45 +278,45 @@ declare namespace Model {
     /** 报表管理-->交易商资金报表 请求 */
     interface InvestorReportReq {
         // 交易商
-        accountid?: number
+        accountid: number
         // 所属经纪人
-        brokerid?: number
+        brokerid: number
         // 
-        changeflag?: number
+        changeflag: number
         // 报表类型
-        cycletype?: number
+        cycletype: number
         // 
-        flag?: number
+        flag: number
         // 入金金额
-        inamount?: number
+        inamount: number
         // 所属会员
-        memberid?: number
+        memberid: number
         // 管理员所属机构角色类型
-        orgztypes?: string
+        orgztypes: string
         // 出金金额
-        outamount?: number
+        outamount: number
         // 页码
-        pageNum?: number
+        pageNum: number
         // 页大小
-        pageSize?: number
+        pageSize: number
         // 
-        parentuserid?: number
+        parentuserid: number
         // 开始季度
-        quarter?: number
+        quarter: number
         // 结束季度
-        quarterend?: number
+        quarterend: number
         // 开始时间
-        reckondate?: string
+        reckondate: string
         // 结束时间
-        reckondateend?: string
+        reckondateend: string
         // 排序
-        sortField?: number
+        sortField: number
         // 排序 1 降序 0 升序
-        sortType?: number
+        sortType: number
         // 所属子机构
-        subareaid?: number
+        subareaid: number
         // 
-        usertype?: number
+        usertype: number
     }
 
     /** 报表管理-->交易商资金报表 响应 */

+ 2 - 0
src/types/model/user.d.ts

@@ -26,6 +26,8 @@ declare global {
         interface LoginInRsp {
             releType: number;
             orgztypes: string;
+            logincode: string;
+            username: string;
         }
 
         /** 获取菜单列表信息 响应 */

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels