فهرست منبع

Merge branch 'master' of http://47.101.159.18:3000/Muchinfo/MTP20_WEB_GLOBAL

li.shaoyi 2 سال پیش
والد
کامیت
aa6b5370d7

+ 79 - 2
src/business/user/account.ts

@@ -1,6 +1,6 @@
-import { shallowRef, reactive } from 'vue'
+import { shallowRef, reactive, computed } from 'vue'
 import { useLoginStore, useAccountStore } from '@/stores'
-import { investorDel, modifyPassword, requestAddAuth } from '@/services/api/account'
+import { investorDel, modifyPassword, requestAddAuth, requestAddUser, requestCreateContractAndAddSigner, requestSignCompleted } from '@/services/api/account'
 import cryptojs from 'crypto-js'
 
 const loginStore = useLoginStore()
@@ -33,6 +33,33 @@ export function addAuthReq() {
     }
 }
 
+// 实名认证添加用户(爱签)
+export function adddUserReq() {
+    const loading = shallowRef(false)
+
+    const formData = reactive<Model.AddUserReq>({
+        idCardType: 1
+    })
+
+    const formSubmit = async () => {
+        try {
+            loading.value = true
+            await requestAddUser ({
+                data: formData
+            })
+        } finally {
+            loading.value = false
+        }
+    }
+
+    return {
+        loading,
+        formData,
+        formSubmit
+    }
+}
+
+
 // 修改密码
 export function useAccountPassword(ModifyPwdType: 0 | 1 | 2) {
     const loading = shallowRef(false)
@@ -90,4 +117,54 @@ export function useAccountCancellation() {
         loading,
         formSubmit,
     }
+}
+
+/**
+ * 上传待签署文件和添加签署方
+ */
+export function  useRequestCreateContractAndAddSigner() {
+    const loading = shallowRef(false)
+
+    /// 合同编号
+    const templateNoFormData = reactive<Model.ContractAndAddSignerReq>({ })
+
+    const createSigner = async () => {
+        try {
+            loading.value = true
+            return await requestCreateContractAndAddSigner({
+                data: {
+                    ...templateNoFormData,
+                }
+            })
+        } finally {
+            loading.value = false
+        }
+    }
+
+    return {
+        loading,
+        createSigner,
+        templateNoFormData
+    }
+}
+
+/**
+ * 提交实名认证
+ */
+export function  useRequestSignCompleted() {
+    const loading = shallowRef(false)
+
+    const signCompleted = async () => {
+        try {
+            loading.value = true
+            return await requestSignCompleted({})
+        } finally {
+            loading.value = false
+        }
+    }
+
+    return {
+        loading,
+        signCompleted
+    }
 }

+ 28 - 0
src/constants/account.ts

@@ -13,6 +13,14 @@ export enum AuthStatus {
 }
 
 /**
+ * 爱签实名认证状态
+ */
+export enum AQCertificateType {
+    /// 身份证
+    Identity = 1
+}
+
+/**
  * 实名认证状态列表
  * @returns 
  */
@@ -35,6 +43,26 @@ export function getAuthStatusName(value: number) {
 }
 
 /**
+ * 获取对应的爱签证件类型列表
+ * @returns 
+ */
+export function getAQCertificateTypeList() {
+    return [
+        { label: '身份证', value: AQCertificateType.Identity },
+    ]
+}
+
+/**
+ * 获取对应的爱签证件类型列表
+ * @returns 
+ */
+export function getAQCertificateTypeListName(value: number) {
+    const enums = getAQCertificateTypeList()
+    return getEnumTypeName(enums, value)
+}
+
+
+/**
  * 获取对应的证件类型列表
  * @returns 
  */

+ 6 - 0
src/filters/index.ts

@@ -13,6 +13,12 @@ export function getUrl(url: string, base?: string) {
     return new URL(url, base ?? uploadUrl)
 }
 
+// 获取商品首图
+export function getFirstImage(url: string){
+    const images = url.split(',').map((path) => getFileUrl(path))
+    return images[0] ?? ''
+}
+
 /**
  * 获取文件链接地址
  * @param filePath 

+ 1 - 1
src/packages/gstj/views/spot/list/Index.vue

@@ -9,7 +9,7 @@
         </template>
         <app-pull-refresh ref="pullRefreshRef" class="purchase__container" v-model:loading="loading" v-model:error="error"
             v-model:pageIndex="pageIndex" :page-count="pageCount" @refresh="run">
-            <Waterfall class="g-goods-list" :data-list="dataList">
+            <Waterfall class="g-goods-waterfall" :data-list="dataList">
                 <template #default="{ item }">
                     <div class="goods"
                         @click="$router.push({ name: 'spot-detail', query: { wrfactortypeid: item.wrfactortypeid } })">

+ 61 - 0
src/packages/mobile/assets/themes/global/global.less

@@ -122,6 +122,67 @@
 
 /* 商品列表 */
 .g-goods-list {
+    .list {
+        padding: .2rem .2rem 0 .2rem;
+
+        &-item {
+            display: flex;
+            align-items: center;
+            border-radius: .1rem;
+            overflow: hidden;
+            padding: .2rem;
+
+            &:not(:last-child) {
+                margin-bottom: .2rem;
+            }
+
+            .img {
+                &:first-child {
+                    display: flex;
+                    align-items: center;
+
+                    img {
+                        width: 1.8rem;
+                        height: 1.8rem;
+                        object-fit: cover;
+                        border-radius: .16rem;
+                        margin-right: .3rem;
+                    }
+                }
+
+                &:last-child {
+                    .van-button {
+                        width: 1.3rem;
+                        height: .5rem;
+                    }
+                }
+            }
+
+            .info {
+                flex: 1;
+
+                .title {
+                    color: #333;
+                    font-size: .30rem;
+                }
+
+                .desc {
+                    color: #666;
+                    font-size: .24rem;
+                    padding: .1rem 0;
+                }
+
+                .price {
+                    .buyprice, .sellprice {
+                        padding-bottom: .02rem;
+                    }
+                }
+            }
+        }
+    }
+}
+
+.g-goods-waterfall {
     padding: .2rem;
 
     .goods {

+ 5 - 1
src/packages/mobile/components/base/waterfall/index.vue

@@ -9,7 +9,7 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, watch, nextTick, onActivated } from 'vue'
+import { shallowRef, watch, nextTick, onActivated, onMounted } from 'vue'
 
 const props = defineProps({
     //数据列表
@@ -101,6 +101,10 @@ onActivated(() => {
         render()
     }
 })
+
+onMounted(() => {
+    render()
+})
 </script>
 
 <style lang="less">

+ 63 - 27
src/packages/mobile/views/ballot/list/Index.vue

@@ -1,57 +1,93 @@
 <template>
     <app-view class="ballot-list">
         <template #header>
-            <app-navbar title="预售中签" />
+            <app-navbar title="预售中签" >
+                <template #right>
+                    <Icon name="bars" size=".4rem" @click="isWaterfall = !isWaterfall"/>
+                </template>
+            </app-navbar>
         </template>
         <Banner :data-list="bannerList" @click="onBannerClick" v-if="bannerList.length" />
-        <Waterfall class="g-goods-list" :data-list="startList">
-            <template #default="{ item }">
-                <div class="goods" @click="toDetail(item)">
-                    <div class="goods-image">
-                        <img :src="getFileUrl(item.attachmenturl)" />
+        <template v-if="isWaterfall">
+            <Waterfall class="g-goods-waterfall" :data-list="startList" >
+                <template #default="{ item }">
+                    <div class="goods" @click="toDetail(item)">
+                        <div class="goods-image">
+                            <img :src="getFileUrl(item.attachmenturl)" />
+                        </div>
+                        <div class="goods-info">
+                            <div class="goods-info__title">{{ item.goodsname }}</div>
+                            <div class="goods-info__price">
+                                <Tag type="danger" plain>卖价</Tag>
+                                <span class="unit">¥</span>
+                                <span class="integer">{{ item.refprice }}</span>
+                            </div>
+                        </div>
+                    </div>
+                </template>
+            </Waterfall>
+            <Divider>发售历史</Divider>
+            <Waterfall class="g-goods-waterfall" :data-list="endList">
+                <template #default="{ item }">
+                    <div class="goods" @click="toDetail(item)">
+                        <div class="goods-image">
+                            <img :src="getFileUrl(item.attachmenturl)" />
+                        </div>
+                        <div class="goods-info">
+                            <div class="goods-info__title">{{ item.goodsname }}</div>
+                            <div class="goods-info__price">
+                                <Tag type="danger" plain>卖价</Tag>
+                                <span class="unit">¥</span>
+                                <span class="integer">{{ item.refprice }}</span>
+                            </div>
+                        </div>
                     </div>
-                    <div class="goods-info">
-                        <div class="goods-info__title">{{ item.goodsname }}</div>
-                        <div class="goods-info__price">
+                </template>
+            </Waterfall>
+        </template>
+        <template v-else>
+            <ul class="g-goods-list">
+                <li class="list-item g-block--bg" v-for="(item, index) in startList" :key="index" @click="toDetail(item)">
+                    <div class="img"><img :src="getFirstImage(item.attachmenturl)" /></div>
+                    <div class="info">
+                        <div class="title"><span>{{ item.goodsname }}</span></div>
+                        <div class="price">
                             <Tag type="danger" plain>卖价</Tag>
                             <span class="unit">¥</span>
                             <span class="integer">{{ item.refprice }}</span>
                         </div>
                     </div>
-                </div>
-            </template>
-        </Waterfall>
-        <Divider>发售历史</Divider>
-        <Waterfall class="g-goods-list" :data-list="endList">
-            <template #default="{ item }">
-                <div class="goods" @click="toDetail(item)">
-                    <div class="goods-image">
-                        <img :src="getFileUrl(item.attachmenturl)" />
-                    </div>
-                    <div class="goods-info">
-                        <div class="goods-info__title">{{ item.goodsname }}</div>
-                        <div class="goods-info__price">
+                </li>
+            </ul>
+            <Divider>发售历史</Divider>
+            <ul class="g-goods-list"> 
+                <li class="list-item g-block--bg" v-for="(item, index) in endList" :key="index" @click="toDetail(item)">
+                    <div class="img"><img :src="getFirstImage(item.attachmenturl)" /></div>
+                    <div class="info">
+                        <div class="title"><span>{{ item.goodsname }}</span></div>
+                        <div class="price">
                             <Tag type="danger" plain>卖价</Tag>
                             <span class="unit">¥</span>
                             <span class="integer">{{ item.refprice }}</span>
                         </div>
                     </div>
-                </div>
-            </template>
-        </Waterfall>
+                </li>
+            </ul>
+        </template>
     </app-view>
 </template>
 
 <script lang="ts" setup>
 import { shallowRef } from 'vue'
-import { Tag, Divider } from 'vant'
-import { getFileUrl } from '@/filters'
+import { Tag, Divider, Icon } from 'vant'
+import { getFileUrl, getFirstImage } from '@/filters'
 import { useNavigation } from '../../../router/navigation'
 import { useRequest } from '@/hooks/request'
 import { queryPresaleAuctions } from '@/services/api/presale'
 import Banner from '../../../components/base/banner/index.vue'
 import Waterfall from '../../../components/base/waterfall/index.vue'
 
+const isWaterfall = shallowRef(false)
 const { router } = useNavigation()
 const bannerList = shallowRef<string[]>([])
 

+ 1 - 1
src/packages/mobile/views/order/position/components/transfer/listing/Index.vue

@@ -75,7 +75,7 @@ const props = defineProps({
 })
 
 const { formData, formSubmit } = useOrder()
-const { getQuoteDayInfo } = useFuturesStore()
+const { getGoodsQuote } = useFuturesStore()
 const formRef = shallowRef<FormInstance>()
 const refresh = shallowRef(false) // 是否刷新父组件数据
 const showModal = shallowRef(true)

+ 64 - 27
src/packages/mobile/views/presale/list/Index.vue

@@ -1,57 +1,94 @@
 <template>
     <app-view class="presale-list">
         <template #header>
-            <app-navbar title="预售竞拍" :show-back-button="false" />
+            <app-navbar title="预售竞拍" :show-back-button="false" >
+                <template #right>
+                    <Icon name="bars" size=".4rem" @click="isWaterfall = !isWaterfall"/>
+                </template>
+            </app-navbar>
         </template>
         <Banner :data-list="bannerList" @click="onBannerClick" v-if="bannerList.length" />
-        <Waterfall class="g-goods-list" :data-list="startList">
-            <template #default="{ item }">
-                <div class="goods" @click="toDetail(item)">
-                    <div class="goods-image">
-                        <img :src="getFileUrl(item.attachmenturl)" />
+        <template v-if="isWaterfall">
+            <Waterfall class="g-goods-waterfall" :data-list="startList">
+                <template #default="{ item }">
+                    <div class="goods" @click="toDetail(item)">
+                        <div class="goods-image">
+                            <img :src="getFileUrl(item.attachmenturl)" />
+                        </div>
+                        <div class="goods-info">
+                            <div class="goods-info__title">{{ item.goodsname }}</div>
+                            <div class="goods-info__price">
+                                <Tag type="danger" plain>起拍价</Tag>
+                                <span class="unit">¥</span>
+                                <span class="integer">{{ item.startprice }}</span>
+                            </div>
+                        </div>
+                    </div>
+                </template>
+            </Waterfall>
+            <Divider>发售历史</Divider>
+            <Waterfall class="g-goods-waterfall" :data-list="endList">
+                <template #default="{ item }">
+                    <div class="goods" @click="toDetail(item)">
+                        <div class="goods-image">
+                            <img :src="getFileUrl(item.attachmenturl)" />
+                        </div>
+                        <div class="goods-info">
+                            <div class="goods-info__title">{{ item.goodsname }}</div>
+                            <div class="goods-info__price">
+                                <Tag type="danger" plain>预售价</Tag>
+                                <span class="unit">¥</span>
+                                <span class="integer">{{ item.tradeprice }}</span>
+                            </div>
+                        </div>
                     </div>
-                    <div class="goods-info">
-                        <div class="goods-info__title">{{ item.goodsname }}</div>
-                        <div class="goods-info__price">
+                </template>
+            </Waterfall>
+        </template>
+        <template v-else>
+            <ul class="lg-goods-list">
+                <li class="list-item g-block--bg" v-for="(item, index) in startList" :key="index" @click="toDetail(item)">
+                    <div class="img"><img :src="getFirstImage(item.attachmenturl)" /></div>
+                    <div class="info">
+                        <div class="title">{{ item.goodsname }}</div>
+                        <div class="desc">开始:{{ formatDate(item.starttime) }}-结束:{{ formatDate(item.endtime) }}</div>
+                        <div class="price">
                             <Tag type="danger" plain>起拍价</Tag>
                             <span class="unit">¥</span>
                             <span class="integer">{{ item.startprice }}</span>
                         </div>
                     </div>
-                </div>
-            </template>
-        </Waterfall>
-        <Divider>发售历史</Divider>
-        <Waterfall class="g-goods-list" :data-list="endList">
-            <template #default="{ item }">
-                <div class="goods" @click="toDetail(item)">
-                    <div class="goods-image">
-                        <img :src="getFileUrl(item.attachmenturl)" />
-                    </div>
-                    <div class="goods-info">
-                        <div class="goods-info__title">{{ item.goodsname }}</div>
-                        <div class="goods-info__price">
+                </li>
+            </ul>
+            <Divider>发售历史</Divider>
+            <ul class="g-goods-list"> 
+                <li class="list-item g-block--bg" v-for="(item, index) in endList" :key="index" @click="toDetail(item)">
+                    <div class="img"><img :src="getFirstImage(item.attachmenturl)" /></div>
+                    <div class="info">
+                        <div class="title">{{ item.goodsname }}</div>
+                        <div class="price">
                             <Tag type="danger" plain>预售价</Tag>
                             <span class="unit">¥</span>
                             <span class="integer">{{ item.tradeprice }}</span>
                         </div>
                     </div>
-                </div>
-            </template>
-        </Waterfall>
+                </li>
+            </ul>
+        </template>
     </app-view>
 </template>
 
 <script lang="ts" setup>
 import { shallowRef } from 'vue'
-import { Tag, Divider } from 'vant'
-import { getFileUrl } from '@/filters'
+import { Tag, Divider, Icon } from 'vant'
+import { formatDate, getFileUrl, getFirstImage } from '@/filters'
 import { useNavigation } from '../../../router/navigation'
 import { useRequest } from '@/hooks/request'
 import { queryPresaleAuctions } from '@/services/api/presale'
 import Banner from '../../../components/base/banner/index.vue'
 import Waterfall from '../../../components/base/waterfall/index.vue'
 
+const isWaterfall = shallowRef(false)
 const { router } = useNavigation()
 const bannerList = shallowRef<string[]>([])
 

+ 25 - 1
src/packages/mobile/views/spot/list/Index.vue

@@ -4,12 +4,13 @@
             <app-navbar title="现货挂牌">
                 <template #right>
                     <Icon name="add" size=".4rem" @click="$router.push({ name: 'spot-add' })" />
+                    <Icon name="bars" size=".4rem" @click="isWaterfall = !isWaterfall"/>
                 </template>
             </app-navbar>
         </template>
         <app-pull-refresh ref="pullRefreshRef" class="purchase__container" v-model:loading="loading" v-model:error="error"
             v-model:pageIndex="pageIndex" :page-count="pageCount" @refresh="run">
-            <Waterfall class="g-goods-list" :data-list="dataList">
+            <Waterfall class="g-goods-waterfall" :data-list="dataList" v-if="isWaterfall">
                 <template #default="{ item }">
                     <div class="goods"
                         @click="$router.push({ name: 'spot-detail', query: { wrfactortypeid: item.wrfactortypeid } })">
@@ -33,6 +34,28 @@
                     </div>
                 </template>
             </Waterfall>
+            <ul class="g-goods-list" v-else>
+                <li class="list-item g-block--bg" v-for="(item, index) in dataList" :key="index" @click="toDetail(item)">
+                    <div class="img"><img :src="getFirstImage(item.thumurls)" /></div>
+                    <div class="info">
+                        <div class="title"><span>{{ item.wrstandardcode }} / {{ item.wrstandardname }}</span></div>
+                        <div class="desc">{{ item.warehousename }}</div>
+                        <div class="price">
+                            <div class="sellprice" v-if="item.sellprice">
+                                <Tag type="danger" plain>卖价</Tag>
+                                <span class="unit">¥</span>
+                                <span class="integer">{{ item.sellprice }}</span>
+                            </div>
+                            <div class="buyprice" v-if="item.buyprice">
+                                <Tag type="warning" plain>买价</Tag>
+                                <span class="unit">¥</span>
+                                <span class="integer">{{ item.buyprice }}</span>
+                            </div>
+                        </div>
+                    </div>
+                    
+                </li>
+            </ul>
         </app-pull-refresh>
     </app-view>
 </template>
@@ -46,6 +69,7 @@ import { queryOrderQuote } from '@/services/api/goods'
 import AppPullRefresh from '../../../components/base/pull-refresh/index.vue'
 import Waterfall from '../../../components/base/waterfall/index.vue'
 
+const isWaterfall = shallowRef(false)
 const error = shallowRef(false)
 const pullRefreshRef = shallowRef()
 const dataList = shallowRef<Model.OrderQuoteRsp[]>([])

+ 1 - 1
src/packages/mobile/views/transfer/detail/Index.vue

@@ -76,7 +76,7 @@ const componentMap = new Map<string, unknown>([
 ])
 
 const { getQueryStringToNumber } = useNavigation()
-const { getQuoteDayInfo } = useFuturesStore()
+const { getGoodsQuote } = useFuturesStore()
 const goodsid = getQueryStringToNumber('goodsid')
 const quote = getGoodsQuote(goodsid)
 

+ 1 - 1
src/packages/mobile/views/transfer/detail2/index.vue

@@ -74,7 +74,7 @@ const componentMap = new Map<string, unknown>([
 ])
 
 const { router, getQueryStringToNumber } = useNavigation()
-const { getQuoteDayInfo } = useFuturesStore()
+const { getGoodsQuote } = useFuturesStore()
 const goodsid = getQueryStringToNumber('goodsid')
 const quote = getGoodsQuote(goodsid)
 const goodsCode = computed(() => quote.value?.goodscode ?? '')

+ 68 - 26
src/packages/qxst/views/account/certification/Index.vue

@@ -3,23 +3,25 @@
         <template #header>
             <app-navbar title="实名认证" />
         </template>
-        <Form ref="formRef" class="g-form__container" @submit="onSubmit">
+        <Form ref="formRef" class="g-form__container" @submit="onSubmit" :loading="loading">
             <CellGroup inset>
-                <Field v-model="formData.username" name="username" label="姓名" placeholder="请输入用户姓名"
-                    :rules="formRules.username" />
-                <Field name="cardtype" label="证件类型" :rules="formRules.cardtype" is-link>
+                <Field v-model="formData.name" name="name" label="姓名" placeholder="请输入用户姓名"
+                    :rules="formRules.name" />
+                <Field v-model="formData.mobile" name="mobile" label="手机号码" placeholder="请输入手机号码"
+                    :rules="formRules.mobile" />
+                <Field name="idCardType" label="证件类型" :rules="formRules.idCardType" is-link>
                     <template #input>
-                        <app-select v-model="formData.cardtype" placeholder="请选择证件类型" :options="enums" />
+                        <app-select v-model="formData.idCardType" placeholder="请选择证件类型" :options="enums" />
                     </template>
                 </Field>
-                <Field v-model="formData.cardnum" name="cardnum" label="证件号码" placeholder="请输入证件号码"
-                    :rules="formRules.cardnum" />
-                <Field name="cardfrontphotourl" label="证件正面照片" :rules="formRules.cardfrontphotourl">
+                <Field v-model="formData.idCard" name="cardnum" label="证件号码" placeholder="请输入证件号码"
+                    :rules="formRules.idCard" />
+                <Field name="idCardPhoto" label="证件正面照片" :rules="formRules.idCardPhoto">
                     <template #input>
                         <app-uploader @success="b_afterRead" />
                     </template>
                 </Field>
-                <Field name="cardbackphotourl" label="证件反面照片" :rules="formRules.cardbackphotourl">
+                <Field name="idCardPhotoBackURL" label="证件反面照片" :rules="formRules.idCardPhotoBackURL">
                     <template #input>
                         <app-uploader @success="f_afterRead" />
                     </template>
@@ -29,53 +31,92 @@
         <img src="../../../assets/images/certification.png" />
         <template #footer>
             <div class="g-form__footer inset">
-                <Button type="danger" @click="formRef?.submit" round block>提交实名认证</Button>
+                <Button type="danger" @click="formRef?.submit" :disabled="!canAdd" round block>提交实名认证</Button>
             </div>
         </template>
+        <component ref="componentRef" v-bind="{ formData }" :is="componentMap.get(componentId)" @closed="closeComponent" v-if="componentId" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, computed } from 'vue'
+import { shallowRef, computed, defineAsyncComponent } from 'vue'
 import { CellGroup, Button, Field, Form, FormInstance, showFailToast, FieldRule } from 'vant'
-import { addAuthReq } from '@/business/user'
 import { fullloading, dialog } from '@/utils/vant';
-import { getCertificateTypeList } from "@/constants/account";
+import { getAQCertificateTypeList } from "@/constants/account";
+import { useRequest } from '@/hooks/request'
+import { queryUserESignRecord } from '@/services/api/account';
+import { adddUserReq } from '@/business/user/account';
+import { validateRules } from '@/constants/regex';
+import { useComponent } from '@/hooks/component'
 import AppSelect from '../../../components/base/select/index.vue'
-import { useNavigation } from '../../../router/navigation'
 import AppUploader from '../../../components/base/uploader/index.vue'
 
 const formRef = shallowRef<FormInstance>()
-const { formData, formSubmit } = addAuthReq()
-const { router } = useNavigation()
+const { formData, formSubmit } = adddUserReq()
+const error = shallowRef(false)
+const canAdd = shallowRef(false)
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+
+const componentMap = new Map<string, unknown>([
+    ['certification-next', defineAsyncComponent(() => import('./components/certification-next/Index.vue'))], // 爱签-实名认证第二步
+])
+
+/// 查询记录
+const { loading  } = useRequest(queryUserESignRecord, {
+    onSuccess: (res) => {
+        res.data.map(obj => {
+            if (obj.templatetype === 1 && obj.recordstatus === 1) {
+                canAdd.value = true
+            }
+        })
+    },
+    onError: () => {
+        error.value = true
+    }
+})
 
 /// 获取对应的证件枚举类型
-const enums = computed(() => { return getCertificateTypeList().map(obj => { return { label: obj.label, value: obj.value } }) })
+const enums = computed(() => { return getAQCertificateTypeList().map(obj => { return { label: obj.label, value: obj.value } }) })
 
 const b_afterRead = (filePath: string) => {
-    formData.cardfrontphotourl = filePath
+    formData.idCardPhoto = filePath
 }
 
 const f_afterRead = (filePath: string) => {
-    formData.cardbackphotourl = filePath
+    formData.idCardPhotoBackURL = filePath
 }
 
 // 表单验证规则
-const formRules: { [key in keyof Model.AddAuthReq]?: FieldRule[] } = {
-    username: [{
+const formRules: { [key in keyof Model.AddUserReq]?: FieldRule[] } = {
+    name: [{
         required: true,
         message: '请输入用户姓名',
     }],
-    cardnum: [{
+    mobile: [{
+        required: true,
+        message: '请输入手机号码',
+        validator: (val) => {
+            if (validateRules.phone.validate(val)) {
+                return true
+            }
+            return validateRules.phone.message
+        }
+    }],
+    idCard: [{
         required: true,
         message: '请输入证件号码',
-
+        validator: (val) => {
+            if (validateRules.cardno.validate(val)) {
+                return true
+            }
+            return validateRules.cardno.message
+        }
     }],
-    cardbackphotourl: [{
+    idCardPhotoBackURL: [{
         required: true,
         message: '请上传证件背面照片',
     }],
-    cardfrontphotourl: [{
+    idCardPhoto: [{
         required: true,
         message: '请上传证件正面照片',
     }],
@@ -86,7 +127,8 @@ const onSubmit = () => {
         formSubmit().then(() => {
             hideLoading()
             dialog('实名认证提交请求成功').then(() => {
-                router.back()
+                /// 进行下一步
+                openComponent('certification-next')
             })
         }).catch((err) => {
             showFailToast(err)

+ 151 - 0
src/packages/qxst/views/account/certification/components/certification-next/Index.vue

@@ -0,0 +1,151 @@
+<template>
+    <app-modal direction="right" height="100%" v-model:show="showModal" :refresh="refresh">
+        <app-view class="g-form account-certification">
+            <template #header>
+                <app-navbar title="实名认证" />
+            </template>
+            <CellGroup inset>
+                <Cell title="姓名" :value="formData.name" />
+                <Cell title="手机号码" :value="formData.mobile" />
+                <Cell title="证件类型" :value="getAQCertificateTypeListName(formData.idCardType ?? 1)" />
+                <Cell title="证件号码" :value="formData.idCard" />
+                <Field name="idCardPhoto" label="证件正面照片">
+                    <template #input>
+                        <image :src="idCardPhoto"></image>
+                    </template>
+                </Field>
+                <Field name="idCardPhotoBackURL" label="证件反面照片">
+                    <template #input>
+                        <image :src="idCardPhotoBackURL"></image>
+                    </template>
+                </Field>
+            </CellGroup>
+            <CellGroup inset>
+                <Cell v-for="(item, index) in dataList" :key="index" @click="signer(item)">
+                    <template #title>
+                        <Icon color="#00CCFF" :name="iconName(item.recordstatus)"></Icon>
+                        <Button :disable="item.recordstatus === 2" :text="true">{{ item.templatename }}</Button>
+                    </template>
+                </Cell>
+            </CellGroup>
+            <template #footer>
+                <div class="g-form__footer inset">
+                    <Button type="danger" :disable="!canAdd" @click="completed()" round block>提交认证</Button>
+                </div>
+            </template>
+        </app-view>
+    </app-modal>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, computed, PropType} from 'vue'
+import { CellGroup, Button, Cell, Field, Icon, showFailToast } from 'vant'
+import { fullloading, dialog } from '@/utils/vant';
+import { getAQCertificateTypeListName } from "@/constants/account";
+import { useRequest } from '@/hooks/request'
+import { queryUserESignRecord } from '@/services/api/account';
+import { useRequestCreateContractAndAddSigner, useRequestSignCompleted } from '@/business/user/account';
+import plus from '@/utils/h5plus'
+import { onMounted } from 'vue';
+import { getFileUrl } from '@/filters';
+import AppModal from '@/components/base/modal/index.vue'
+
+const error = shallowRef(false)
+const showModal = shallowRef(true)
+// 是否刷新父组件数据
+const refresh = shallowRef(false)
+const dataList = shallowRef<Model.UserESignRecordRsq[]>([])
+const { createSigner, templateNoFormData} = useRequestCreateContractAndAddSigner()
+const { signCompleted} = useRequestSignCompleted()
+/// 可以认证
+const canAdd = shallowRef(false)
+
+const iconName = (type: number) => {
+    switch (type) {
+        case 1:
+            return 'circle'
+        case 2:
+            return 'circle'
+        case 3:
+            return 'passed'
+        default:
+            return 'close'
+    }
+}
+
+// 正面照
+const idCardPhoto = computed(() => {
+    const idCardPhoto = props.formData.idCardPhoto ?? ''
+    return idCardPhoto.split(',').map((path) => getFileUrl(path))
+})
+
+// 背面照
+const idCardPhotoBackURL = computed(() => {
+    const idCardPhotoBackURL = props.formData.idCardPhotoBackURL ?? ''
+    return idCardPhotoBackURL.split(',').map((path) => getFileUrl(path))
+})
+
+const openURL = (url: string) => {
+    plus.openURL(url)
+}
+
+const props = defineProps({
+    formData: {
+        type: Object as PropType<Model.AddUserReq>,
+        required: true,
+    }
+})
+
+const completed = () => {
+    fullloading((hideLoading) => {
+        signCompleted().then(() => {
+            hideLoading()
+            dialog('实名认证提交请求成功').then(() => {
+                // router.back()
+            })
+        }).catch((err) => {
+            showFailToast(err)
+        })
+    })
+}
+
+const signer = (item: Model.UserESignRecordRsq) => {
+    ///  如果是已签署
+    if (item.recordstatus === 3) { 
+        if (item.contractfileaddr != '') {
+            openURL(item.contractfileaddr)
+        } else {
+            showFailToast('已签署文件地址错误')
+        }
+    } else {
+        fullloading((hideLoading) => {
+            templateNoFormData.templateNo = item.templateno
+            /// 创建合同
+            createSigner().then((res) => {
+                hideLoading()
+                openURL(res.data.data)
+            }).catch((err) => {
+                showFailToast(err)
+            })
+        })
+    }
+}
+
+onMounted(() => {
+    /// 查询
+    useRequest(queryUserESignRecord, {
+        onSuccess: (res) => {
+            if (res.data.length != 0) {
+                dataList.value = res.data.filter(obj => {
+                    return obj.templatetype === 2
+                })
+            }
+            /// 只有全部签署才可以进行下一步
+            canAdd.value = dataList.value.some(obj => { [1, 2, 4].includes(obj.recordstatus) })
+        },
+        onError: () => {
+            error.value = true
+        }
+    })
+})
+</script>

+ 44 - 0
src/services/api/account/index.ts

@@ -140,4 +140,48 @@ export function modifyPassword(config: RequestConfig<Proto.ModifyPwdReq>) {
         requestCode: 'ModifyPwdReq',
         responseCode: 'ModifyPwdRsp',
     })
+}
+
+/**
+ * 实名认证添加用户
+ */
+export function requestAddUser(config: RequestConfig<Model.AddUserReq> = {}) {
+    return http.goRequest<Model.AddUserRsp>({
+        method: 'post',
+        url: '/Account/AddUser',
+        data: config.data,
+    })
+}
+
+/**
+ * 查询用户电子签记录表
+ */
+export function queryUserESignRecord(config: RequestConfig<Model.UserESignRecordReq> = {}) {
+    return http.goRequest<Model.UserESignRecordRsq[]>({
+        method: 'get',
+        url: '/Account/QueryUserESignRecord',
+        data: config.data,
+    })
+}
+
+/**
+ * 上传待签署文件和添加签署方
+ */
+export function requestCreateContractAndAddSigner(config: RequestConfig<Model.ContractAndAddSignerReq> = {}) {
+    return http.goRequest<Model.ContractAndAddSignerRsq>({
+        method: 'post',
+        url: '/Account/CreateContractAndAddSigner',
+        data: config.data,
+    })
+}
+
+/**
+ * 提交实名认证
+ */
+export function requestSignCompleted(config: RequestConfig<Model.ContractAndAddSignerReq> = {}) {
+    return http.goRequest<Model.ContractAndAddSignerRsq>({
+        method: 'post',
+        url: '/Account/SignCompleted',
+        data: config.data,
+    })
 }

+ 85 - 0
src/types/model/bank.d.ts

@@ -282,4 +282,89 @@ declare namespace Model {
         // 交易模式
         trademode: number
     }
+
+
+    // 查询用户电子签记录表请求
+    interface UserESignRecordReq {
+        /// 页数
+        page?: number
+        /// 条数
+        size?: number
+    }
+
+    // 查询用户电子签记录表回应
+    interface UserESignRecordRsq {
+        // 认证信息
+        authinfo: string
+        // 合同签署文件地址
+        contractfileaddr: string
+        // 合同编号
+        contractno: string
+        // 创建时间
+        createtime: string
+        // 创建人
+        creatorid: number
+        // 显示顺序
+        orderindex: number
+        // 记录ID(SEQ_USERESIGNRECORD)
+        recordid: number
+        // 记录状态 - 1:未签署 2:签署中 3:已签署 4:签署拒绝
+        recordstatus: number
+        // 签署备注
+        signremark: string
+        // 合同签署URL(三方URL)
+        signurl: string
+        // 模板配置ID
+        templateconfigid: number
+        // 模板名称
+        templatename: string
+        // 模板编号(电子签类型对应的模板编号)
+        templateno: string
+        // 模板类型 - 1:实名认证 2:开户协议
+        templatetype: number
+        // 更新时间
+        updatetime: string
+        // 用户ID
+        userid: number
+    }
+
+    /// 实名认证添加用户请求
+    interface AddUserReq {
+        // 证件号码
+        idCard?: string
+        // 证件照正面
+        idCardPhoto?: string
+        // 证件照背面
+        idCardPhotoBackURL?: string
+        // 证件类型(默认1):1-居民身份证 2-台湾居民来往内地通行证 3-港澳居民往来内地通行证 10-武装警察身份证 11-军人身份证 15-警察(警官)证 21-外国人永久居留证 23-护照
+        idCardType?: number
+        // 手机号码
+        mobile?: string
+        // 用户姓名
+        name?: string
+    }
+
+    /// 实名认证添加用户回应
+    interface AddUserRsp {
+        // 返回码
+        code: string
+        // 返回信息
+        msg: string
+    }
+
+    /// 上传待签署文件和添加签署方-请求
+    interface ContractAndAddSignerReq {
+        /// 合同模板编号
+        templateNo?: string
+    }
+
+    /// 上传待签署文件和添加签署方-回应
+    interface ContractAndAddSignerRsq {
+        /// code
+        code: number
+        /// data
+        data: string
+        /// msg
+        msg: string
+    }
 }

+ 0 - 1
src/types/proto/bank.d.ts

@@ -1,5 +1,4 @@
 import { IMessageHead } from './proto'
-import Long from 'long'
 
 declare global {
     namespace Proto {