mirror of
https://gitee.com/blackfox/geekai.git
synced 2024-12-02 12:17:42 +08:00
feat: add system configration switch option for order pay service, support sandbox env for alipay
This commit is contained in:
parent
7ca4dfe09b
commit
9dc9a6923e
@ -36,7 +36,7 @@ func NewDefaultConfig() *types.AppConfig {
|
||||
MjConfig: types.MidJourneyConfig{Enabled: false},
|
||||
SdConfig: types.StableDiffusionConfig{Enabled: false, Txt2ImgJsonPath: "res/text2img.json"},
|
||||
WeChatBot: false,
|
||||
AlipayConfig: types.AlipayConfig{Enabled: false},
|
||||
AlipayConfig: types.AlipayConfig{Enabled: false, SandBox: false},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@ type AliYunSmsConfig struct {
|
||||
|
||||
type AlipayConfig struct {
|
||||
Enabled bool // 是否启用该服务
|
||||
SandBox bool // 是否沙盒环境
|
||||
Company string // 公司名称
|
||||
UserId string // 支付宝用户 ID
|
||||
AppId string // 支付宝 AppID
|
||||
@ -69,7 +70,6 @@ type AlipayConfig struct {
|
||||
PublicKey string // 用户公钥文件路径
|
||||
AlipayPublicKey string // 支付宝公钥文件路径
|
||||
RootCert string // Root 秘钥路径
|
||||
ReturnURL string // 支付成功返回 URL
|
||||
NotifyURL string // 异步通知回调
|
||||
}
|
||||
|
||||
@ -144,5 +144,6 @@ type SystemConfig struct {
|
||||
RewardImg string `json:"reward_img"` // 众筹收款二维码地址
|
||||
EnabledFunction bool `json:"enabled_function"` // 启用 API 函数功能
|
||||
EnabledReward bool `json:"enabled_reward"` // 启用众筹功能
|
||||
EnabledAlipay bool `json:"enabled_alipay"` // 是否启用支付宝支付通道
|
||||
DefaultModels []string `json:"default_models"` // 默认开通的 AI 模型
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ func (h *PaymentHandler) Alipay(c *gin.Context) {
|
||||
h.db.Model(&order).UpdateColumn("status", types.OrderScanned)
|
||||
// 生成支付链接
|
||||
notifyURL := h.App.Config.AlipayConfig.NotifyURL
|
||||
returnURL := h.App.Config.AlipayConfig.ReturnURL
|
||||
returnURL := "" // 关闭同步回跳
|
||||
amount := fmt.Sprintf("%.2f", order.Amount)
|
||||
|
||||
uri, err := h.alipayService.PayUrlMobile(order.OrderNo, notifyURL, returnURL, amount, order.Subject)
|
||||
@ -113,6 +113,11 @@ func (h *PaymentHandler) OrderQuery(c *gin.Context) {
|
||||
|
||||
// AlipayQrcode 生成支付宝支付 URL 二维码
|
||||
func (h *PaymentHandler) AlipayQrcode(c *gin.Context) {
|
||||
if !h.App.SysConfig.EnabledAlipay {
|
||||
resp.ERROR(c, "当前支付通道已经关闭,请联系管理员开通!")
|
||||
return
|
||||
}
|
||||
|
||||
var data struct {
|
||||
ProductId uint `json:"product_id"`
|
||||
UserId int `json:"user_id"`
|
||||
|
@ -232,6 +232,7 @@ type userProfile struct {
|
||||
TotalTokens int64 `json:"total_tokens"`
|
||||
Tokens int64 `json:"tokens"`
|
||||
ExpiredTime int64 `json:"expired_time"`
|
||||
Vip bool `json:"vip"`
|
||||
}
|
||||
|
||||
func (h *UserHandler) Profile(c *gin.Context) {
|
||||
|
@ -28,7 +28,7 @@ func NewAlipayService(appConfig *types.AppConfig) (*AlipayService, error) {
|
||||
return nil, fmt.Errorf("error with read App Private key: %v", err)
|
||||
}
|
||||
|
||||
xClient, err := alipay.New(config.AppId, priKey, false)
|
||||
xClient, err := alipay.New(config.AppId, priKey, !config.SandBox)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error with initialize alipay service: %v", err)
|
||||
}
|
||||
|
@ -16,8 +16,14 @@
|
||||
<el-input v-model="form.mobile"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机验证码">
|
||||
<el-input v-model.number="form.code" maxlength="6" style="max-width: 200px; margin-right: 10px;"/>
|
||||
<send-msg size="" :mobile="form.mobile"/>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="16">
|
||||
<el-input v-model.number="form.code" maxlength="6"/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<send-msg size="" :mobile="form.mobile"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -81,6 +87,12 @@ const close = function () {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
#bind-mobile-form {
|
||||
.el-form-item__content {
|
||||
.el-row {
|
||||
width 100%
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -16,6 +16,14 @@
|
||||
</el-row>
|
||||
<el-form-item label="账户">
|
||||
<span>{{ user.mobile }}</span>
|
||||
<el-tooltip
|
||||
class="box-item"
|
||||
effect="light"
|
||||
content="您已经是 VIP 会员"
|
||||
placement="right"
|
||||
>
|
||||
<el-image v-if="user.vip" :src="vipImg" style="height: 25px;margin-left: 10px"/>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="剩余对话次数">
|
||||
<el-tag>{{ user['calls'] }}</el-tag>
|
||||
@ -60,6 +68,7 @@ import {dateFormat} from "@/utils/libs";
|
||||
import {checkSession} from "@/action/session";
|
||||
|
||||
const user = ref({
|
||||
vip: false,
|
||||
username: '',
|
||||
nickname: '',
|
||||
avatar: '',
|
||||
@ -68,6 +77,7 @@ const user = ref({
|
||||
tokens: 0,
|
||||
chat_config: {api_keys: {OpenAI: "", Azure: "", ChatGLM: ""}}
|
||||
})
|
||||
const vipImg = ref("/images/vip.png")
|
||||
|
||||
onMounted(() => {
|
||||
checkSession().then(() => {
|
||||
|
@ -194,8 +194,7 @@
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<config-dialog v-if="isLogin" :show="showConfigDialog" :models="models" @hide="showConfigDialog = false"
|
||||
@update-user="updateUser"/>
|
||||
<config-dialog v-if="isLogin" :show="showConfigDialog" :models="models" @hide="showConfigDialog = false"/>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -10,16 +10,20 @@
|
||||
|
||||
<el-row class="user-opt" :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-button type="primary">修改密码</el-button>
|
||||
<el-button type="primary" @click="showPasswordDialog = true">修改密码</el-button>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button type="primary">绑定手机号</el-button>
|
||||
<el-button type="primary" @click="showBindMobileDialog = true">绑定手机号</el-button>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button type="primary">加入众筹</el-button>
|
||||
<el-button type="primary" v-if="enableReward" @click="showRewardDialog = true">加入众筹</el-button>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button type="primary">众筹核销</el-button>
|
||||
<el-button type="primary" v-if="enableReward" @click="showRewardVerifyDialog = true">众筹核销</el-button>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" style="padding-top: 30px">
|
||||
<el-button type="danger" round @click="logout">退出登录</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
@ -67,7 +71,7 @@
|
||||
<password-dialog v-if="isLogin" :show="showPasswordDialog" @hide="showPasswordDialog = false"
|
||||
@logout="logout"/>
|
||||
|
||||
<bind-mobile v-if="isLogin" :show="showBindMobileDialog" :mobile="loginUser.mobile"
|
||||
<bind-mobile v-if="isLogin" :show="showBindMobileDialog" :mobile="user.mobile"
|
||||
@hide="showBindMobileDialog = false"/>
|
||||
|
||||
<reward-verify v-if="isLogin" :show="showRewardVerifyDialog" @hide="showRewardVerifyDialog = false"/>
|
||||
@ -81,7 +85,7 @@
|
||||
<el-alert type="info" :closable="false">
|
||||
<div style="font-size: 14px">您好,众筹 9.9元,就可以兑换 100 次对话,以此来覆盖我们的 OpenAI
|
||||
账单和服务器的费用。<strong
|
||||
style="color: #f56c6c">由于本人没有开通微信支付,付款后请凭借转账单号进入核销【众筹核销】菜单手动核销。</strong>
|
||||
style="color: #f56c6c">由于本人没有开通微信支付,付款后请凭借转账单号,点击【众筹核销】按钮手动核销。</strong>
|
||||
</div>
|
||||
</el-alert>
|
||||
<div style="text-align: center;padding-top: 10px;">
|
||||
@ -94,7 +98,7 @@
|
||||
:close-on-click-modal="false"
|
||||
:show-close="true"
|
||||
:width="400"
|
||||
title="用户登录">
|
||||
title="充值订单支付">
|
||||
<div class="pay-container">
|
||||
<div class="pay-qrcode">
|
||||
<el-image :src="qrcode"/>
|
||||
@ -130,6 +134,7 @@ import PasswordDialog from "@/components/PasswordDialog.vue";
|
||||
import BindMobile from "@/components/BindMobile.vue";
|
||||
import RewardVerify from "@/components/RewardVerify.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {removeUserToken} from "@/store/session";
|
||||
|
||||
const listBoxHeight = window.innerHeight - 97
|
||||
const list = ref([])
|
||||
@ -201,6 +206,15 @@ const queryOrder = (orderNo) => {
|
||||
})
|
||||
}
|
||||
|
||||
const logout = function () {
|
||||
httpGet('/api/user/logout').then(() => {
|
||||
removeUserToken();
|
||||
router.push('/login');
|
||||
}).catch(() => {
|
||||
ElMessage.error('注销失败!');
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
@ -90,6 +90,19 @@
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="启用支付宝" prop="enabled_alipay">
|
||||
<el-switch v-model="system['enabled_alipay']"/>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="是否启用支付宝支付功能,<br />请先在 config.toml 配置文件配置支付秘钥"
|
||||
raw-content
|
||||
placement="right"
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="默认AI模型" prop="default_models">
|
||||
<template #default>
|
||||
<div class="tip-input">
|
||||
|
@ -11,7 +11,12 @@
|
||||
<el-table :data="users.items" border class="table" :row-key="row => row.id"
|
||||
@selection-change="handleSelectionChange" table-layout="auto">
|
||||
<el-table-column type="selection" width="38"/>
|
||||
<el-table-column prop="mobile" label="账号"/>
|
||||
<el-table-column prop="mobile" label="账号">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.mobile }}</span>
|
||||
<el-image v-if="scope.row.vip" :src="vipImg" style="height: 20px;position: relative; top:5px; left: 5px"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="calls" label="剩余对话次数"/>
|
||||
<el-table-column prop="img_calls" label="剩余绘图次数"/>
|
||||
<el-table-column prop="total_tokens" label="累计消耗tokens"/>
|
||||
@ -74,7 +79,7 @@
|
||||
<el-input v-model.number="user.calls" autocomplete="off" placeholder="0"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="绘图次数:" prop="img_calls">
|
||||
<el-input v-model.number="user.img_calls" autocomplete="off" placeholder="0"/>
|
||||
<el-input v-model.number="user['img_calls']" autocomplete="off" placeholder="0"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="有效期:" prop="expired_time">
|
||||
@ -124,6 +129,10 @@
|
||||
<el-form-item label="启用状态">
|
||||
<el-switch v-model="user.status"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开通VIP">
|
||||
<el-switch v-model="user.vip"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
@ -140,8 +149,8 @@
|
||||
width="50%"
|
||||
>
|
||||
<el-form label-width="100px" ref="userEditFormRef">
|
||||
<el-form-item label="用户名:">
|
||||
<el-input v-model="pass.username" autocomplete="off" readonly disabled/>
|
||||
<el-form-item label="账户:">
|
||||
<el-input v-model="pass.mobile" autocomplete="off" readonly disabled/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="新密码:">
|
||||
@ -168,18 +177,18 @@ import {Plus, Search} from "@element-plus/icons-vue";
|
||||
|
||||
// 变量定义
|
||||
const users = ref({page: 1, page_size: 15, items: []})
|
||||
const query = ref({username: '', mobile: '', page: 1, page_size: 15})
|
||||
const query = ref({mobile: '', page: 1, page_size: 15})
|
||||
|
||||
const title = ref('添加用户')
|
||||
const vipImg = ref("/images/vip.png")
|
||||
const add = ref(true)
|
||||
const user = ref({chat_roles: [], chat_models: []})
|
||||
const pass = ref({username: '', password: '', id: 0})
|
||||
const pass = ref({mobile: '', password: '', id: 0})
|
||||
const roles = ref([])
|
||||
const models = ref([])
|
||||
const showUserEditDialog = ref(false)
|
||||
const showResetPassDialog = ref(false)
|
||||
const rules = reactive({
|
||||
username: [{required: true, message: '请输入用户名', trigger: 'change',}],
|
||||
nickname: [{required: true, message: '请输入昵称', trigger: 'change',}],
|
||||
password: [{required: true, message: '请输入密码', trigger: 'change',}],
|
||||
mobile: [{required: true, message: '请输入手机号码', trigger: 'change',}],
|
||||
@ -300,7 +309,7 @@ const handleSelectionChange = function (rows) {
|
||||
const resetPass = (row) => {
|
||||
showResetPassDialog.value = true
|
||||
pass.value.id = row.id
|
||||
pass.value.username = row.username
|
||||
pass.value.mobile = row.mobile
|
||||
}
|
||||
|
||||
const doResetPass = () => {
|
||||
|
Loading…
Reference in New Issue
Block a user