算力配置功能已完成

This commit is contained in:
GeekMaster
2025-08-28 14:59:42 +08:00
parent 77a8969f73
commit ebaaefaf7a
7 changed files with 220 additions and 252 deletions

View File

@@ -80,7 +80,6 @@ type BaseConfig struct {
LumaPower int `json:"luma_power,omitempty"` // Luma 生成视频消耗算力
KeLingPowers map[string]int `json:"keling_powers,omitempty"` // 可灵生成视频消耗算力
AdvanceVoicePower int `json:"advance_voice_power,omitempty"` // 高级语音对话消耗算力
PromptPower int `json:"prompt_power,omitempty"` // 生成提示词消耗算力
WechatCardURL string `json:"wechat_card_url,omitempty"` // 微信客服地址
@@ -94,7 +93,6 @@ type BaseConfig struct {
Copyright string `json:"copyright"` // 版权信息
DefaultNickname string `json:"default_nickname"` // 默认昵称
ICP string `json:"icp"` // ICP 备案号
MarkMapText string `json:"mark_map_text"` // 思维导入的默认文本
EnabledVerify bool `json:"enabled_verify"` // 是否启用验证码
EmailWhiteList []string `json:"email_white_list"` // 邮箱白名单列表

View File

@@ -140,17 +140,15 @@ func (h *ConfigHandler) UpdateBase(c *gin.Context) {
// UpdatePower 更新系统配置
func (h *ConfigHandler) UpdatePower(c *gin.Context) {
var data struct {
InitPower int `json:"init_power,omitempty"` // 新用户注册赠送算力值
DailyPower int `json:"daily_power,omitempty"` // 每日签到赠送算力
InvitePower int `json:"invite_power,omitempty"` // 邀请新用户赠送算力值
MjPower int `json:"mj_power,omitempty"` // MJ 绘画消耗算力
MjActionPower int `json:"mj_action_power,omitempty"` // MJ 操作(放大,变换)消耗算力
SdPower int `json:"sd_power,omitempty"` // SD 绘画消耗算力
SunoPower int `json:"suno_power,omitempty"` // Suno 生成歌曲消耗算力
LumaPower int `json:"luma_power,omitempty"` // Luma 生成视频消耗算力
KeLingPowers map[string]int `json:"keling_powers,omitempty"` // 可灵生成视频消耗算力
AdvanceVoicePower int `json:"advance_voice_power,omitempty"` // 高级语音对话消耗算力
PromptPower int `json:"prompt_power,omitempty"` // 生成提示词消耗算力
InitPower int `json:"init_power,omitempty"` // 新用户注册赠送算力值
DailyPower int `json:"daily_power,omitempty"` // 每日签到赠送算力
InvitePower int `json:"invite_power,omitempty"` // 邀请新用户赠送算力值
MjPower int `json:"mj_power,omitempty"` // MJ 绘画消耗算力
MjActionPower int `json:"mj_action_power,omitempty"` // MJ 操作(放大,变换)消耗算力
SdPower int `json:"sd_power,omitempty"` // SD 绘画消耗算力
SunoPower int `json:"suno_power,omitempty"` // Suno 生成歌曲消耗算力
LumaPower int `json:"luma_power,omitempty"` // Luma 生成视频消耗算力
KeLingPowers map[string]int `json:"keling_powers,omitempty"` // 可灵生成视频消耗算力
}
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
@@ -166,8 +164,6 @@ func (h *ConfigHandler) UpdatePower(c *gin.Context) {
h.sysConfig.Base.SunoPower = data.SunoPower
h.sysConfig.Base.LumaPower = data.LumaPower
h.sysConfig.Base.KeLingPowers = data.KeLingPowers
h.sysConfig.Base.AdvanceVoicePower = data.AdvanceVoicePower
h.sysConfig.Base.PromptPower = data.PromptPower
err := h.Update(types.ConfigKeySystem, h.sysConfig.Base)
if err != nil {

View File

@@ -14,7 +14,6 @@ import (
"geekai/core/middleware"
"geekai/core/types"
"geekai/service"
"geekai/service/crawler"
"geekai/service/dalle"
"geekai/service/oss"
"geekai/store/model"
@@ -66,7 +65,6 @@ func (h *FunctionHandler) RegisterRoutes() {
group.POST("weibo", h.WeiBo)
group.POST("zaobao", h.ZaoBao)
group.POST("dalle3", h.Dall3)
group.POST("websearch", h.WebSearch)
}
}
@@ -189,140 +187,140 @@ func (h *FunctionHandler) Dall3(c *gin.Context) {
return
}
var params map[string]interface{}
if err := c.ShouldBindJSON(&params); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
// var params map[string]interface{}
// if err := c.ShouldBindJSON(&params); err != nil {
// resp.ERROR(c, types.InvalidArgs)
// return
// }
logger.Debugf("绘画参数:%+v", params)
var user model.User
res := h.DB.Where("id = ?", params["user_id"]).First(&user)
if res.Error != nil {
resp.ERROR(c, "当前用户不存在!")
return
}
// logger.Debugf("绘画参数:%+v", params)
// var user model.User
// res := h.DB.Where("id = ?", params["user_id"]).First(&user)
// if res.Error != nil {
// resp.ERROR(c, "当前用户不存在!")
// return
// }
if user.Power < h.App.SysConfig.Base.DallPower {
resp.ERROR(c, "创建 DALL-E 绘图任务失败,算力不足")
return
}
// if user.Power < h.App.SysConfig.Base.DallPower {
// resp.ERROR(c, "创建 DALL-E 绘图任务失败,算力不足")
// return
// }
// create dall task
prompt := utils.InterfaceToString(params["prompt"])
task := types.DallTask{
UserId: user.Id,
Prompt: prompt,
ModelId: 0,
ModelName: "dall-e-3",
TranslateModelId: h.App.SysConfig.Base.AssistantModelId,
N: 1,
Quality: "standard",
Size: "1024x1024",
Style: "vivid",
Power: h.App.SysConfig.Base.DallPower,
}
job := model.DallJob{
UserId: user.Id,
Prompt: prompt,
Power: h.App.SysConfig.Base.DallPower,
TaskInfo: utils.JsonEncode(task),
}
err := h.DB.Create(&job).Error
if err != nil {
resp.ERROR(c, "创建 DALL-E 绘图任务失败:"+err.Error())
return
}
// // create dall task
// prompt := utils.InterfaceToString(params["prompt"])
// task := types.DallTask{
// UserId: user.Id,
// Prompt: prompt,
// ModelId: 0,
// ModelName: "dall-e-3",
// TranslateModelId: h.App.SysConfig.Base.AssistantModelId,
// N: 1,
// Quality: "standard",
// Size: "1024x1024",
// Style: "vivid",
// Power: h.App.SysConfig.Base.DallPower,
// }
// job := model.DallJob{
// UserId: user.Id,
// Prompt: prompt,
// Power: h.App.SysConfig.Base.DallPower,
// TaskInfo: utils.JsonEncode(task),
// }
// err := h.DB.Create(&job).Error
// if err != nil {
// resp.ERROR(c, "创建 DALL-E 绘图任务失败:"+err.Error())
// return
// }
task.Id = job.Id
content, err := h.dallService.Image(task, true)
if err != nil {
resp.ERROR(c, "任务执行失败:"+err.Error())
return
}
// task.Id = job.Id
// content, err := h.dallService.Image(task, true)
// if err != nil {
// resp.ERROR(c, "任务执行失败:"+err.Error())
// return
// }
// 扣减算力
err = h.userService.DecreasePower(user.Id, job.Power, model.PowerLog{
Type: types.PowerConsume,
Model: task.ModelName,
Remark: fmt.Sprintf("绘画提示词:%s", utils.CutWords(job.Prompt, 10)),
})
if err != nil {
resp.ERROR(c, "扣减算力失败:"+err.Error())
return
}
// // 扣减算力
// err = h.userService.DecreasePower(user.Id, job.Power, model.PowerLog{
// Type: types.PowerConsume,
// Model: task.ModelName,
// Remark: fmt.Sprintf("绘画提示词:%s", utils.CutWords(job.Prompt, 10)),
// })
// if err != nil {
// resp.ERROR(c, "扣减算力失败:"+err.Error())
// return
// }
resp.SUCCESS(c, content)
}
// resp.SUCCESS(c, content)
// }
// 实现一个联网搜索的函数工具,采用爬虫实现
func (h *FunctionHandler) WebSearch(c *gin.Context) {
if err := h.checkAuth(c); err != nil {
resp.ERROR(c, err.Error())
return
}
// // 实现一个联网搜索的函数工具,采用爬虫实现
// func (h *FunctionHandler) WebSearch(c *gin.Context) {
// if err := h.checkAuth(c); err != nil {
// resp.ERROR(c, err.Error())
// return
// }
var params map[string]interface{}
if err := c.ShouldBindJSON(&params); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
// var params map[string]interface{}
// if err := c.ShouldBindJSON(&params); err != nil {
// resp.ERROR(c, types.InvalidArgs)
// return
// }
// 从参数中获取搜索关键词
keyword, ok := params["keyword"].(string)
if !ok || keyword == "" {
resp.ERROR(c, "搜索关键词不能为空")
return
}
// // 从参数中获取搜索关键词
// keyword, ok := params["keyword"].(string)
// if !ok || keyword == "" {
// resp.ERROR(c, "搜索关键词不能为空")
// return
// }
// 从参数中获取最大页数默认为1页
maxPages := 1
if pages, ok := params["max_pages"].(float64); ok {
maxPages = int(pages)
}
// // 从参数中获取最大页数默认为1页
// maxPages := 1
// if pages, ok := params["max_pages"].(float64); ok {
// maxPages = int(pages)
// }
// 获取用户ID
userID, ok := params["user_id"].(float64)
if !ok {
resp.ERROR(c, "用户ID不能为空")
return
}
// // 获取用户ID
// userID, ok := params["user_id"].(float64)
// if !ok {
// resp.ERROR(c, "用户ID不能为空")
// return
// }
// 查询用户信息
var user model.User
res := h.DB.Where("id = ?", int(userID)).First(&user)
if res.Error != nil {
resp.ERROR(c, "用户不存在")
return
}
// // 查询用户信息
// var user model.User
// res := h.DB.Where("id = ?", int(userID)).First(&user)
// if res.Error != nil {
// resp.ERROR(c, "用户不存在")
// return
// }
// 检查用户算力是否足够
searchPower := 1 // 每次搜索消耗1点算力
if user.Power < searchPower {
resp.ERROR(c, "算力不足,无法执行网络搜索")
return
}
// // 检查用户算力是否足够
// searchPower := 1 // 每次搜索消耗1点算力
// if user.Power < searchPower {
// resp.ERROR(c, "算力不足,无法执行网络搜索")
// return
// }
// 执行网络搜索
searchResults, err := crawler.SearchWeb(keyword, maxPages)
if err != nil {
resp.ERROR(c, fmt.Sprintf("搜索失败: %v", err))
return
}
// // 执行网络搜索
// searchResults, err := crawler.SearchWeb(keyword, maxPages)
// if err != nil {
// resp.ERROR(c, fmt.Sprintf("搜索失败: %v", err))
// return
// }
// 扣减用户算力
err = h.userService.DecreasePower(user.Id, searchPower, model.PowerLog{
Type: types.PowerConsume,
Model: "web_search",
Remark: fmt.Sprintf("网络搜索:%s", utils.CutWords(keyword, 10)),
})
if err != nil {
resp.ERROR(c, "扣减算力失败:"+err.Error())
return
}
// // 扣减用户算力
// err = h.userService.DecreasePower(user.Id, searchPower, model.PowerLog{
// Type: types.PowerConsume,
// Model: "web_search",
// Remark: fmt.Sprintf("网络搜索:%s", utils.CutWords(keyword, 10)),
// })
// if err != nil {
// resp.ERROR(c, "扣减算力失败:"+err.Error())
// return
// }
// 返回搜索结果
resp.SUCCESS(c, searchResults)
// resp.SUCCESS(c, searchResults)
}
// List 获取所有的工具函数列表

View File

@@ -17,6 +17,7 @@ import (
"geekai/utils"
"geekai/utils/resp"
"strings"
"time"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
@@ -45,7 +46,7 @@ func (h *PromptHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/prompt/")
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis)).Use(middleware.RateLimitEvery(h.App.Redis, 30*time.Second))
{
group.POST("lyric", h.Lyric)
group.POST("image", h.Image)
@@ -69,19 +70,6 @@ func (h *PromptHandler) Lyric(c *gin.Context) {
return
}
if h.App.SysConfig.Base.PromptPower > 0 {
userId := h.GetLoginUserId(c)
err = h.userService.DecreasePower(userId, h.App.SysConfig.Base.PromptPower, model.PowerLog{
Type: types.PowerConsume,
Model: h.getPromptModel(),
Remark: "生成歌词",
})
if err != nil {
resp.ERROR(c, err.Error())
return
}
}
resp.SUCCESS(c, content)
}
@@ -99,18 +87,7 @@ func (h *PromptHandler) Image(c *gin.Context) {
resp.ERROR(c, err.Error())
return
}
if h.App.SysConfig.Base.PromptPower > 0 {
userId := h.GetLoginUserId(c)
err = h.userService.DecreasePower(userId, h.App.SysConfig.Base.PromptPower, model.PowerLog{
Type: types.PowerConsume,
Model: h.getPromptModel(),
Remark: "生成绘画提示词",
})
if err != nil {
resp.ERROR(c, err.Error())
return
}
}
resp.SUCCESS(c, strings.Trim(content, `"`))
}
@@ -129,19 +106,6 @@ func (h *PromptHandler) Video(c *gin.Context) {
return
}
if h.App.SysConfig.Base.PromptPower > 0 {
userId := h.GetLoginUserId(c)
err = h.userService.DecreasePower(userId, h.App.SysConfig.Base.PromptPower, model.PowerLog{
Type: types.PowerConsume,
Model: h.getPromptModel(),
Remark: "生成视频脚本",
})
if err != nil {
resp.ERROR(c, err.Error())
return
}
}
resp.SUCCESS(c, strings.Trim(content, `"`))
}

View File

@@ -13,6 +13,9 @@
<div class="cell-item">License Key</div>
</template>
{{ license.key }}
<el-tooltip content="复制" placement="top">
<i class="iconfont icon-copy ml-2 cursor-pointer" @click="copy(license.key)"></i>
</el-tooltip>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
@@ -105,6 +108,11 @@ const active = () => {
ElMessage.error(e.message)
})
}
const copy = (text) => {
navigator.clipboard.writeText(text)
ElMessage.success('复制成功')
}
</script>
<style scoped>

View File

@@ -1,18 +1,48 @@
<template>
<div class="container py-3 px-10" v-loading="loading">
<el-tabs v-model="active">
<el-tabs v-model="active" type="border-card">
<el-tab-pane label="支付宝" name="alipay">
<el-form :model="alipay" label-width="140px">
<el-form-item label="启用通道"><el-switch v-model="alipay.enabled" /></el-form-item>
<el-form-item label="沙盒模式"><el-switch v-model="alipay.sandbox" /></el-form-item>
<el-form-item label="AppId"><el-input v-model="alipay.app_id" /></el-form-item>
<template #label>
<div class="d-flex align-items-center text-blue-600">
<i class="iconfont icon-alipay"></i>
<span class="ms-2">支付宝</span>
</div>
</template>
<div class="rounded-md bg-blue-100 p-3 text-gray-500 border-blue-500 border-2 text-base">
如果你不知道怎么获取这些配置信息请参考文档
<a
href="https://docs.geekai.me/plus/config/payment.html#%E6%94%AF%E4%BB%98%E5%AE%9D%E9%85%8D%E7%BD%AE"
target="_blank"
>支付宝配置</a
>
</div>
<el-form :model="alipay" label-width="140px" label-position="top">
<el-form-item label="商户ID"><el-input v-model="alipay.app_id" /></el-form-item>
<el-form-item label="商户私钥"
><el-input v-model="alipay.private_key" type="textarea" :rows="5"
/></el-form-item>
<el-form-item label="支付宝公钥"
><el-input v-model="alipay.alipay_public_key" type="textarea" :rows="3"
/></el-form-item>
<el-form-item label="回调域名"><el-input v-model="alipay.domain" /></el-form-item>
<el-form-item
label="回调域名(<span class='text-red-500'>请确保回调域名已备案且在支付宝应用添加了白名单</span>"
>
<template #label>
<label class="form-label"
>支付回调域名
<el-tooltip
placement="top"
content="请确保回调域名已备案且在支付宝应用添加了白名单"
>
<i class="iconfont icon-info"></i>
</el-tooltip>
</label>
</template>
<el-input v-model="alipay.domain" />
</el-form-item>
<el-form-item label="启用该支付通道"><el-switch v-model="alipay.enabled" /></el-form-item>
<el-form-item label="启用沙盒模式"><el-switch v-model="alipay.sandbox" /></el-form-item>
<el-form-item>
<el-button type="primary" @click="save('alipay')">保存</el-button>
<el-button @click="test('alipay')">测试</el-button>
@@ -21,16 +51,16 @@
</el-tab-pane>
<el-tab-pane label="微信支付" name="wxpay">
<el-form :model="wechat" label-width="140px">
<el-form-item label="启用通道"><el-switch v-model="wechat.enabled" /></el-form-item>
<el-form-item label="AppId"><el-input v-model="wechat.app_id" /></el-form-item>
<el-form-item label="商户号(MchId)"><el-input v-model="wechat.mch_id" /></el-form-item>
<el-form-item label="证书序列号"><el-input v-model="wechat.serial_no" /></el-form-item>
<el-form :model="wxpay" label-width="140px">
<el-form-item label="启用通道"><el-switch v-model="wxpay.enabled" /></el-form-item>
<el-form-item label="AppId"><el-input v-model="wxpay.app_id" /></el-form-item>
<el-form-item label="商户号(MchId)"><el-input v-model="wxpay.mch_id" /></el-form-item>
<el-form-item label="证书序列号"><el-input v-model="wxpay.serial_no" /></el-form-item>
<el-form-item label="商户私钥"
><el-input v-model="wechat.private_key" type="textarea" :rows="3"
><el-input v-model="wxpay.private_key" type="textarea" :rows="3"
/></el-form-item>
<el-form-item label="APIv3 Key"><el-input v-model="wechat.api_v3_key" /></el-form-item>
<el-form-item label="回调域名"><el-input v-model="wechat.domain" /></el-form-item>
<el-form-item label="APIv3 Key"><el-input v-model="wxpay.api_v3_key" /></el-form-item>
<el-form-item label="回调域名"><el-input v-model="wxpay.domain" /></el-form-item>
<el-form-item>
<el-button type="primary" @click="save('wxpay')">保存</el-button>
<el-button @click="test('wxpay')">测试</el-button>
@@ -54,22 +84,20 @@
</el-form>
</el-tab-pane>
<el-tab-pane label="GeekPay" name="geekpay">
<el-form :model="geekpay" label-width="140px">
<el-form-item label="启用通道"><el-switch v-model="geekpay.enabled" /></el-form-item>
<el-form-item label="商户ID"><el-input v-model="geekpay.app_id" /></el-form-item>
<el-tab-pane label="易支付" name="epay">
<el-form :model="epay" label-width="140px">
<el-form-item label="启用通道"><el-switch v-model="epay.enabled" /></el-form-item>
<el-form-item label="商户ID"><el-input v-model="epay.app_id" /></el-form-item>
<el-form-item label="商户私钥"
><el-input v-model="geekpay.private_key" type="textarea" :rows="3"
><el-input v-model="epay.private_key" type="textarea" :rows="3"
/></el-form-item>
<el-form-item label="网关地址"><el-input v-model="geekpay.api_url" /></el-form-item>
<el-form-item label="异步通知URL"><el-input v-model="geekpay.notify_url" /></el-form-item>
<el-form-item label="同步回跳URL"><el-input v-model="geekpay.return_url" /></el-form-item>
<el-form-item label="支付方式"
><items-input v-model:value="geekpay.methods"
<el-form-item label="网关地址"><el-input v-model="epay.api_url" /></el-form-item>
<el-form-item label="回调域名(请确保回调域名已备案且在支付宝应用添加了白名单)"
><el-input v-model="epay.domain"
/></el-form-item>
<el-form-item>
<el-button type="primary" @click="save('geekpay')">保存</el-button>
<el-button @click="test('geekpay')">测试</el-button>
<el-button type="primary" @click="save('epay')">保存</el-button>
<el-button @click="test('epay')">测试</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
@@ -78,13 +106,15 @@
</template>
<script setup>
import ItemsInput from '@/components/ui/ItemsInput.vue'
import { httpGet, httpPost } from '@/utils/http'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue'
const loading = ref(true)
const active = ref('alipay')
const domain = computed(() => {
return window.location.origin
})
const alipay = ref({
enabled: false,
@@ -94,7 +124,7 @@ const alipay = ref({
alipay_public_key: '',
domain: '',
})
const wechat = ref({
const wxpay = ref({
enabled: false,
app_id: '',
mch_id: '',
@@ -110,28 +140,42 @@ onMounted(() => {
.then((res) => {
const data = res.data || {}
alipay.value = { ...alipay.value, ...(data.alipay || {}) }
wechat.value = { ...wechat.value, ...(data.wxpay || data.wechat || {}) }
wxpay.value = { ...wxpay.value, ...(data.wxpay || data.wechat || {}) }
epay.value = { ...epay.value, ...(data.epay || {}) }
// 如果 domain 为空,则设置为当前域名
if (!alipay.value.domain) {
alipay.value.domain = domain.value
}
if (!wxpay.value.domain) {
wxpay.value.domain = domain.value
}
if (!epay.value.domain) {
epay.value.domain = domain.value
}
})
.catch(() => {})
.finally(() => (loading.value = false))
})
const save = (key) => {
const payload = { alipay: alipay.value, wxpay: wechat.value, epay: epay.value }
const save = () => {
const payload = { alipay: alipay.value, wxpay: wxpay.value, epay: epay.value }
httpPost('/api/admin/config/update/payment', payload)
.then(() => ElMessage.success('保存成功'))
.catch((e) => ElMessage.error(e.message))
}
const test = (key) => {
// 后端未提供独立测试接口,保留占位提示
ElMessage.info('请在支付端自行验证配置')
}
</script>
<style scoped>
.form {
padding: 10px 20px 40px 20px;
<style lang="scss" scoped>
.container {
form {
padding: 20px;
}
a {
color: #409eff;
&:hover {
text-decoration: underline;
}
}
}
</style>

View File

@@ -92,42 +92,6 @@
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<template #label>
<div class="label-title">
高级语音算力
<el-tooltip
effect="dark"
content="使用一次 OpenAI 高级语音对话消耗的算力"
raw-content
placement="right"
>
<el-icon>
<InfoFilled />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input v-model.number="system['advance_voice_power']" placeholder="" />
</el-form-item>
<el-form-item>
<template #label>
<div class="label-title">
提示词算力
<el-tooltip
effect="dark"
content="生成AI绘图提示词歌词视频描述消耗的算力"
raw-content
placement="right"
>
<el-icon>
<InfoFilled />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input v-model.number="system['prompt_power']" placeholder="" />
</el-form-item>
</div>
<div style="padding: 10px">
@@ -142,7 +106,6 @@
<script setup>
import { httpGet, httpPost } from '@/utils/http'
import { copyObj } from '@/utils/libs'
import { InfoFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { onMounted, reactive, ref } from 'vue'
@@ -186,12 +149,9 @@ const save = function () {
daily_power: system.value.daily_power,
mj_power: system.value.mj_power,
sd_power: system.value.sd_power,
dall_power: system.value.dall_power,
suno_power: system.value.suno_power,
luma_power: system.value.luma_power,
keling_powers: system.value.keling_powers,
advance_voice_power: system.value.advance_voice_power,
prompt_power: system.value.prompt_power,
})
.then(() => {
ElMessage.success('操作成功!')