li.shaoyi 2 년 전
부모
커밋
9ca4f00771

+ 1 - 1
app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "trading",
-  "version": "1.0.8",
+  "version": "1.0.1",
   "main": "main.js",
   "dependencies": {
     "electron-updater": "^6.1.4",

+ 1 - 1
public/config/appconfig.json

@@ -1,6 +1,6 @@
 {
   "appId": "com.muchinfo.app",
-  "appName": "多元世纪",
+  "appName": "多元世纪交易中心",
   "version": "1.0.5",
   "versionCode": "10005",
   "apiUrl": "http://192.168.31.204:8080/cfg?key=test_204",

+ 7 - 7
public/config/router.json

@@ -316,6 +316,13 @@
                                 "title": "中远期挂牌",
                                 "code": "market_trade_goods_50102",
                                 "component": "views/market/trade/goods/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 3,
+                                "title": "全款挂牌",
+                                "code": "market_trade_goods_16201",
+                                "component": "views/market/trade/goods/list/index.vue"
                             }
                         ]
                     },
@@ -341,13 +348,6 @@
                                 "title": "定金转让",
                                 "code": "market_trade_presell_49201",
                                 "component": "views/market/trade/presell/transfer/index.vue"
-                            },
-                            {
-                                "authType": 2,
-                                "sort": 3,
-                                "title": "全款挂牌",
-                                "code": "market_trade_goods_16201",
-                                "component": "views/market/trade/goods/list/index.vue"
                             }
                         ]
                     },

+ 1 - 1
public/manifest.json

@@ -155,7 +155,7 @@
                 ],
                 "abiFilters" : [ "armeabi-v7a", "arm64-v8a" ],
                 "autoSdkPermissions" : false,
-                "minSdkVersion" : 26
+                "minSdkVersion" : 30
             },
             /*使用Native.js调用原生安卓API需要使用到的系统权限*/
             "orientation" : [ "portrait-primary" ],

+ 1 - 1
src/hooks/hqchart/candlestick/dataset.ts

@@ -10,7 +10,7 @@ export function useDataset(goodsCode: string, cycleType = ChartCycleType.Minutes
 
     const state = reactive({
         loading: false,
-        symbol: '',
+        symbol: '000000.et',
         cycleType
     })
 

+ 28 - 24
src/hooks/hqchart/timeline/dataset.ts

@@ -9,7 +9,7 @@ export function useDataset(goodsCode: string) {
 
     const state = reactive({
         loading: false,
-        symbol: ''
+        symbol: '000000.et'
     })
 
     // 获取历史行情
@@ -80,29 +80,33 @@ export function useDataset(goodsCode: string) {
         data.PreventDefault = true
         if (data.Name === 'MinuteChartContainer::RequestMinuteData') {
             getTSDataAsync.then((res) => {
-                const [lastItem] = res.data.historyDatas.slice(-1)
-                cache.value = res.data
-                state.symbol = data.Request.Data.symbol[0]
-                callback({
-                    stock: [
-                        {
-                            symbol: state.symbol,
-                            yclose: res.data.preSettle,
-                            date: Number(moment(lastItem.ts).format('YYYYMMDD')),
-                            time: Number(moment(lastItem.ts).format('HHmm')),
-                            minute: res.data.historyDatas.map((e) => ({
-                                price: e.c,
-                                open: e.o || null,
-                                high: e.h || null,
-                                low: e.l || null,
-                                vol: e.tv,
-                                amount: e.tt || null,
-                                date: Number(moment(e.ts).format('YYYYMMDD')),
-                                time: Number(moment(e.ts).format('HHmm')),
-                            }))
-                        }
-                    ]
-                })
+                if (res.data.historyDatas.length) {
+                    const [lastItem] = res.data.historyDatas.slice(-1)
+                    cache.value = res.data
+                    state.symbol = data.Request.Data.symbol[0]
+                    callback({
+                        stock: [
+                            {
+                                symbol: state.symbol,
+                                yclose: res.data.preSettle,
+                                date: Number(moment(lastItem.ts).format('YYYYMMDD')),
+                                time: Number(moment(lastItem.ts).format('HHmm')),
+                                minute: res.data.historyDatas.map((e) => ({
+                                    price: e.c,
+                                    open: e.o || null,
+                                    high: e.h || null,
+                                    low: e.l || null,
+                                    vol: e.tv,
+                                    amount: e.tt || null,
+                                    date: Number(moment(e.ts).format('YYYYMMDD')),
+                                    time: Number(moment(e.ts).format('HHmm')),
+                                }))
+                            }
+                        ]
+                    })
+                } else {
+                    callback({ stock: [] })
+                }
             })
         } else {
             callback({ stock: [] })

+ 2 - 1
src/hooks/hqchart/timeline/types.ts

@@ -15,7 +15,7 @@ export interface NetworkFilterData {
     }
 }
 
-// https://blog.csdn.net/jones2000/article/details/100149703
+// https://blog.csdn.net/jones2000/article/details/100132357
 export interface RequestData {
     name?: string; // 股票名称
     symbol: string; // 股票代码
@@ -34,6 +34,7 @@ export interface RequestData {
     before?: []; // 集合竞价数据
 }
 
+// https://blog.csdn.net/jones2000/article/details/100149703
 export interface MinuteData {
     price: number; // 价格
     open: number | null; // 开盘价

+ 14 - 9
src/packages/mobile/components/modules/hqchart/candlestick/index.less

@@ -4,6 +4,7 @@
     flex-direction: column;
     height: 8rem;
     overflow: hidden;
+    padding:0 .1rem;
 
     .app-hqchart {
         flex: 1;
@@ -12,25 +13,29 @@
     .app-tabs--indicator {
         .tabs {
             width: 100%;
-            font-size: 12px;
-            border-top: 1px solid #22292c;
-            padding: 1px;
+            font-size: .24rem;
+            border: 1px solid #f6f6f6;
+            border-left: 0;
+            border-right: 0;
+            padding: .1rem;
 
             &-item {
+                flex: 1;
                 z-index: 1;
                 display: flex;
                 justify-content: center;
                 align-items: center;
-                color: #7a8a94;
+                color: #222;
                 cursor: pointer;
-                padding: 5px 16px;
+                padding: .16rem 0;
 
-                &:hover {
-                    background-color: #181E22;
+                &:not(:first-child) {
+                    margin-left: 0;
                 }
 
-                &.is-active {
-                    color: #0D96FF;
+                &:not(.is-active) {
+                    color: #7a8a94;
+                    background-color: transparent;
                 }
             }
         }

+ 31 - 8
src/packages/mobile/components/modules/hqchart/candlestick/index.vue

@@ -8,10 +8,12 @@
 <script lang="ts" setup>
 import { shallowRef, watch, computed } from 'vue'
 import { Chart } from 'hqchart'
+import { changeUnit } from '@/filters'
 import { ChartCycleType } from '@/constants/chart'
 import { useFuturesStore } from '@/stores'
 import { useDataset } from '@/hooks/hqchart/candlestick/dataset'
 import { NetworkFilterData, NetworkFilterCallback } from '@/hooks/hqchart/candlestick/types'
+import { KLineChartContainer } from './types'
 import HQChart from '@/components/base/hqchart/index.vue'
 import Tabs from '@/components/base/tabs/index.vue'
 
@@ -40,10 +42,7 @@ const tabs = [
     { label: 'MACD', value: 'MACD' },
     { label: 'KDJ', value: 'KDJ' },
     { label: 'RSI', value: 'RSI' },
-    { label: 'WR', value: 'WR' },
-    { label: 'OBV', value: 'OBV' },
-    { label: 'CCI', value: 'CCI' },
-    { label: 'DMI', value: 'DMI' }
+    { label: 'CCI', value: 'CCI' }
 ]
 
 // 自定义品种小数位
@@ -55,6 +54,10 @@ const period = computed(() => {
     switch (props.cycleType) {
         case ChartCycleType.Day:
             return 0
+        case ChartCycleType.Week:
+            return 1
+        case ChartCycleType.Month:
+            return 2
         case ChartCycleType.Minutes:
             return 4
         case ChartCycleType.Minutes5:
@@ -87,7 +90,8 @@ const chartOption = {
     // https://blog.csdn.net/jones2000/article/details/97682466
     CorssCursorInfo: {
         Left: 0,
-        Right: 1,
+        Right: 0,
+        HPenType: -1
     },
     Border: {
         Left: 0,
@@ -112,14 +116,15 @@ const chartOption = {
     KLineTitle:
     {
         IsShowName: false, // 不显示股票名称
-        IsShowSettingInfo: false // 不显示周期/复权
+        IsShowSettingInfo: false, // 不显示周期/复权
+        IsShow: true // 是否显示标题
     },
     Frame: [
         {
             Custom: [
                 {
                     Type: 0,
-                    Position: 'right',
+                    Position: 'left',
                 }
             ],
             IsShowRightText: false // 是否显示Y轴右侧刻度
@@ -127,7 +132,25 @@ const chartOption = {
         {
             IsShowRightText: false // 是否显示Y轴右侧刻度
         }
-    ]
+    ],
+    OnCreatedCallback: (chart: KLineChartContainer) => {
+        const paint = chart.TitlePaint[0]
+        if (paint) {
+            // 自定义标题栏,参考源码 DynamicKLineTitlePainting.GetFormatTitle
+            paint.GetFormatTitle = (data) => {
+                const { Open, High, Low, Close, Vol, YClose } = data.Data
+                return {
+                    AryText: [
+                        { Text: '开:' + Open, Color: paint.GetColor(Open, YClose) },
+                        { Text: '高:' + High, Color: paint.GetColor(High, YClose) },
+                        { Text: '低:' + Low, Color: paint.GetColor(Low, YClose) },
+                        { Text: '收:' + Close, Color: paint.GetColor(Close, YClose) },
+                        { Text: '量:' + changeUnit(Vol), Color: paint.VolColor }
+                    ]
+                }
+            }
+        }
+    }
 }
 
 // 切换指标

+ 27 - 0
src/packages/mobile/components/modules/hqchart/candlestick/types.ts

@@ -0,0 +1,27 @@
+export interface KLineChartContainer {
+    TitlePaint: {
+        GetColor: (price: number, yclose: number) => string;
+        GetFormatTitle: (data: FormatTitleData) => FormatTitleReturn;
+        AmountColor: string;
+        VolColor: string;
+        PositionColor: string;
+    }[]
+}
+
+export interface FormatTitleData {
+    Data: {
+        Open: number;
+        High: number;
+        Low: number;
+        Close: number;
+        YClose: number;
+        Vol: number;
+    }
+}
+
+export interface FormatTitleReturn {
+    AryText: {
+        Text: string;
+        Color: string;
+    }[]
+}

+ 43 - 0
src/packages/mobile/components/modules/hqchart/timeline/index.less

@@ -0,0 +1,43 @@
+.app-candlestick {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    height: 8rem;
+    overflow: hidden;
+    padding:0 .1rem;
+
+    .app-hqchart {
+        flex: 1;
+    }
+
+    .app-tabs--indicator {
+        .tabs {
+            width: 100%;
+            font-size: .24rem;
+            border: 1px solid #f6f6f6;
+            border-left: 0;
+            border-right: 0;
+            padding: .1rem;
+
+            &-item {
+                flex: 1;
+                z-index: 1;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                color: #222;
+                cursor: pointer;
+                padding: .1rem .2rem;
+
+                &:not(:first-child) {
+                    margin-left: 0;
+                }
+
+                &:not(.is-active) {
+                    color: #7a8a94;
+                    background-color: transparent;
+                }
+            }
+        }
+    }
+}

+ 24 - 9
src/packages/mobile/components/modules/hqchart/timeline/index.vue

@@ -1,5 +1,7 @@
 <template>
-    <HQChart @ready="onReady" default-theme="Dark" />
+    <div class="app-candlestick">
+        <HQChart @ready="onReady" />
+    </div>
 </template>
 
 <script lang="ts" setup>
@@ -36,11 +38,17 @@ const chartOption = {
     Type: '分钟走势图',
     IsAutoUpdate: false,
     NetworkFilter: (data: NetworkFilterData, callback: NetworkFilterCallback) => networkFilter(data, callback),
-    IsShowCorssCursorInfo: true,
+    CorssCursorTouchEnd: true, // 手指离开屏幕 隐藏十字光标
+    // https://blog.csdn.net/jones2000/article/details/97682466
+    CorssCursorInfo: {
+        Left: 0,
+        Right: 0,
+        HPenType: -1
+    },
     DayCount: 1,
     Border: {
-        Left: 80,
-        Right: 80,
+        Left: 0,
+        Right: 0,
         Top: 30,
         Bottom: 25,
         AutoLeft: { Blank: 15, MinWidth: 30 },
@@ -49,9 +57,10 @@ const chartOption = {
     MinuteLine: {
         IsShowAveragePrice: false, // 不显示均线
     },
-    MinuteLineTitle:
+    MinuteTitle:
     {
         IsShowName: false, // 不显示股票名称
+        IsShowTime: false,
     },
     Frame: [
         // {
@@ -71,13 +80,15 @@ const chartOption = {
 const onReady = (chart: unknown) => {
     chartInstance.value = chart
     getTSDataAsync.then(() => {
-        // https://blog.csdn.net/jones2000/article/details/105587559
+        // https://blog.csdn.net/jones2000/article/details/104165374
         const minuteTimeStringData = Chart.JSChart.GetMinuteTimeStringData()
         const minuteCoordinateData = Chart.JSChart.GetMinuteCoordinateData()
+        // 当天所有的交易时间点
+        minuteTimeStringData.GetET = () => minuteTimeStringData.CreateTimeData(timeSplit.value)
         // 替换交易时间段
-        minuteTimeStringData.CreateSHSZData = () => minuteTimeStringData.CreateTimeData(timeSplit.value)
+        minuteTimeStringData.CreateETData = () => minuteTimeStringData.GetET()
         // 替换X轴刻度信息
-        minuteCoordinateData.GetSHSZData = () => handleXAxisScale(minuteTimeStringData.CreateSHSZData())
+        minuteCoordinateData.GetETData = () => handleXAxisScale(minuteTimeStringData.GetET())
         chartInstance.value.SetOption(chartOption)
     })
 }
@@ -90,4 +101,8 @@ quoteWatch(props.goodsCode, (q) => {
         JSChartContainer.RecvMinuteData(data)
     }
 })
-</script>
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 3 - 2
src/packages/mobile/components/modules/quote/chart/index.vue

@@ -16,7 +16,7 @@
             </Tabs>
             <Icon name="setting-o" style="padding: 0 .32rem;" v-if="false" />
         </div>
-        <TimeLine v-bind="{ goodsCode }" v-if="tabIndex === 0" />
+        <TimeLine v-bind="{ symbol, goodsCode }" v-if="tabIndex === 0" />
         <KLine v-bind="{ symbol, goodsCode, cycleType }" v-else />
     </div>
 </template>
@@ -27,6 +27,7 @@ import { Tab, Tabs, Popover, Icon, PopoverAction } from 'vant'
 import { ChartCycleType } from '@/constants/chart'
 import TimeLine from './timeline/index.vue'
 import KLine from './kline/index.vue'
+import MLine from '../../hqchart/timeline/index.vue'
 //import KLine from '../../hqchart/candlestick/index.vue'
 
 defineProps({
@@ -36,7 +37,7 @@ defineProps({
     }
 })
 
-const symbol = '600000.sh' // 股票代码
+const symbol = '000000.et' // https://blog.csdn.net/jones2000/article/details/104457569
 const tabIndex = shallowRef(0) // 当前选中的标签
 const selectedText = shallowRef('') // 当前选中的分钟线
 const cycleType = shallowRef(ChartCycleType.Minutes) // 图表周期类型

+ 20 - 4
src/packages/mobile/views/bank/sign/components/edit/Index.vue

@@ -32,8 +32,9 @@
                         </template>
                         <template v-else-if="(item.fieldcode === 'bank_branch_name')">
                             <Field v-if="showExtendInfo(item)" name="OpenBankName" :label="item.fieldname"
-                                v-model="item.value" maxlength="50" :placeholder="`请输入${item.fieldname}`"
-                                :rules="formRules.OpenBankName" @click-right-icon="showSearch = true" />
+                                v-model="item.value" maxlength="50" right-icon="search"
+                                :placeholder="`请输入${item.fieldname}`" :rules="formRules.OpenBankName"
+                                @click-right-icon="showSearch = true" />
                         </template>
                         <template v-else-if="(item.fieldcode === '100')">
                             <Field v-if="showExtendInfo(item)" name="OpenBankNo" :label="item.fieldname"
@@ -125,8 +126,23 @@ const sendVerifyCode = () => {
     })
 }
 
-const onBankChange = (value: string) => {
-    console.log(value)
+const onBankChange = (item: Model.BankBranChnumInfoRsp) => {
+    configs.value.forEach((e) => {
+        switch (e.fieldcode) {
+            case 'bank_branch_name':
+                e.value = item.branchname
+                break
+            case '100':
+                e.value = item.branchnum
+                break
+            case '101':
+                e.value = item.branchprovince
+                break
+            case '102':
+                e.value = item.branchcity
+                break
+        }
+    })
 }
 
 // 表单验证规则

+ 42 - 4
src/packages/mobile/views/bank/sign/components/edit/search/index.vue

@@ -10,14 +10,28 @@
                     </template>
                 </app-navbar>
             </template>
-            <Empty description="暂无数据" />
+            <RadioGroup v-model="checked" style="padding-bottom: 1rem;" v-if="dataList.length">
+                <CellGroup title="选择支行">
+                    <template v-for="(item, index) in dataList" :key="index">
+                        <Cell :title="item.branchname" :label="item.branchnum" clickable @click="onChange(item)">
+                            <template #icon>
+                                <Radio :name="item" style="padding: 0 .2rem;" />
+                            </template>
+                        </Cell>
+                    </template>
+                </CellGroup>
+            </RadioGroup>
+            <Empty description="暂无数据" v-else />
         </app-view>
     </app-modal>
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, computed } from 'vue'
-import { Form, Search, Empty } from 'vant'
+import { shallowRef, computed,toRaw } from 'vue'
+import { Form, Search, Empty, Cell, CellGroup, RadioGroup, Radio } from 'vant'
+import { fullloading } from '@/utils/vant'
+import { useRequest } from '@/hooks/request'
+import { queryBankBranChnumInfo } from '@/services/api/bank'
 import AppModal from '@/components/base/modal/index.vue'
 
 const props = defineProps({
@@ -29,13 +43,37 @@ const props = defineProps({
 
 const emit = defineEmits(['update:show', 'change'])
 const keyword = shallowRef('')
+const checked = shallowRef<Model.BankBranChnumInfoRsp>()
 
 const showModal = computed({
     get: () => props.show,
     set: (val) => emit('update:show', val)
 })
 
+const { dataList, runAsync } = useRequest(queryBankBranChnumInfo, {
+    manual: true,
+    params: {
+        pagesize: 30
+    }
+})
+
 const onSearch = (val: string) => {
-    console.log(val)
+    if (val.length >= 3) {
+        fullloading((hideLoading) => {
+            runAsync({
+                branchname: val
+            }).then((res) => {
+                dataList.value = res.data
+            }).finally(() => {
+                hideLoading()
+            })
+        }, '搜索中...')
+    }
+}
+
+const onChange = (item: Model.BankBranChnumInfoRsp) => {
+    checked.value = item
+    showModal.value = false
+    emit('change', toRaw(item))
 }
 </script>

+ 5 - 5
src/packages/mobile/views/order/inout/components/add/search/index.vue

@@ -10,12 +10,12 @@
                     </template>
                 </app-navbar>
             </template>
-            <RadioGroup v-model="checked" v-if="dataList.length">
-                <CellGroup title="选择客户" inset>
+            <RadioGroup v-model="checked" style="padding-bottom: 1rem;" v-if="dataList.length">
+                <CellGroup title="选择客户">
                     <template v-for="(item, index) in dataList" :key="index">
                         <Cell :title="item.customername" clickable @click="onChange(item)">
-                            <template #right-icon>
-                                <Radio :name="item.userid" />
+                            <template #icon>
+                                <Radio :name="item.userid" style="padding: 0 .2rem;" />
                             </template>
                         </Cell>
                     </template>
@@ -57,7 +57,7 @@ const { dataList, runAsync } = useRequest(getUserInfo, {
 })
 
 const onSearch = (val: string) => {
-    if (val) {
+    if (val.length > 3) {
         fullloading((hideLoading) => {
             runAsync({
                 param: val

+ 7 - 1
src/packages/pc/components/layouts/page/index.vue

@@ -53,6 +53,10 @@
             <span>{{ loginStore.loginId }}</span>
           </li>
           <li>
+            <span>风险率:</span>
+            <span>{{ parsePercent(accountStore.currentAccount.hazardRatio) }}</span>
+          </li>
+          <li>
             <!-- <span>{{ serverTime?.format('MM/DD') }}</span> -->
             <span>{{ serverTime?.format('HH:mm:ss') }}</span>
           </li>
@@ -66,8 +70,9 @@
 import { ref, onMounted, onUnmounted, computed } from 'vue'
 import { RouteRecordNormalized, RouteRecordName } from 'vue-router'
 import { timerTask } from '@/utils/timer'
+import { parsePercent } from '@/filters'
 import { getServerTime } from '@/services/api/common'
-import { useGlobalStore, useLoginStore } from '@/stores'
+import { useGlobalStore, useLoginStore, useAccountStore } from '@/stores'
 import eventBus from '@/services/bus'
 import moment, { Moment } from 'moment'
 import AppIcon from '@pc/components/base/icon/index.vue'
@@ -78,6 +83,7 @@ import AppSidebar from '../sidebar/index.vue'
 
 const globalStore = useGlobalStore()
 const loginStore = useLoginStore()
+const accountStore = useAccountStore()
 const fullLoading = ref(false)
 const isCollapse = ref(globalStore.isMobile)
 const footerWinType = ref(0) // -1最小化,0默认,1最大化

+ 1 - 1
src/packages/pc/components/modules/hqchart/index.vue

@@ -20,7 +20,7 @@ defineProps({
     }
 })
 
-const symbol = '600000.sh' // 股票代码
+const symbol = '000000.et' // https://blog.csdn.net/jones2000/article/details/104457569
 const cycleType = shallowRef(ChartCycleType.Time) // 图表周期类型
 const dataList = getChartCycleTypeList()
 

+ 5 - 3
src/packages/pc/components/modules/hqchart/timeline/index.vue

@@ -71,13 +71,15 @@ const chartOption = {
 const onReady = (chart: unknown) => {
     chartInstance.value = chart
     getTSDataAsync.then(() => {
-        // https://blog.csdn.net/jones2000/article/details/105587559
+        // https://blog.csdn.net/jones2000/article/details/104165374
         const minuteTimeStringData = Chart.JSChart.GetMinuteTimeStringData()
         const minuteCoordinateData = Chart.JSChart.GetMinuteCoordinateData()
+        // 当天所有的交易时间点
+        minuteTimeStringData.GetET = () => minuteTimeStringData.CreateTimeData(timeSplit.value)
         // 替换交易时间段
-        minuteTimeStringData.CreateSHSZData = () => minuteTimeStringData.CreateTimeData(timeSplit.value)
+        minuteTimeStringData.CreateETData = () => minuteTimeStringData.GetET()
         // 替换X轴刻度信息
-        minuteCoordinateData.GetSHSZData = () => handleXAxisScale(minuteTimeStringData.CreateSHSZData())
+        minuteCoordinateData.GetETData = () => handleXAxisScale(minuteTimeStringData.GetET())
         chartInstance.value.SetOption(chartOption)
     })
 }

+ 153 - 102
src/packages/pc/views/account/sign/components/sign/index.vue

@@ -1,7 +1,7 @@
 <!-- 账户管理-签约账号管理-签约 -->
 <template>
-    <app-drawer :title="bankInfo?.signstatus != undefined ? '修改签约账户' : '添加签约账户'" :width="800" v-model:show="show" :loading="loading"
-        :refresh="refresh">
+    <app-drawer :title="bankInfo?.signstatus != undefined ? '修改签约账户' : '添加签约账户'" :width="800" v-model:show="show"
+        :loading="loading" :refresh="refresh">
         <el-form ref="formRef" class="el-form--horizontal" label-width="120px" :model="formData" :rules="formRules">
             <el-form-item label="开户银行" prop="OpenBankAccId">
                 <el-select v-model="formData.OpenBankAccId">
@@ -9,21 +9,24 @@
                 </el-select>
             </el-form-item>
             <el-form-item label="银行卡号" prop="BankAccountNo">
-                <el-input type="number" name="BankAccountNo" placeholder="银行卡号" :maxlength="30" v-model="formData.BankAccountNo"
-                    :rules="formRules.BankAccountNo" />
+                <el-input type="number" name="BankAccountNo" placeholder="银行卡号" :maxlength="30"
+                    v-model="formData.BankAccountNo" :rules="formRules.BankAccountNo" />
             </el-form-item>
             <el-form-item label="名称" prop="AccountName">
                 <el-input name="AccountName" readonly placeholder="银行卡账户名" v-model="formData.AccountName"
                     :rules="formRules.AccountName" />
             </el-form-item>
             <el-form-item label="手机号码" prop="MobilePhone">
-                <el-input name="MobilePhone" :readonly="userStore.userInfo?.mobile2 != ''" maxlength="50" placeholder="请输入手机号码" v-model="formData.MobilePhone" />
+                <el-input name="MobilePhone" :readonly="userStore.userInfo?.mobile2 != ''" maxlength="50"
+                    placeholder="请输入手机号码" v-model="formData.MobilePhone" />
             </el-form-item>
+        </el-form>
+        <el-form ref="extendRef" class="el-form--horizontal" label-width="120px" :model="extendModel" :rules="formRules">
             <template v-for="(item, index) in configs" :key="index">
                 <template v-if="(item.fieldcode === 'verify_code')">
-                    <el-form-item :label="item.fieldname" :prop="item.fieldcode" 
-                    v-if="bankInfo === undefined && showExtendInfo(item)">
-                        <el-input placeholder="请必须输入" type="number" v-model="item.value" :rules="formRules.vcode">
+                    <el-form-item :label="item.fieldname" :prop="item.fieldcode"
+                        v-if="bankInfo === undefined && showExtendInfo(item)">
+                        <el-input placeholder="请输入" type="number" v-model="item.value" :rules="formRules.vcode">
                             <template #append>
                                 <el-button size="small" type="primary" :disabled="isCountdown" @click="sendVerifyCode">
                                     <span v-if="isCountdown">重新发送({{ seconds }})</span>
@@ -34,21 +37,24 @@
                     </el-form-item>
                 </template>
                 <template v-else-if="(item.fieldcode === 'bank_branch_name')">
-                    <el-form-item :label="item.fieldname" prop="OpenBankName"
-                            v-if="showExtendInfo(item)">
-                        <el-input maxlength="50" :name="item.fieldcode" placeholder="请必须输入" v-model="item.value" />
+                    <el-form-item :label="item.fieldname" :prop="item.fieldcode" v-if="showExtendInfo(item)">
+                        <el-select placeholder="请输入" v-model="item.value" value-key="branchnum" :loading="searchLoading"
+                            :remote-method="remoteMethod" filterable remote clearable allow-create @change="onBankChange">
+                            <template v-for="(item, index) in dataList" :key="index">
+                                <el-option :label="item.branchname" :value="item" />
+                            </template>
+                        </el-select>
                     </el-form-item>
                 </template>
                 <template v-else-if="(item.fieldcode === '100')">
-                    <el-form-item :label="item.fieldname" prop="OpenBankNo"
-                            v-if="showExtendInfo(item)">
-                        <el-input maxlength="50" :name="item.fieldcode" placeholder="请必须输入" v-model="item.value" />
+                    <el-form-item :label="item.fieldname" :prop="item.fieldcode" v-if="showExtendInfo(item)">
+                        <el-input maxlength="50" placeholder="请f输入" v-model="item.value" />
                     </el-form-item>
                 </template>
                 <template v-else>
-                    <el-form-item :label="item.fieldname" :prop="item.fieldcode"
-                            v-if="showExtendInfo(item)">
-                        <el-input :readonly="item.fieldcode === 'legal_name' && userStore.userInfo?.legalpersonname != ''" maxlength="50" :name="item.fieldcode" placeholder="请必须输入" v-model="item.value" />
+                    <el-form-item :label="item.fieldname" :prop="item.fieldcode" v-if="showExtendInfo(item)">
+                        <el-input :readonly="item.fieldcode === 'legal_name' && userStore.userInfo?.legalpersonname != ''"
+                            maxlength="50" placeholder="请输入" v-model="item.value" />
                     </el-form-item>
                 </template>
             </template>
@@ -61,11 +67,12 @@
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue'
-import { ElMessage } from 'element-plus'
-import type { FormInstance, FormRules } from 'element-plus'
-import { useDoBankSign, useDoCusBankExtendConfigs, useT2bSMSVerificationCode } from '@/business/bank'
+import { ref, computed } from 'vue'
+import { ElMessage, FormInstance, FormRules } from 'element-plus'
 import { validateRules } from '@/constants/regex'
+import { useRequest } from '@/hooks/request'
+import { queryBankBranChnumInfo } from '@/services/api/bank'
+import { useDoBankSign, useDoCusBankExtendConfigs, useT2bSMSVerificationCode } from '@/business/bank'
 import { useUserStore } from '@/stores'
 import service from '@/services'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
@@ -79,57 +86,98 @@ const userStore = useUserStore()
 const show = ref(true)
 const refresh = ref(false)
 const formRef = ref<FormInstance>()
+const extendRef = ref<FormInstance>()
 const seconds = ref(60) //倒计时剩余时间
 const isCountdown = ref(false) // 是否正在倒计时
 /// 短信验证码交易中心信息
 const CenterErrMsg = shallowRef('')
 
-const formRules: FormRules = {
-    OpenBankAccId: [{
-        message: '请选择银行信息',
-        validator: () => {
-            return !!formData.OpenBankAccId
+// 表单数据对象
+const extendModel = computed(() => {
+    const obj = Object.create(null)
+    configs.value.forEach((e) => {
+        if (e.fieldcode) {
+            obj[e.fieldcode] = e.value
         }
-    }],
-    BankAccountNo: [{
-        required: true,
-        message: '请输入银行卡账号'
-    }],
-    MobilePhone: [{
-        required: true,
-        message: '请输入手机号码',
-        validator: (rule, value, callback) => {
-            if (validateRules.phone.validate(value)) {
-                callback()
-            } else {
-                callback(new Error(validateRules.phone.message))
+    })
+    return obj
+})
+
+const formRules = computed(() => {
+    const rules: FormRules = {
+        OpenBankAccId: [{
+            message: '请选择银行信息',
+            validator: () => {
+                return !!formData.OpenBankAccId
             }
+        }],
+        BankAccountNo: [{
+            required: true,
+            message: '请输入银行卡账号'
+        }],
+        MobilePhone: [{
+            required: true,
+            message: '请输入手机号码',
+            validator: (rule, value, callback) => {
+                if (validateRules.phone.validate(value)) {
+                    callback()
+                } else {
+                    callback(new Error(validateRules.phone.message))
+                }
+            }
+        }],
+        AccountName: [{
+            required: true,
+            message: '请输入行卡账户名',
+        }]
+    }
+    configs.value.forEach((e) => {
+        if (e.fieldcode) {
+            rules[e.fieldcode] = [{
+                required: true,
+                message: '请输入' + e.fieldname,
+            }]
         }
-    }],
-    AccountName: [{
-        required: true,
-        message: '请输入行卡账户名',
-    }],
-    OpenBankName: [{
-        required: true,
-        message: '请输入开户行支行名称',
-    }],
-    OpenBankNo: [{
-        required: true,
-        message: '请输入开户行支行号',
-    }],
-    legal_name: [{
-        required: true,
-        message: '请输入法人姓名',
-    }],
-    agent_name: [{
-        required: true,
-        message: '请输入经办人姓名',
-    }],
-    business_num_addr: [{
-        required: true,
-        message: '请输入营业执照地址',
-    }]
+    })
+    return rules
+})
+
+const { loading: searchLoading, dataList, runAsync: searchBankBranChnumInfo } = useRequest(queryBankBranChnumInfo, {
+    manual: true,
+    params: {
+        pagesize: 30
+    }
+})
+
+// 远程搜索银行支行
+const remoteMethod = (query: string) => {
+    if (query.length >= 3) {
+        searchBankBranChnumInfo({
+            branchname: query
+        }).then((res) => {
+            dataList.value = res.data
+        })
+    }
+}
+
+// 选择支行时触发
+const onBankChange = (item: Model.BankBranChnumInfoRsp) => {
+    configs.value.forEach((e) => {
+        switch (e.fieldcode) {
+            case 'bank_branch_name':
+                e.value = typeof item === 'string' ? item : item.branchname
+                break
+            case '100':
+                e.value = item.branchnum
+                break
+            case '101':
+                e.value = item.branchprovince
+                break
+            case '102':
+                e.value = item.branchcity
+                break
+        }
+    })
 }
 
 const onCancel = (isRefresh = false) => {
@@ -139,9 +187,9 @@ const onCancel = (isRefresh = false) => {
 
 /// 是否显示拓展信息
 const showExtendInfo = (item: Model.BankCusBankExtendConfigRsp) => {
-    return (item.usabletype === 1) || 
-           (item.usabletype === 2 && userStore.userInfo?.userinfotype === 2) || 
-           (item.usabletype === 3 && userStore.userInfo?.userinfotype === 1)
+    return (item.usabletype === 1) ||
+        (item.usabletype === 2 && userStore.userInfo?.userinfotype === 2) ||
+        (item.usabletype === 3 && userStore.userInfo?.userinfotype === 1)
 }
 
 // 发送手机验证码
@@ -173,44 +221,47 @@ const sendVerifyCode = () => {
 }
 
 const formSubmit = () => {
-    formRef.value?.validate((valid) => {
-        if (valid) {
-            if (formData.CusBankID) {
-                const obj: { [key: string]: unknown } = Object.create({})
-                configs.value.forEach((e) => {
-                    if (e.value) {
-                        obj[e.fieldcode] = e.value
-                    }
-                    if (e.fieldcode === 'bank_branch_name') {
-                        formData.OpenBankName = e.value
-                    }
-                    if (e.fieldcode === '100') {
-                        formData.OpenBankNo = e.value
-                    }
-                    if (e.fieldcode === '101') {
-                        formData.BankProvince = e.value
-                    }
-                    if (e.fieldcode === '102') {
-                        formData.BankCity = e.value
+    formRef.value?.validate((formValid) => {
+        if (formValid) {
+            extendRef.value?.validate((extendValid) => {
+                if (extendValid) {
+                    if (formData.CusBankID) {
+                        const obj: { [key: string]: unknown } = Object.create({})
+                        configs.value.forEach((e) => {
+                            if (e.value) {
+                                obj[e.fieldcode] = e.value
+                            }
+                            if (e.fieldcode === 'bank_branch_name') {
+                                formData.OpenBankName = e.value
+                            }
+                            if (e.fieldcode === '100') {
+                                formData.OpenBankNo = e.value
+                            }
+                            if (e.fieldcode === '101') {
+                                formData.BankProvince = e.value
+                            }
+                            if (e.fieldcode === '102') {
+                                formData.BankCity = e.value
+                            }
+                        })
+                        /// 如果需要短信验证码
+                        if (CenterErrMsg.value != '') {
+                            obj['smsSerialNo'] = CenterErrMsg.value
+                        }
+                        formData.extendInfo = JSON.stringify(obj)
+                        
+                        onSubmit().then(() => {
+                            ElMessage.success(bankInfo.value?.signstatus != undefined ? '签约信息修改成功' : '签约提交成功,请耐心等待审核。')
+                            onCancel(true)
+                        }).catch((err) => {
+                            ElMessage.error('提交失败:' + err)
+                        })
+                    } else {
+                        ElMessage.error('未签约')
                     }
-                })
-                /// 如果需要短信验证码
-                if (CenterErrMsg.value != '') {
-                    obj['smsSerialNo'] = CenterErrMsg.value
                 }
-                formData.extendInfo = JSON.stringify(obj)
-
-                onSubmit().then(() => {
-                    ElMessage.success(bankInfo.value?.signstatus != undefined ? '签约信息修改成功' : '签约提交成功,请耐心等待审核。')
-                    onCancel(true)
-                }).catch((err) => {
-                    ElMessage.error('提交失败:' + err)
-                })
-            } else {
-                ElMessage.error('未签约')
-            }
+            })
         }
     })
 }
-
 </script>

+ 1 - 1
src/packages/pc/views/footer/inout/out/add/index.vue

@@ -100,7 +100,7 @@ const { loading: searchLoading, dataList, runAsync: searchUser } = useRequest(ge
 
 // 远程搜索转入客户
 const remoteMethod = (query: string) => {
-    if (query) {
+    if (query.length > 3) {
         searchUser({
             param: query
         }).then((res) => {

+ 9 - 0
src/services/api/bank/index.ts

@@ -155,3 +155,12 @@ export function queryBankCusBankExtendConfigs(config: RequestConfig<Model.BankCu
     })
 }
 
+/**
+ * 查询银行支行联行号信息表
+ */
+export function queryBankBranChnumInfo(config: RequestConfig<Model.BankBranChnumInfoReq> = {}) {
+    return http.commonRequest<Model.BankBranChnumInfoRsp[]>({
+        url: '/Bank/QueryBankBranChnumInfo',
+        params: config.data,
+    })
+}

+ 20 - 4
src/types/model/bank.d.ts

@@ -219,11 +219,11 @@ declare namespace Model {
         // 用户id
         userid?: number;
         // 半身照
-        halfbodyphotourl?: string; 
+        halfbodyphotourl?: string;
         /// 手机号码
         mobile?: string
         // 用户类型
-        userinfotype?: number; 
+        userinfotype?: number;
     }
 
     interface AddAuthRsp {
@@ -241,7 +241,7 @@ declare namespace Model {
         page?: number
         // 每页条数
         pagesize?: number
-         // 分页标志 0-page从0开始 1-page从1开始
+        // 分页标志 0-page从0开始 1-page从1开始
         pageflag?: number;
         // 资金账户 - 格式:1,2,3
         accountID?: string
@@ -440,7 +440,7 @@ declare namespace Model {
         /// 身份证号码,目前只支持身份证
         idCardNumber?: string
         /// 手机号码
-        mobile?: string 
+        mobile?: string
         /// 姓名
         name?: string
     }
@@ -472,4 +472,20 @@ declare namespace Model {
         /// code
         code: string
     }
+
+    /** 查询银行支行联行号信息表 请求 */
+    interface BankBranChnumInfoReq {
+        branchname?: string; // 支行名称(模糊查询)
+        page?: number; // 页码
+        pagesize?: number; // 每页条数
+    }
+
+    /** 查询银行支行联行号信息表 响应 */
+    interface BankBranChnumInfoRsp {
+        branchcity: string; // 市县
+        branchname: string; // 支行名称
+        branchnum: string; // 支行行号
+        branchprovince: string; // 省份
+        isexpired: string; // 是否过期
+    }
 }