li.shaoyi 11 місяців тому
батько
коміт
86fece8664

+ 2 - 3
src/packages/pc/views/member/institution/user/components/account/index.vue

@@ -11,7 +11,6 @@
                 </template>
                 <template #headerRight>
                     <div>
-                        <el-button type="primary" @click="showComponent('Edit')">{{ t('operation.add') }}</el-button>
                         <el-button @click="emit('closed')">{{ t('operation.close') }}</el-button>
                     </div>
                 </template>
@@ -20,7 +19,7 @@
                     <el-button size="small" icon="Search" @click="showComponent('Details', row)" circle plain />
                     <el-button size="small" icon="Document" @click="showComponent('SignStatement', row)" circle plain />
                     <el-button size="small" icon="Edit" @click="showComponent('Edit', row)" circle plain />
-                    <el-button size="small" icon="Key" @click="showComponent('Password', row)" circle plain />
+                    <el-button size="small" icon="Key" @click="showComponent('UpdatePassword', row)" circle plain />
                 </template>
                 <template #footer>
                     <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
@@ -57,7 +56,7 @@ const componentMap = new Map<string, unknown>([
     ['Details', defineAsyncComponent(() => import('@pc/views/account/fundacct/components/details/index.vue'))], // 详情
     ['SignStatement', defineAsyncComponent(() => import('./signstatement/index.vue'))], // 签解约流水
     ['Edit', defineAsyncComponent(() => import('./edit/index.vue'))], // 修改
-    ['Password', defineAsyncComponent(() => import('./password/index.vue'))], // 重置密码
+    ['UpdatePassword', defineAsyncComponent(() => import('./password/index.vue'))], // 重置密码
 ])
 
 const emit = defineEmits(['closed'])

+ 52 - 0
src/packages/pc/views/member/institution/user/components/close/index.vue

@@ -0,0 +1,52 @@
+<!-- 会员机构管理-机构管理-机构资料管理-注销 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :refresh="refresh" :loading="loading">
+        <div class="g-text-message">确认注销该机构?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { organDetailLogout } from '@/services/api/member'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.OrganDetailListRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+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
+    organDetailLogout({
+        data: {
+            userid: props.record.userid
+        }
+    }).then(() => {
+        ElMessage.success('注销成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('注销失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 6 - 5
src/packages/pc/views/member/institution/user/components/details/index.vue

@@ -43,6 +43,7 @@
 import { shallowRef, PropType, computed } from 'vue'
 import { ElMessage } from 'element-plus'
 import { formatDate } from '@/filters'
+import { decryptAES } from '@/services/crypto'
 import { useEnum } from '@/hooks/enum'
 import { useRequest } from '@/hooks/request'
 import { UserInfoType, getGenderName, getUserInfoTypeName } from '@/constants/member'
@@ -119,7 +120,7 @@ const detailProps2 = computed<CellProp[]>(() => {
         { prop: 'company', label: '公司', show: isPerson },
         { prop: 'biznature', label: '企业性质', formatValue: (val) => biznatureEnum.getEnumTypeName(val), show: !isPerson },
         { prop: 'cardtypeid', label: '证件类型', formatValue: (val) => certificatetypeEnum.getEnumTypeName(val) },
-        { prop: 'cardnum', label: '证件号码' },
+        { prop: 'cardnum', label: '证件号码', formatValue: (val) => decryptAES(val) },
         { prop: 'cardfrontphotourl', label: '证件照正面' },
         { prop: 'cardbackphotourl', label: '证件照反面', show: isPerson },
         { prop: 'legalpersonname', label: '法人姓名', show: !isPerson },
@@ -127,11 +128,11 @@ const detailProps2 = computed<CellProp[]>(() => {
         { prop: 'legalcardbackphotourl', label: '法人身份证反面', show: !isPerson },
         { prop: 'contactname', label: '联系人', show: !isPerson },
         { prop: 'sex', label: '性别', formatValue: (val) => getGenderName(val) },
-        { prop: 'mobile', label: '手机号' },
-        { prop: 'telphone', label: '联系电话' },
-        { prop: 'address', label: '地址', formatValue: (val) => data.value?.division + val },
+        { prop: 'mobile', label: '手机号', formatValue: (val) => decryptAES(val) },
+        { prop: 'telphone', label: '联系电话', formatValue: (val) => decryptAES(val) },
+        { prop: 'address', label: '地址', formatValue: (val) => (data.value?.division ?? '') + (val ?? '') },
         { prop: 'postalcode', label: '邮政编码' },
-        { prop: 'email', label: '邮箱' },
+        { prop: 'email', label: '邮箱', formatValue: (val) => decryptAES(val) },
         { prop: 'qq', label: 'QQ' },
         { prop: 'wechat', label: '微信' },
         { prop: 'remark', label: '备注' },

+ 298 - 0
src/packages/pc/views/member/institution/user/components/edit/index.vue

@@ -0,0 +1,298 @@
+<!-- 会员机构管理-机构管理-机构资料管理-编辑 -->
+<template>
+    <app-drawer :title="t('member.institution.open.edit.title')" width="900" v-model:show="show" :refresh="refresh"
+        :loading="loading">
+        <el-form ref="formRef" label-width="140px" :model="formData" :rules="formRules" :show-message="false">
+            <fieldset class="g-fieldset el-form--horizontal">
+                <legend class="g-fieldset__legend">基本信息</legend>
+                <el-form-item label="机构代码">
+                    {{ handleNoneValue(data?.rspResult.userid) }}
+                </el-form-item>
+                <el-form-item label="所有者类型" prop="userinfotype">
+                    {{ data ? getUserInfoTypeName(data.userinfo.userinfotype) : handleNoneValue() }}
+                </el-form-item>
+                <el-form-item label="机构名称" prop="username">
+                    <el-input v-model="formData.username" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="机构类型">
+                    {{ data ? usertype2Enum.getEnumTypeName(data.rspResult.usertype) : handleNoneValue() }}
+                </el-form-item>
+                <el-form-item label="推荐人" prop="refereeuserid">
+                    <app-select-member v-model="formData.refereeuserid" />
+                </el-form-item>
+            </fieldset>
+            <fieldset class="g-fieldset el-form--horizontal">
+                <legend class="g-fieldset__legend">{{ isPerson ? '个人' : '企业' }}资料</legend>
+                <el-form-item label="名称" prop="customername">
+                    <el-input v-model="formData.customername" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="公司" prop="company" v-if="isPerson">
+                    <el-input v-model="formData.company" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="企业性质" prop="biznature" v-if="!isPerson">
+                    <app-enum code="biznature" v-model="formData.biznature" />
+                </el-form-item>
+                <el-form-item label="证件类型" prop="cardtypeid">
+                    <app-enum code="certypecompany" v-model="formData.cardtypeid" v-if="!isPerson" />
+                    <app-enum code="certypeperson" v-model="formData.cardtypeid" v-else />
+                </el-form-item>
+                <el-form-item label="证件号码" prop="cardnum">
+                    <el-input v-model="formData.cardnum" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <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" v-if="isPerson">
+                    <app-upload v-model="uploadFiles.cardbackphotourl" :file-types="['image']"
+                        type-message="请选择正确的图片类型" />
+                </el-form-item>
+                <template v-if="!isPerson">
+                    <el-form-item label="法人姓名" prop="legalpersonname">
+                        <el-input v-model="formData.legalpersonname" maxlength="50" placeholder="请输入" />
+                    </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="legalcardbackphotourl">
+                        <app-upload v-model="uploadFiles.legalcardbackphotourl" :file-types="['image']"
+                            type-message="请选择正确的图片类型" />
+                    </el-form-item>
+                    <el-form-item label="联系人" prop="contactname">
+                        <el-input v-model="formData.contactname" maxlength="50" placeholder="请输入" />
+                    </el-form-item>
+                </template>
+                <el-form-item label="性别" prop="sex">
+                    <el-radio-group v-model="formData.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="mobile">
+                    <el-input type="number" v-model="formData.mobile" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="联系电话" prop="telphone">
+                    <el-input type="number" v-model="formData.telphone" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item class="el-form-item--row" label="地区" prop="provinceid">
+                    <app-region class="el-form-item--col" v-model:province="formData.provinceid"
+                        v-model:city="formData.cityid" v-model:district="formData.districtid" />
+                </el-form-item>
+                <el-form-item class="el-form-item--row" label="地址" prop="address">
+                    <el-input v-model="formData.address" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="邮政编码" prop="postalcode">
+                    <el-input v-model="formData.postalcode" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item label="邮箱" prop="email">
+                    <el-input v-model="formData.email" maxlength="50" placeholder="请输入" />
+                </el-form-item>
+                <el-form-item class="el-form-item--row" label="备注" prop="remark">
+                    <el-input type="textarea" v-model="formData.remark" maxlength="200" :rows="3" placeholder="请输入" />
+                </el-form-item>
+            </fieldset>
+            <fieldset class="g-fieldset el-form--horizontal" v-if="data && data.rspResult.usertype !== 4">
+                <legend class="g-fieldset__legend">管理员及账户信息</legend>
+                <el-form-item label="管理员名称">
+                    {{ data.users.username }}
+                </el-form-item>
+                <el-form-item label="资金账户" prop="userinfotype" v-if="data.rspResult.usertype === 2">
+                    {{ data.rspResult.reckonaccountid }}
+                </el-form-item>
+            </fieldset>
+            <fieldset class="g-fieldset el-form--horizontal">
+                <legend class="g-fieldset__legend">附件</legend>
+                <el-form-item label="附件1" prop="attachment1">
+                    <app-upload v-model="uploadFiles.attachment1" :file-types="['image', 'pdf']"
+                        type-message="请选择正确的图片类型" />
+                </el-form-item>
+                <el-form-item label="附件2" prop="attachment2">
+                    <app-upload v-model="uploadFiles.attachment2" :file-types="['image', 'pdf']"
+                        type-message="请选择正确的图片类型" />
+                </el-form-item>
+            </fieldset>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" :disabled="!data" @click="onSubmit">保存</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, PropType, computed } from 'vue'
+import { ElMessage, FormInstance, FormRules, UploadUserFile } from 'element-plus'
+import { handleNoneValue } from '@/filters'
+import { useEnum } from '@/hooks/enum'
+import { decryptAES } from '@/services/crypto'
+import { useRequest } from '@/hooks/request'
+import { editOrgan, queryOrganDetail } from '@/services/api/member'
+import { getGenderList, UserInfoType, getUserInfoTypeName } 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 { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.OrganDetailListRsp>,
+        required: true
+    }
+})
+
+// 机构类型
+const usertype2Enum = useEnum('usertype2')
+
+const { global: { t } } = i18n
+const formRef = ref<FormInstance>()
+const show = ref(true)
+const refresh = ref(false)
+
+const formData = ref<Partial<Model.EditOrganReq>>({})
+
+const uploadFiles = reactive<{
+    cardfrontphotourl: UploadUserFile[];
+    cardbackphotourl: UploadUserFile[];
+    legalcardfrontphotourl: UploadUserFile[];
+    legalcardbackphotourl: UploadUserFile[];
+    attachment1: UploadUserFile[];
+    attachment2: UploadUserFile[];
+}>({
+    cardfrontphotourl: [],
+    cardbackphotourl: [],
+    legalcardfrontphotourl: [],
+    legalcardbackphotourl: [],
+    attachment1: [],
+    attachment2: []
+})
+
+// 是否个人
+const isPerson = computed(() => formData.value.userinfotype === UserInfoType.Personal)
+
+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 { data, loading } = useRequest(queryOrganDetail, {
+    params: {
+        areaId: props.record.userid
+    },
+    onSuccess: ((res) => {
+        const { rspResult, userinfo, users } = res.data
+
+        if (userinfo) {
+            uploadFiles.cardfrontphotourl = getUploadFiles(userinfo.cardfrontphotourl)
+            uploadFiles.cardbackphotourl = getUploadFiles(userinfo.cardbackphotourl)
+            uploadFiles.legalcardfrontphotourl = getUploadFiles(userinfo.legalcardfrontphotourl)
+            uploadFiles.legalcardbackphotourl = getUploadFiles(userinfo.legalcardbackphotourl)
+            uploadFiles.attachment1 = getUploadFiles(userinfo.attachment1)
+            uploadFiles.attachment2 = getUploadFiles(userinfo.attachment2)
+        }
+
+        formData.value = {
+            accountname: rspResult.accountname,
+            address: userinfo.address,
+            attachment1: userinfo.attachment1,
+            attachment2: userinfo.attachment2,
+            autoid: users.autoid,
+            biznature: userinfo.biznature,
+            cardbackphotourl: userinfo.cardbackphotourl,
+            cardfrontphotourl: userinfo.cardfrontphotourl,
+            cardnum: decryptAES(userinfo.cardnum),
+            cardtypeid: userinfo.cardtypeid,
+            cityid: userinfo.cityid,
+            company: userinfo.company,
+            contactname: userinfo.contactname,
+            customername: userinfo.customername,
+            districtid: userinfo.districtid,
+            email: decryptAES(userinfo.email),
+            legalcardbackphotourl: userinfo.legalcardbackphotourl,
+            legalcardfrontphotourl: userinfo.legalcardfrontphotourl,
+            legalpersonname: userinfo.legalpersonname,
+            logincode: userinfo.logincode,
+            mobile: decryptAES(userinfo.mobile),
+            modifystatus: rspResult.modifystatus,
+            parentuserid: rspResult.parentuserid,
+            postalcode: userinfo.postalcode,
+            provinceid: userinfo.provinceid,
+            qq: userinfo.qq,
+            reckonaccountid: rspResult.reckonaccountid,
+            refereeuserid: rspResult.refereeuserid,
+            remark: userinfo.remark,
+            sex: userinfo.sex,
+            telphone: decryptAES(userinfo.telphone),
+            userid: userinfo.userid,
+            userinfotype: userinfo.userinfotype,
+            username: users.username,
+            usertype: userinfo.usertype,
+            wechat: userinfo.wechat
+        }
+    }),
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+// 表单验证规则
+const formRules: FormRules = {
+    cardtypeid: [{ required: true }],
+    username: [{ required: true }],
+    customername: [{ required: true }],
+    cardnum: [{ 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.cardfrontphotourl = updateUploadFiles(uploadFiles.cardfrontphotourl)
+    rawData.cardbackphotourl = updateUploadFiles(uploadFiles.cardbackphotourl)
+    rawData.legalcardfrontphotourl = updateUploadFiles(uploadFiles.legalcardfrontphotourl)
+    rawData.legalcardbackphotourl = updateUploadFiles(uploadFiles.legalcardbackphotourl)
+    rawData.attachment1 = updateUploadFiles(uploadFiles.attachment1)
+    rawData.attachment2 = updateUploadFiles(uploadFiles.attachment2)
+
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            loading.value = true
+            editOrgan({
+                data: rawData
+            }).then(() => {
+                ElMessage.success(t('common.tips3'))
+                onCancel(true)
+            }).catch((err) => {
+                ElMessage.error(t('common.tips4') + err)
+            }).finally(() => {
+                loading.value = false
+            })
+        }
+    })
+}
+</script>

+ 97 - 0
src/packages/pc/views/member/institution/user/components/login/index.vue

@@ -0,0 +1,97 @@
+<!-- 会员机构管理-机构管理-机构资料管理-登录账户 -->
+<template>
+    <teleport to="#appPageTeleport">
+        <app-view>
+            <app-table :data="dataList" :columns="tableColumns" :loading="loading">
+                <template #headerLeft>
+                    <span>[{{ record.accountname }}]及子机构 管理员账户</span>
+                </template>
+                <template #headerRight>
+                    <div>
+                        <el-button type="primary" @click="updateStatuses(1)">全部启用</el-button>
+                        <el-button type="primary" @click="updateStatuses(2)">全部停用</el-button>
+                        <el-button @click="emit('closed')">{{ t('operation.close') }}</el-button>
+                    </div>
+                </template>
+                <!-- 操作 -->
+                <template #operate="{ row }">
+                    <el-button size="small" icon="Key" @click="showComponent('UpdatePassword', row)" circle plain />
+                    <el-button size="small" :icon="row.managerstatus === 1 ? 'SwitchButton' : 'Refresh'"
+                        @click="showComponent('UpdateStatus', row)" circle plain />
+                </template>
+                <template #footer>
+                    <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                        @change="run" />
+                </template>
+            </app-table>
+            <component ref="componentRef" :is="componentMap.get(componentId)"
+                v-bind="{ statuses, record, selectedItem }" @closed="closeComponent" v-if="componentId" />
+        </app-view>
+    </teleport>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType, defineAsyncComponent } from 'vue'
+import { ElMessage } from 'element-plus'
+import { formatDate } from '@/filters'
+import { useEnum } from '@/hooks/enum'
+import { useRequest } from '@/hooks/request'
+import { useComponent } from '@/hooks/component'
+import { queryorgan2User } from '@/services/api/member'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.OrganDetailListRsp>,
+        required: true
+    }
+})
+
+const componentMap = new Map<string, unknown>([
+    ['UpdateStatuses', defineAsyncComponent(() => import('./statuses/index.vue'))], // 全部账户状态
+    ['UpdateStatus', defineAsyncComponent(() => import('./status/index.vue'))], // 账户状态
+    ['UpdatePassword', defineAsyncComponent(() => import('./password/index.vue'))], // 重置密码
+])
+
+const emit = defineEmits(['closed'])
+
+// 帐号状态
+const userstatusEnum = useEnum('userstatus')
+
+const { global: { t } } = i18n
+const statuses = shallowRef(0) // 所有状态
+const selectedItem = shallowRef<Model.OrganTaaccountRsp>()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => run())
+
+const { dataList, total, pageSize, pageIndex, loading, run } = useRequest(queryorgan2User, {
+    params: {
+        pageNum: 1,
+        pageSize: 20,
+        userid: props.record.userid
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { field: 'areauserid', label: '所属机构代码' },
+    { field: 'logincode', label: '登录账户' },
+    { field: 'managerstatus', label: '账户状态', formatValue: (val) => userstatusEnum.getEnumTypeName(val) },
+    { field: 'modifytime', label: '更新时间', formatValue: (val) => formatDate(val) },
+    { field: 'operate', label: 'common.operate', fixed: 'right' }
+])
+
+const updateStatuses = (value: number) => {
+    statuses.value = value
+    openComponent('UpdateStatuses')
+}
+
+const showComponent = (code: string, row?: Model.OrganTaaccountRsp) => {
+    selectedItem.value = row
+    openComponent(code)
+}
+</script>

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

@@ -0,0 +1,50 @@
+<!-- 会员机构管理-机构管理-机构资料管理-登录账户-重置密码 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :loading="loading">
+        <div class="g-text-message">确认将密码重置?</div>
+        <template #footer>
+            <el-button @click="onCancel">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { updateStatus } from '@/services/api/member'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.Organ2UserRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+const loading = shallowRef(false)
+
+const onCancel = () => {
+    show.value = false
+}
+
+const onSubmit = () => {
+    loading.value = true
+    updateStatus({
+        data: {
+            type: 0,
+            userid: props.selectedItem.autoid
+        }
+    }).then(() => {
+        ElMessage.success('重置成功')
+    }).catch((err) => {
+        ElMessage.error('重置失败:' + err)
+    }).finally(() => {
+        loading.value = false
+        onCancel()
+    })
+}
+</script>

+ 58 - 0
src/packages/pc/views/member/institution/user/components/login/status/index.vue

@@ -0,0 +1,58 @@
+<!-- 会员机构管理-机构管理-机构资料管理-登录账户-停用/启用 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :refresh="refresh" :loading="loading">
+        <div class="g-text-message">
+            <span v-if="isActivated">确认停用管理员登录账号?</span>
+            <span v-else>确认启用管理员登录账号?</span>
+        </div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType, computed } from 'vue'
+import { ElMessage } from 'element-plus'
+import { updateStatusByAutoId } from '@/services/api/member'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.Organ2UserRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const isActivated = computed(() => props.selectedItem.managerstatus === 1)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    updateStatusByAutoId({
+        data: {
+            autoid: props.selectedItem.autoid,
+            status: isActivated.value ? 2 : 1
+        }
+    }).then(() => {
+        ElMessage.success('提交成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('提交失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 60 - 0
src/packages/pc/views/member/institution/user/components/login/statuses/index.vue

@@ -0,0 +1,60 @@
+<!-- 会员机构管理-机构管理-机构资料管理-登录账户-全部停用/启用 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :refresh="refresh" :loading="loading">
+        <div class="g-text-message">
+            <span v-if="statuses === 1">确认启用所有管理员登录账号?</span>
+            <span v-else>确认停用所有管理员登录账号?</span>
+        </div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { updateOrgan2User } from '@/services/api/member'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    statuses: {
+        type: Number,
+        required: true
+    },
+    record: {
+        type: Object as PropType<Model.OrganDetailListRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+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
+    updateOrgan2User({
+        data: {
+            userid: props.record.userid,
+            status: props.statuses
+        }
+    }).then(() => {
+        ElMessage.success('提交成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('提交失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 52 - 0
src/packages/pc/views/member/institution/user/components/recover/index.vue

@@ -0,0 +1,52 @@
+<!-- 会员机构管理-机构管理-机构资料管理-恢复 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :refresh="refresh" :loading="loading">
+        <div class="g-text-message">确认恢复该机构?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { organDetailRecover } from '@/services/api/member'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.OrganDetailListRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+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
+    organDetailRecover({
+        data: {
+            userid: props.record.userid
+        }
+    }).then(() => {
+        ElMessage.success('恢复成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('恢复失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 112 - 0
src/packages/pc/views/member/institution/user/components/terminal/index.vue

@@ -0,0 +1,112 @@
+<!-- 会员机构管理-机构管理-机构资料管理-自营会员登录账号 -->
+<template>
+    <teleport to="#appPageTeleport">
+        <app-view>
+            <template #header>
+                <app-filter :option="filterOption" />
+            </template>
+            <app-table :data="dataList" :columns="tableColumns" :loading="loading">
+                <template #headerLeft>
+                    <span>[{{ record.accountname }}]自营会员登录账号</span>
+                </template>
+                <template #headerRight>
+                    <div>
+                        <el-button @click="emit('closed')">{{ t('operation.close') }}</el-button>
+                    </div>
+                </template>
+                <!-- 操作 -->
+                <template #operate="{ row }">
+                    <el-button size="small" icon="Key" @click="showComponent('UpdatePassword', row)" circle plain />
+                    <el-button size="small" :icon="row.loginstatus === 1 ? 'Lock' : ''"
+                        @click="showComponent('UpdateStatus', 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 { shallowRef, PropType, defineAsyncComponent } from 'vue'
+import { ElMessage } from 'element-plus'
+import { formatDate } from '@/filters'
+import { useEnum } from '@/hooks/enum'
+import { useRequest } from '@/hooks/request'
+import { useDataFilter } from '@/hooks/datatable-v2'
+import { useComponent } from '@/hooks/component'
+import { queryselfsupport } from '@/services/api/member'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Model.OrganDetailListRsp>,
+        required: true
+    }
+})
+
+const componentMap = new Map<string, unknown>([
+    ['UpdateStatus', defineAsyncComponent(() => import('./status/index.vue'))], // 锁定/解锁
+    ['UpdatePassword', defineAsyncComponent(() => import('./password/index.vue'))], // 重置密码
+])
+
+const emit = defineEmits(['closed'])
+
+// 帐号状态
+const userstatusEnum = useEnum('userstatus')
+
+const selectedItem = shallowRef<Model.SelfSupportRsp>()
+
+const { global: { t } } = i18n
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => run())
+
+const { dataList, total, pageSize, pageIndex, loading, run } = useRequest(queryselfsupport, {
+    params: {
+        pageNum: 1,
+        pageSize: 20,
+        userid: props.record.userid
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { field: 'userid', label: '所属机构代码' },
+    { field: 'loginid', label: '登录账户' },
+    { field: 'loginstatus', label: '账户状态', formatValue: (val) => userstatusEnum.getEnumTypeName(val) },
+    { field: 'modifytime', label: '更新时间', formatValue: (val) => formatDate(val) },
+    { field: 'operate', label: 'common.operate', fixed: 'right' }
+])
+
+const { filterOption, getQueryParams, resetFilters } = useDataFilter<Model.SelfSupportReq>({
+    filters: [
+        {
+            field: 'loginid',
+            label: '登录账户'
+        },
+    ],
+    buttons: [
+        { label: t('operation.search'), className: 'el-button--primary', onClick: () => onSearch() },
+        { label: t('operation.reset'), className: 'el-button--primary', validateEvent: false, onClick: () => resetFilters() }
+    ]
+})
+
+const showComponent = (code: string, row?: Model.SelfSupportRsp) => {
+    selectedItem.value = row
+    openComponent(code)
+}
+
+const onSearch = (clear = false) => {
+    const qs = getQueryParams(clear)
+    run(qs)
+}
+</script>

+ 49 - 0
src/packages/pc/views/member/institution/user/components/terminal/password/index.vue

@@ -0,0 +1,49 @@
+<!-- 会员机构管理-机构管理-机构资料管理-自营会员登录账号-重置密码 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :loading="loading">
+        <div class="g-text-message">确认将密码重置?</div>
+        <template #footer>
+            <el-button @click="onCancel">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { selfsupportresetPwd } from '@/services/api/member'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.SelfSupportRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+const loading = shallowRef(false)
+
+const onCancel = () => {
+    show.value = false
+}
+
+const onSubmit = () => {
+    loading.value = true
+    selfsupportresetPwd({
+        data: {
+            loginid: props.selectedItem.loginid
+        }
+    }).then(() => {
+        ElMessage.success('重置成功')
+    }).catch((err) => {
+        ElMessage.error('重置失败:' + err)
+    }).finally(() => {
+        loading.value = false
+        onCancel()
+    })
+}
+</script>

+ 58 - 0
src/packages/pc/views/member/institution/user/components/terminal/status/index.vue

@@ -0,0 +1,58 @@
+<!-- 会员机构管理-机构管理-机构资料管理-自营会员登录账号-锁定/解锁 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :refresh="refresh" :loading="loading">
+        <div class="g-text-message">
+            <span v-if="isActivated">确认锁定该账户?</span>
+            <span v-else>确认解锁该账户?</span>
+        </div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType, computed } from 'vue'
+import { ElMessage } from 'element-plus'
+import { selfSupportLock } from '@/services/api/member'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    selectedItem: {
+        type: Object as PropType<Model.SelfSupportRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const isActivated = computed(() => props.selectedItem.loginstatus === 1)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    selfSupportLock({
+        data: {
+            loginid: props.selectedItem.loginid,
+            status: isActivated.value ? 2 : 1
+        }
+    }).then(() => {
+        ElMessage.success('提交成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('提交失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 17 - 1
src/packages/pc/views/member/institution/user/index.vue

@@ -121,7 +121,23 @@ const { filterOption, getQueryParams, resetFilters } = useDataFilter<Model.Organ
 
 // 处理操作按钮
 const handleOperateButtons = (row: Model.OrganDetailListRsp) => {
-    const buttons = ['member_institution_user_details', 'member_institution_user_modify', 'member_institution_user_account', 'member_institution_user_login', 'member_institution_user_terminal']
+    const buttons = ['member_institution_user_details']
+
+    if (row.accountstatus === 6) {
+        buttons.push('member_institution_user_recover')
+    } else {
+        buttons.push('member_institution_user_modify')
+        if (!row.roleIds) {
+            buttons.push('member_institution_user_close')
+        }
+    }
+
+    buttons.push('member_institution_user_account', 'member_institution_user_login')
+
+    if (row.roleIds?.split(',').includes('6')) {
+        buttons.push('member_institution_user_terminal')
+    }
+
     return getActionButtons(buttons)
 }
 

+ 70 - 1
src/services/api/member/index.ts

@@ -121,6 +121,27 @@ export function queryOrganDetail(options: CommonFetchOptions<{ request: Model.Or
 }
 
 /**
+ * 会员机构管理-->机构管理-->机构资料管理-->修改
+ */
+export function editOrgan(options: CommonFetchOptions<{ request: Partial<Model.EditOrganReq>; }>) {
+    return httpClient.commonRequest('/organDetail/editorgan', 'post', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->注销
+ */
+export function organDetailLogout(options: CommonFetchOptions<{ request: Model.OrganDetailLogoutReq; }>) {
+    return httpClient.commonRequest('/organDetail/logout', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->恢复
+ */
+export function organDetailRecover(options: CommonFetchOptions<{ request: Model.OrganDetailRecoverReq; }>) {
+    return httpClient.commonRequest('/organDetail/recover', 'get', options)
+}
+
+/**
  * 会员机构管理-->机构管理-->商品限制设置--> 新增、修改
  */
 export function addLimit(options: CommonFetchOptions<{ request: Model.AddLimitReq; }>) {
@@ -190,7 +211,6 @@ export function deleteAccountRiskConfig(options: CommonFetchOptions<{ request: M
     return httpClient.commonRequest('/organDetail/delaccountriskconfig', 'get', options)
 }
 
-
 /**
  * 会员机构管理-->机构管理-->机构资料管理-->资金账户-->获取列表
  */
@@ -224,4 +244,53 @@ export function taaccountEdit(options: CommonFetchOptions<{ request: Model.Taacc
  */
 export function taaccountResetPwd(options: CommonFetchOptions<{ request: Model.TaaccountResetPwdReq; }>) {
     return httpClient.commonRequest('/organDetail/resetPwd', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->登陆账号-->获取列表
+ */
+export function queryorgan2User(options: CommonFetchOptions<{ request: Model.Organ2UserReq; response: Model.Organ2UserRsp[]; }>) {
+    return httpClient.commonRequest('/organDetail/queryorgan2User', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->登入账号-->启用/停用
+ */
+export function updateStatusByAutoId(options: CommonFetchOptions<{ request: Model.UpdateStatusByAutoIdReq; }>) {
+    return httpClient.commonRequest('/organDetail/updatestatusbyautoid', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->登入账号-->全部启用/全部停用
+ */
+export function updateOrgan2User(options: CommonFetchOptions<{ request: Model.UpdateOrgan2UserReq; }>) {
+    return httpClient.commonRequest('/organDetail/updateorgan2User', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->登陆账号-->重置登入密码
+ */
+export function updateStatus(options: CommonFetchOptions<{ request: Model.UpdateStatusReq; }>) {
+    return httpClient.commonRequest('/organDetail/updateStatus', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->自营会员终端登录账号-->获取列表
+ */
+export function queryselfsupport(options: CommonFetchOptions<{ request: Model.SelfSupportReq; response: Model.SelfSupportRsp[]; }>) {
+    return httpClient.commonRequest('/organDetail/queryselfsupport', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->自营会员终端登录账号-->重置登录密码
+ */
+export function selfsupportresetPwd(options: CommonFetchOptions<{ request: Model.SelfSupportResetPwdReq; }>) {
+    return httpClient.commonRequest('/organDetail/selfsupportresetPwd', 'get', options)
+}
+
+/**
+ * 会员机构管理-->机构管理-->机构资料管理-->自营会员终端登录账号-->锁定
+ */
+export function selfSupportLock(options: CommonFetchOptions<{ request: Model.SelfSupportLockReq; }>) {
+    return httpClient.commonRequest('/organDetail/lockAccount', 'get', options)
 }

+ 116 - 4
src/types/model/member.d.ts

@@ -717,7 +717,7 @@ declare namespace Model {
     /** 会员机构管理-->机构管理-->商品限制设置-->获取列表 响应 */
     interface MemberGoodsLimitRsp {
         autoid: number
-         // 不能挂买
+        // 不能挂买
         cannotbuy: number
         // 不能挂卖
         cannotsell: number
@@ -727,7 +727,7 @@ declare namespace Model {
         membername: string
         // 不显示
         nodisplay: number
-         // 机构角色
+        // 机构角色
         roledisplay: string
     }
 
@@ -957,7 +957,7 @@ declare namespace Model {
     }
 
     // 机构资料信息
-    interface UserInfoVo { 
+    interface UserInfoVo {
         // 资金账户
         accountid: number
         // 账户名称(机构名称)
@@ -1490,7 +1490,7 @@ declare namespace Model {
         curRiskRate: number; // 风险率
         currency: string; // 币种
         isMain: number; // 账户类型 0 子账户,1 母账号
-        outThreshold:number; // 出金阈值
+        outThreshold: number; // 出金阈值
         parentAccountId: number; // 所属母账户
         relatedName: string; // 关联账户
         selfsupport: number; // 是否展示修改按钮
@@ -1593,4 +1593,116 @@ declare namespace Model {
     interface TaaccountResetPwdReq {
         accountid: number;
     }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->修改 请求 */
+    interface EditOrganReq {
+        accountname: string; // 机构名称
+        address: string; // 地址
+        attachment1: string; // 附件1
+        attachment2: string; // 附件2
+        autoid: number; // 管理员id
+        biznature: number; // 企业性质 公司
+        cardbackphotourl: string; // 证件照反面
+        cardfrontphotourl: string; // 证件照正面
+        cardnum: string; // 证件号码
+        cardtypeid: number; // 证件类型
+        cityid: number; // 市
+        company: string; // 公司 个人
+        contactname: string; // 联系人
+        customername: string; // 名称
+        districtid: number; // 区
+        email: string; // 邮箱
+        legalcardbackphotourl: string; // 法人身份证反面
+        legalcardfrontphotourl: string; // 法人身份证正面
+        legalpersonname: string; // 法人姓名
+        logincode: string; // 管理员登录帐号
+        mobile: string; // 手机号
+        modifystatus: number; // 修改用
+        parentuserid: number; // 父级userid
+        postalcode: string; // 邮政编码
+        provinceid: number; // 省
+        qq: string; // qq
+        reckonaccountid: number;
+        refereeuserid: number; // 修改用 推荐人
+        remark: string; // 备注
+        sex: number; // 性别
+        telphone: string; // 联系电话
+        userid: number; // 机构代码
+        userinfotype: number; // 所有者类型
+        username: string; // 管理员名称
+        usertype: number; // 平台、机构新增、修改固定为3
+        wechat: string; // 微信
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->注销 请求 */
+    interface OrganDetailLogoutReq {
+        userid: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->恢复 请求 */
+    interface OrganDetailRecoverReq {
+        userid: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->登陆账号-->获取列表 请求 */
+    interface Organ2UserReq {
+        userid: number;
+        pageNum: number;
+        pageSize: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->登陆账号-->获取列表 响应 */
+    interface Organ2UserRsp {
+        autoid: number;
+        areauserid: number; // 所属机构代码
+        logincode: number; // 登录账户
+        managerstatus: number; // 账户状态
+        modifytime: number; // 更新时间
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->登入账号-->启用/停用 请求 */
+    interface UpdateStatusByAutoIdReq {
+        autoid: number;
+        status: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->登入账号-->全部启用/全部停用 请求 */
+    interface UpdateOrgan2UserReq {
+        status: number;
+        userid: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->登陆账号-->重置登入密码 请求 */
+    interface UpdateStatusReq {
+        type: number;
+        userid: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->自营会员终端登录账号-->获取列表 请求 */
+    interface SelfSupportReq {
+        loginid?: number;
+        loginusertype?: number;
+        pageNum: number;
+        pageSize: number;
+        userid: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->自营会员终端登录账号-->获取列表 响应 */
+    interface SelfSupportRsp {
+        loginid: number; // 登录账户
+        loginstatus: number; // 账户状态
+        modifytime: string; // 更新时间
+        userid: number; // 所属机构代码
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->自营会员终端登录账号-->重置登录密码 请求 */
+    interface SelfSupportResetPwdReq {
+        loginid: number;
+    }
+
+    /** 会员机构管理-->机构管理-->机构资料管理-->自营会员终端登录账号-->锁定 请求 */
+    interface SelfSupportLockReq {
+        loginid: number;
+        status: number;
+    }
 }