From 0dca2cc0ba3a58728d86ca0af07c92eab2b44c48 Mon Sep 17 00:00:00 2001
From: 李凌 <344137771@qq.com>
Date: Fri, 12 Jun 2026 16:12:00 +0800
Subject: [PATCH] Merge branch '2.10' of http://124.156.157.155:8060/r/dg/dabao-admin-new into 2.10

---
 src/locales/lang/zh-CN/account/settings.js    |    1 
 src/views/user/Login.vue                      |   15 +
 src/mock/services/user.js                     |   11 +
 src/api/managesettings.js                     |   34 +++
 src/locales/lang/en-US/account/settings.js    |    1 
 .env.preview                                  |    4 
 src/views/capital/withdrawallist.vue          |    2 
 src/views/account/settings/googleAuthCode.vue |  233 +++++++++++++++++++++++++
 .env.development                              |    2 
 src/views/capital/payOption.vue               |  187 ++++++++++++++++++++
 src/api/capital.js                            |   30 +++
 src/config/router.config.js                   |   12 +
 src/views/account/settings/Index.vue          |    5 
 13 files changed, 531 insertions(+), 6 deletions(-)

diff --git a/.env.development b/.env.development
index c7028ad..a8031e1 100644
--- a/.env.development
+++ b/.env.development
@@ -9,4 +9,4 @@
 # VUE_APP_API_BASE_URL=https://api.ispentagon-institution.com/
 # VUE_APP_API_BASE_URL= https://www.prudentcapitals.net/
 # VUE_APP_API_BASE_URL=https://api.guosen.org/
-VUE_APP_API_BASE_URL = https://api.nalandacapital.icu/
\ No newline at end of file
+VUE_APP_API_BASE_URL = https://api.nalandacapital.icu/
diff --git a/.env.preview b/.env.preview
index 1e843dc..c209e37 100644
--- a/.env.preview
+++ b/.env.preview
@@ -2,6 +2,6 @@
 
 VUE_APP_PREVIEW=true
 
-VUE_APP_API_BASE_URL=https://api.durocapital.top/
-
+VUE_APP_API_BASE_URL=https://api.nalandacapital.cyou/
+# VUE_APP_API_BASE_URL=http://192.168.10.11:8091/
 # VUE_APP_API_BASE_URL=http://192.168.10.4:8091/
\ No newline at end of file
diff --git a/src/api/capital.js b/src/api/capital.js
index 13b4eb2..8283558 100644
--- a/src/api/capital.js
+++ b/src/api/capital.js
@@ -12,6 +12,9 @@
   cashlist: '/admin/cash/list.do', // 资金记录
   logtransList: '/admin/log/transList.do', // 资金互转记录
   moneylog: '/admin/moneylog/moneylogAll.do', // 资金互转记录
+  payOptionList: '/admin/payOption/list.do', // 支付设置列表
+  payOptionUpdateSort: '/admin/payOption/updateSort.do', // 支付设置排序
+  payOptionSetEnabled: '/admin/payOption/setEnabled.do', // 支付设置开启/关闭
 }
 
 /**
@@ -115,3 +118,30 @@
     data: qs.stringify(parameter),
   })
 }
+
+export function payOptionList(parameter) {
+  return request({
+    url: userApi.payOptionList,
+    method: 'post',
+    data: qs.stringify(parameter || {}),
+  })
+}
+
+export function payOptionUpdateSort(parameter) {
+  return request({
+    url: userApi.payOptionUpdateSort,
+    method: 'post',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+    data: parameter,
+  })
+}
+
+export function payOptionSetEnabled(parameter) {
+  return request({
+    url: userApi.payOptionSetEnabled,
+    method: 'post',
+    data: qs.stringify(parameter),
+  })
+}
diff --git a/src/api/managesettings.js b/src/api/managesettings.js
index ecf9b15..44c1a75 100644
--- a/src/api/managesettings.js
+++ b/src/api/managesettings.js
@@ -4,7 +4,11 @@
     adminlist: '/admin/list.do', // 管理列表
     adminupdateLock: '/admin/updateLock.do', // 管理锁定 解锁
     adminadd: '/admin/add.do', // 添加管理员
-    adminupdate: '/admin/update.do' // 修改管理员密码
+    adminupdate: '/admin/update.do' ,// 修改管理员密码
+    getAdmin: '/api/admin/getAdmin',//获取当前管理用户信息
+    getLoginGoogleAuthSecret: '/api/admin/getLoginGoogleAuthSecret',//生成秘钥二维码
+    bindGoogleAuth: '/api/admin/bindGoogleAuth',//获取当前管理验证码
+    unbindingGoogleAuth:'/api/admin/unbindingGoogleAuth',//解绑
 }
 
 /**
@@ -18,6 +22,34 @@
  * @param parameter
  * @returns {*}
  */
+export function unbindingGoogleAuth (parameter) {
+    return request({
+        url: userApi.unbindingGoogleAuth,
+        method: 'post',
+        data: qs.stringify(parameter)
+    })
+}
+export function getLoginGoogleAuthSecret (parameter) {
+    return request({
+        url: userApi.getLoginGoogleAuthSecret,
+        method: 'get',
+        data: qs.stringify(parameter)
+    })
+}
+export function bindGoogleAuth (parameter) {
+    return request({
+        url: userApi.bindGoogleAuth,
+        method: 'post',
+        data: qs.stringify(parameter)
+    })
+}
+export function getAdmin (parameter) {
+    return request({
+        url: userApi.getAdmin,
+        method: 'get',
+        data: qs.stringify(parameter)
+    })
+}
 export function adminlist (parameter) {
     return request({
         url: userApi.adminlist,
diff --git a/src/config/router.config.js b/src/config/router.config.js
index ec00a19..2c8a98c 100644
--- a/src/config/router.config.js
+++ b/src/config/router.config.js
@@ -231,6 +231,12 @@
             component: () => import('@/views/capital/withdrawallist'),
             meta: { title: '提现列表', keepAlive: true, permission: ['withdrawallist'] },
           },
+          {
+            path: '/capital/payOption',
+            name: 'payOption',
+            component: () => import('@/views/capital/payOption.vue'),
+            meta: { title: '支付设置', keepAlive: true, permission: ['rechargelist'] },
+          },
           // {
           //   path: '/capital/fundrecords',
           //   name: 'fundrecords',
@@ -606,6 +612,12 @@
                   permission: ['user'],
                 },
               },
+              {
+                path: '/account/settings/googleAuthCode',
+                name: 'GoogleAuthCode',
+                component: () => import('@/views/account/settings/googleAuthCode'),
+                meta: { title: 'account.settings.menuMap.googleAuthCode', hidden: true, keepAlive: true, permission: ['user'] },
+              },
             ],
           },
         ],
diff --git a/src/locales/lang/en-US/account/settings.js b/src/locales/lang/en-US/account/settings.js
index c6c2eac..4ee5fa5 100644
--- a/src/locales/lang/en-US/account/settings.js
+++ b/src/locales/lang/en-US/account/settings.js
@@ -1,6 +1,7 @@
 export default {
   'account.settings.menuMap.basic': '基本设置',
   'account.settings.menuMap.security': '安全设置',
+  'account.settings.menuMap.googleAuthCode': '绑定谷歌验证器',
   'account.settings.menuMap.custom': '个性化',
   'account.settings.menuMap.binding': '账号绑定',
   'account.settings.menuMap.notification': '新消息通知',
diff --git a/src/locales/lang/zh-CN/account/settings.js b/src/locales/lang/zh-CN/account/settings.js
index c6c2eac..4ee5fa5 100644
--- a/src/locales/lang/zh-CN/account/settings.js
+++ b/src/locales/lang/zh-CN/account/settings.js
@@ -1,6 +1,7 @@
 export default {
   'account.settings.menuMap.basic': '基本设置',
   'account.settings.menuMap.security': '安全设置',
+  'account.settings.menuMap.googleAuthCode': '绑定谷歌验证器',
   'account.settings.menuMap.custom': '个性化',
   'account.settings.menuMap.binding': '账号绑定',
   'account.settings.menuMap.notification': '新消息通知',
diff --git a/src/mock/services/user.js b/src/mock/services/user.js
index 67e8081..f2eb3dc 100644
--- a/src/mock/services/user.js
+++ b/src/mock/services/user.js
@@ -869,6 +869,17 @@
       component: 'SecuritySettings'
     },
     {
+      name: 'GoogleAuthCode',
+      path: '/account/settings/googleAuthCode',
+      parentId: 10030,
+      id: 10033,
+      meta: {
+        title: 'account.settings.menuMap.googleAuthCode',
+        show: false
+      },
+      component: 'GoogleAuthCode'
+    },
+    {
       name: 'CustomSettings',
       path: '/account/settings/custom',
       parentId: 10030,
diff --git a/src/views/account/settings/Index.vue b/src/views/account/settings/Index.vue
index 32f268e..6dbaa8f 100644
--- a/src/views/account/settings/Index.vue
+++ b/src/views/account/settings/Index.vue
@@ -19,6 +19,11 @@
                 {{ $t('account.settings.menuMap.security') }}
               </router-link>
             </a-menu-item>
+            <a-menu-item key="/account/settings/googleAuthCode">
+              <router-link :to="{ name: 'GoogleAuthCode' }">
+                {{ $t('account.settings.menuMap.googleAuthCode') }}
+              </router-link>
+            </a-menu-item>
             <!-- <a-menu-item key="/account/settings/custom">
               <router-link :to="{ name: 'CustomSettings' }">
                 {{ $t('account.settings.menuMap.custom') }}
diff --git a/src/views/account/settings/googleAuthCode.vue b/src/views/account/settings/googleAuthCode.vue
new file mode 100644
index 0000000..5071ad4
--- /dev/null
+++ b/src/views/account/settings/googleAuthCode.vue
@@ -0,0 +1,233 @@
+<template>
+  <div class="account-settings-info-view">
+    <a-form layout="vertical" :form="addUserform" ref="addUserform" v-if="!googleAuthBind">
+      <a-row :gutter="16" type="flex" justify="center">
+        <a-col :order="isMobile ? 2 : 1" :md="24" :lg="16">
+          <a-form-item label="秘钥">
+            <a-input
+              placeholder="请点击右侧 生成秘钥和二维码"
+              readonly    
+              @click="handleCopy"
+              :addonAfter="addonContent"
+              v-decorator="['secret', { rules: [{ required: false, message: '请输入您的昵称' }] }]"
+            />
+            <img v-if="googleAuthimg" style="width: 100px;margin-top:10px;" :src="googleAuthimg"/>
+          </a-form-item>
+          
+          <a-form-item label="谷歌验证码">
+            <a-input
+              placeholder="请输入谷歌验证码"
+              v-decorator="['googleAuthCode', { rules: [{ required: true, message: '请输入谷歌验证码' }] }]"
+            />
+          </a-form-item>
+
+          <!-- <a-form-item label="超级谷歌验证码">
+            <a-input
+              placeholder="请输入超级谷歌验证码"
+              v-decorator="['rootGoogleAuthCode', { rules: [{ required: true, message: '请输入超级谷歌验证码' }] }]"
+            />
+          </a-form-item> -->
+          <a-form-item>
+            <a-button type="primary" @click="saveinfo">绑定</a-button>
+          </a-form-item>
+        </a-col>
+      </a-row>
+    </a-form>
+    <div v-else style="">
+      <div style="margin-bottom: 20px;">已绑定</div>
+      
+      <a-form-item label="谷歌验证码">
+        <a-input
+          placeholder="请输入谷歌验证码"
+          v-model="ggyzm"
+          v-decorator="['googleAuthCode', { rules: [{ required: true, message: '请输入谷歌验证码' }] }]"
+        />
+      </a-form-item>
+      
+      <a-button type="primary" @click="adskille">解绑</a-button>
+    </div>
+    <avatar-modal ref="modal" @ok="setavatar" />
+  </div>
+</template>
+
+<script>
+import AvatarModal from './AvatarModal'
+import { baseMixin } from '@/store/app-mixin'
+import { adminlist, adminupdate,bindGoogleAuth,getLoginGoogleAuthSecret,getAdmin,unbindingGoogleAuth } from '@/api/managesettings'
+import pick from 'lodash.pick'
+export default {
+  mixins: [baseMixin],
+  components: {
+    AvatarModal,
+  },
+  data() {
+    return {
+      // cropper
+      addonContent: (
+              <a
+                onClick={this.handleGenerate} // 这里是点击事件
+              >
+                生成秘钥和二维码
+              </a>
+      ),
+      preview: {},
+      googleAuthimg:'',
+      ggyzm:'',
+      userid:'',
+      googleAuthBind:'',
+      option: {
+        img: '/avatar2.jpg',
+        info: true,
+        size: 1,
+        outputType: 'jpeg',
+        canScale: false,
+        autoCrop: true,
+        // 只有自动截图开启 宽度高度才生效
+        autoCropWidth: 180,
+        autoCropHeight: 180,
+        fixedBox: true,
+        // 开启宽度和高度比例
+        fixed: true,
+        fixedNumber: [1, 1],
+      },
+      settingdetail: {},
+      addUserform: this.$form.createForm(this),
+      fields: ['googleAuthCode', 'secret','id'],
+    }
+  },
+  mounted() {
+    this.getnowuser()
+  },
+  methods: {
+    adskille(){
+          var values ={}
+          values.rootGoogleAuthCode = this.ggyzm
+          values.id = this.userid
+          unbindingGoogleAuth(values).then((res) => {
+            if (res.status == 0) {
+              this.getnowuser()
+              this.$message.success({ content: '解绑成功', duration: 2 });
+              form.resetFields();
+            } else {
+              this.$message.error(res.msg);
+            }
+          });
+    },
+    getnowuser() {
+      getAdmin().then((res) => {
+        if(res.status==0){
+          this.userid = res.data.id
+          this.googleAuthBind = res.data.googleAuthBind
+        }
+        console.log(res);
+      })
+    },
+    setavatar(url) {
+      this.option.img = url
+    },
+    handleCopy() {
+          // 使用浏览器的 execCommand 来实现复制功能
+          const input = document.createElement('input');
+          input.value = this.addUserform.getFieldValue('secret');  // 这里用你的秘钥变量
+          document.body.appendChild(input);
+          input.select();
+          document.execCommand('copy');
+          document.body.removeChild(input);
+    
+          this.$message.success('秘钥已复制');
+     },
+    handleGenerate() {
+      getLoginGoogleAuthSecret().then((res) => {
+        if (res.status == 0) {
+          // this.$set(this.$refs.addUserform.form, 'secret', res.data.googleAuthSecret);
+          this.addUserform.setFieldsValue({
+            secret: res.data.googleAuthSecret,
+          })
+          this.googleAuthimg = res.data.googleAuthImg;
+        } else {
+          this.$message.error(res.msg);
+        }
+      });
+    },
+    saveinfo() {
+      const form = this.$refs.addUserform.form;
+      form.validateFields((errors, values) => {
+        if (!errors) {
+          values.id = this.userid
+          bindGoogleAuth(values).then((res) => {
+            if (res.status == 0) {
+              this.getnowuser()
+              this.$message.success({ content: '绑定成功', duration: 2 });
+              form.resetFields();
+              this.getnowuser();
+            } else {
+              this.$message.error(res.msg);
+            }
+          });
+        }
+      });
+    }
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.avatar-upload-wrapper {
+  height: 200px;
+  width: 100%;
+}
+
+.ant-upload-preview {
+  position: relative;
+  margin: 0 auto;
+  width: 100%;
+  max-width: 180px;
+  border-radius: 50%;
+  box-shadow: 0 0 4px #ccc;
+
+  .upload-icon {
+    position: absolute;
+    top: 0;
+    right: 10px;
+    font-size: 1.4rem;
+    padding: 0.5rem;
+    background: rgba(222, 221, 221, 0.7);
+    border-radius: 50%;
+    border: 1px solid rgba(0, 0, 0, 0.2);
+  }
+
+  .mask {
+    opacity: 0;
+    position: absolute;
+    background: rgba(0, 0, 0, 0.4);
+    cursor: pointer;
+    transition: opacity 0.4s;
+
+    &:hover {
+      opacity: 1;
+    }
+
+    i {
+      font-size: 2rem;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      margin-left: -1rem;
+      margin-top: -1rem;
+      color: #d6d6d6;
+    }
+  }
+
+  img,
+  .mask {
+    width: 100%;
+    max-width: 180px;
+    height: 100%;
+    border-radius: 50%;
+    overflow: hidden;
+  }
+}
+</style>
+
+<style>
+</style>
\ No newline at end of file
diff --git a/src/views/capital/payOption.vue b/src/views/capital/payOption.vue
new file mode 100644
index 0000000..279bca5
--- /dev/null
+++ b/src/views/capital/payOption.vue
@@ -0,0 +1,187 @@
+<template>
+  <page-header-wrapper>
+    <a-card :bordered="false">
+      <a-table
+        bordered
+        :loading="loading"
+        :columns="columns"
+        :data-source="datalist"
+        :pagination="false"
+        rowKey="id"
+        :customRow="customRow"
+      >
+        <span slot="enabled" slot-scope="text, record">
+          <a-tag :color="record.enabled === 1 ? 'green' : 'red'">
+            {{ record.enabled === 1 ? '开启' : '关闭' }}
+          </a-tag>
+        </span>
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            type="link"
+            size="small"
+            @click="toggleEnabled(record)"
+            :loading="record._loading"
+          >
+            {{ record.enabled === 1 ? '关闭' : '开启' }}
+          </a-button>
+        </template>
+        <span slot="dragHandle" class="drag-handle">
+          <a-icon type="menu" />
+        </span>
+      </a-table>
+    </a-card>
+  </page-header-wrapper>
+</template>
+
+<script>
+import { payOptionList, payOptionUpdateSort, payOptionSetEnabled } from '@/api/capital'
+
+export default {
+  name: 'PayOption',
+  data() {
+    return {
+      columns: [
+        {
+          title: '排序',
+          key: 'sort',
+          width: 60,
+          align: 'center',
+          scopedSlots: { customRender: 'dragHandle' },
+        },
+        {
+          title: '名称',
+          dataIndex: 'name',
+          align: 'center',
+        },
+        {
+          title: '排序序号',
+          dataIndex: 'sortOrder',
+          align: 'center',
+          width: 120,
+        },
+        {
+          title: '状态',
+          dataIndex: 'enabled',
+          align: 'center',
+          width: 100,
+          scopedSlots: { customRender: 'enabled' },
+        },
+        {
+          title: '操作',
+          key: 'action',
+          align: 'center',
+          width: 120,
+          scopedSlots: { customRender: 'action' },
+        },
+      ],
+      loading: false,
+      datalist: [],
+      dragIndex: null,
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    getList() {
+      this.loading = true
+      payOptionList()
+        .then((res) => {
+          this.loading = false
+          if (res.status === 0 && Array.isArray(res.data)) {
+            this.datalist = (res.data || [])
+              .slice()
+              .sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0))
+          } else {
+            this.datalist = []
+          }
+        })
+        .catch(() => {
+          this.loading = false
+          this.datalist = []
+        })
+    },
+    customRow(record, index) {
+      return {
+        attrs: {
+          draggable: true,
+        },
+        on: {
+          dragstart: (e) => this.onDragStart(e, index),
+          dragover: (e) => this.onDragOver(e, index),
+          drop: (e) => this.onDrop(e, index),
+        },
+      }
+    },
+    onDragStart(e, index) {
+      this.dragIndex = index
+      e.dataTransfer.effectAllowed = 'move'
+      e.dataTransfer.setData('text/plain', index)
+      try {
+        e.target.classList.add('drag-over')
+      } catch (_) {}
+    },
+    onDragOver(e, index) {
+      e.preventDefault()
+      e.dataTransfer.dropEffect = 'move'
+    },
+    onDrop(e, dropIndex) {
+      e.preventDefault()
+      try {
+        e.target.classList.remove('drag-over')
+      } catch (_) {}
+      const dragIndex = this.dragIndex
+      if (dragIndex == null || dragIndex === dropIndex) return
+      const list = this.datalist.slice()
+      const [item] = list.splice(dragIndex, 1)
+      list.splice(dropIndex, 0, item)
+      this.datalist = list
+      this.dragIndex = null
+      const orderedIds = list.map((i) => i.id)
+      // console.log(orderedIds, 'orderedIds');
+      // return
+      payOptionUpdateSort(orderedIds)
+        .then((res) => {
+          if (res.status === 0) {
+            this.$message.success('排序已更新')
+          } else {
+            this.$message.error(res.msg || '排序更新失败')
+            this.getList()
+          }
+        })
+        .catch(() => {
+          this.$message.error('排序更新失败')
+          this.getList()
+        })
+    },
+    toggleEnabled(record) {
+      const enabled = record.enabled === 1 ? 0 : 1
+      this.$set(record, '_loading', true)
+      payOptionSetEnabled({ id: record.id, enabled })
+        .then((res) => {
+          this.$set(record, '_loading', false)
+          if (res.status === 0) {
+            record.enabled = enabled
+            this.$message.success(enabled === 1 ? '已开启' : '已关闭')
+          } else {
+            this.$message.error(res.msg || '操作失败')
+          }
+        })
+        .catch(() => {
+          this.$set(record, '_loading', false)
+          this.$message.error('操作失败')
+        })
+    },
+  },
+}
+</script>
+
+<style scoped>
+.drag-handle {
+  cursor: move;
+  color: #999;
+}
+.drag-handle:hover {
+  color: #1890ff;
+}
+</style>
diff --git a/src/views/capital/withdrawallist.vue b/src/views/capital/withdrawallist.vue
index 1327463..affcefc 100644
--- a/src/views/capital/withdrawallist.vue
+++ b/src/views/capital/withdrawallist.vue
@@ -128,7 +128,7 @@
         <a-button type="primary" style="background-color: " @click="OkeditOrderdialog(3)">驳回</a-button>
         <a-button type="primary" @click="OkeditOrderdialog(2)">通过</a-button>
         <a-button type="primary" @click="OkeditOrderdialog(1)">代付1</a-button>
-        <!-- <a-button type="primary" @click="OkeditOrderdialog(4)">代付2</a-button> -->
+        <a-button type="primary" @click="OkeditOrderdialog(4)">代付2</a-button>
       </div>
     </a-modal>
   </page-header-wrapper>
diff --git a/src/views/user/Login.vue b/src/views/user/Login.vue
index 25e90c9..b602264 100644
--- a/src/views/user/Login.vue
+++ b/src/views/user/Login.vue
@@ -36,6 +36,18 @@
               <a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }" />
             </a-input-password>
           </a-form-item>
+          
+          <a-form-item>
+            <a-input
+              size="large"
+              type="number" 
+              placeholder="请输入谷歌验证码"
+              v-decorator="[
+                'googleAuthCode',
+                { rules: [], validateTrigger: 'change' }
+              ]">
+            </a-input>
+          </a-form-item>
         </a-tab-pane>
         <!-- <a-tab-pane key="tab2" :tab="$t('user.login.tab-login-mobile')">
           <a-form-item>
@@ -174,7 +186,7 @@
 
       state.loginBtn = true
 
-      const validateFieldsKey = customActiveKey === 'tab1' ? ['username', 'password'] : ['mobile', 'captcha']
+      const validateFieldsKey = customActiveKey === 'tab1' ? ['username', 'password' ,'googleAuthCode'] : ['mobile', 'captcha']
 
       validateFields(validateFieldsKey, { force: true }, (err, values) => {
         if (!err) {
@@ -183,6 +195,7 @@
           const loginParams = {}
           loginParams.adminPhone = values.username
           loginParams.adminPwd = values.password
+          loginParams.googleAuthCode = values.googleAuthCode
           loginParams.verifyCode = 1234
           Login(loginParams)
             .then((res) => this.loginSuccess(res))

--
Gitblit v1.9.3