如果管理后台没有启用会员充值菜单,移动端也不显示充值套餐功能

This commit is contained in:
GeekMaster
2025-05-27 16:49:31 +08:00
parent a7063bf30a
commit 6b6fe1bebd
7 changed files with 353 additions and 304 deletions

View File

@@ -10,6 +10,7 @@
- 功能优化:修改重新回答功能,撤回千面的问答内容为可编辑内容,撤回的内容不会增加额外的上下文
- 功能优化:优化聊天记录的存储结构,增加模型名称字段,支持存储更长的模型名称
- Bug 修复:聊天应用绑定模型后无效,还是会轮询 API KEY导致一会成功一会请求失败。
- 功能优化:如果管理后台没有启用会员充值菜单,移动端也不显示充值套餐功能
## v4.2.3

View File

@@ -6,35 +6,41 @@
</div>
<div class="chat-icon">
<van-image :src="icon"/>
<van-image :src="icon" />
</div>
</div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import Clipboard from "clipboard";
import {showNotify} from "vant";
import Clipboard from 'clipboard'
import { showNotify } from 'vant'
import { onMounted, ref } from 'vue'
// eslint-disable-next-line no-unused-vars,no-undef
const props = defineProps({
content: {
type: String,
default: '',
type: Object,
default: {
text: '',
files: [],
},
},
icon: {
type: String,
default: '/images/user-icon.png',
}
});
},
})
const contentRef = ref(null)
const content = computed(() => {
return props.content.text
})
onMounted(() => {
const clipboard = new Clipboard(contentRef.value);
const clipboard = new Clipboard(contentRef.value)
clipboard.on('success', () => {
showNotify({type: 'success', message: '复制成功', duration: 1000})
showNotify({ type: 'success', message: '复制成功', duration: 1000 })
})
clipboard.on('error', () => {
showNotify({type: 'danger', message: '复制失败', duration: 2000})
showNotify({ type: 'danger', message: '复制失败', duration: 2000 })
})
})
</script>
@@ -100,4 +106,4 @@ onMounted(() => {
}
}
}
</style>
</style>

View File

@@ -28,8 +28,11 @@ import { showImagePreview } from 'vant'
import Thinking from '../Thinking.vue'
const props = defineProps({
content: {
type: String,
default: '',
type: Object,
default: {
text: '',
files: [],
},
},
orgContent: {
type: String,
@@ -41,6 +44,9 @@ const props = defineProps({
},
})
const content = computed(() => {
return props.content.text
})
const contentRef = ref(null)
onMounted(() => {
const imgs = contentRef.value.querySelectorAll('img')

View File

@@ -86,16 +86,15 @@ import ThemeChange from '@/components/ThemeChange.vue'
import { checkSession, getLicenseInfo, getSystemInfo } from '@/store/cache'
import { removeUserToken } from '@/store/session'
import { httpGet } from '@/utils/http'
import { isMobile } from '@/utils/libs'
import { ElMessage } from 'element-plus'
import { onMounted, onUnmounted, ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
if (isMobile()) {
router.push('/mobile/index')
}
// if (isMobile()) {
// router.push('/mobile/index')
// }
const title = ref('')
const logo = ref('')

View File

@@ -15,43 +15,47 @@
<div class="chat-list-wrapper">
<div id="message-list-box" class="message-list-box">
<van-list
v-model:error="error"
:finished="finished"
error-text="请求失败点击重新加载"
@load="onLoad"
v-model:error="error"
:finished="finished"
error-text="请求失败点击重新加载"
@load="onLoad"
>
<van-cell v-for="item in chatData" :key="item" :border="false" class="message-line">
<chat-prompt
v-if="item.type==='prompt'"
:content="item.content"
:created-at="dateFormat(item['created_at'])"
:icon="item.icon"
:tokens="item['tokens']"/>
<chat-reply v-else-if="item.type==='reply'"
:content="item.content"
:created-at="dateFormat(item['created_at'])"
:icon="item.icon"
:org-content="item.orgContent"
:tokens="item['tokens']"/>
v-if="item.type === 'prompt'"
:content="item.content"
:created-at="dateFormat(item['created_at'])"
:icon="item.icon"
:tokens="item['tokens']"
/>
<chat-reply
v-else-if="item.type === 'reply'"
:content="item.content"
:created-at="dateFormat(item['created_at'])"
:icon="item.icon"
:org-content="item.orgContent"
:tokens="item['tokens']"
/>
</van-cell>
</van-list>
</div>
</div>
</div><!-- end chat box -->
</div>
<!-- end chat box -->
</div>
</template>
<script setup>
import {dateFormat, processContent} from "@/utils/libs";
import ChatReply from "@/components/mobile/ChatReply.vue";
import ChatPrompt from "@/components/mobile/ChatPrompt.vue";
import {nextTick, ref} from "vue";
import {useRouter} from "vue-router";
import {httpGet} from "@/utils/http";
import ChatPrompt from '@/components/mobile/ChatPrompt.vue'
import ChatReply from '@/components/mobile/ChatReply.vue'
import { httpGet } from '@/utils/http'
import { dateFormat, processContent } from '@/utils/libs'
import hl from 'highlight.js'
import 'highlight.js/styles/a11y-dark.css'
import hl from "highlight.js";
import {showFailToast} from "vant";
import MarkdownIt from 'markdown-it'
import mathjaxPlugin from 'markdown-it-mathjax3'
import { showFailToast } from 'vant'
import { nextTick, ref } from 'vue'
import { useRouter } from 'vue-router'
const chatData = ref([])
const router = useRouter()
@@ -62,8 +66,7 @@ const model = ref('')
const finished = ref(false)
const error = ref(false)
const mathjaxPlugin = require('markdown-it-mathjax3')
const md = require('markdown-it')({
const md = new MarkdownIt({
breaks: true,
html: true,
linkify: true,
@@ -72,11 +75,14 @@ const md = require('markdown-it')({
const codeIndex = parseInt(Date.now()) + Math.floor(Math.random() * 10000000)
// 显示复制代码按钮
const copyBtn = `<span class="copy-code-mobile" data-clipboard-action="copy" data-clipboard-target="#copy-target-${codeIndex}">复制</span>
<textarea style="position: absolute;top: -9999px;left: -9999px;z-index: -9999;" id="copy-target-${codeIndex}">${str.replace(/<\/textarea>/g, '&lt;/textarea>')}</textarea>`
<textarea style="position: absolute;top: -9999px;left: -9999px;z-index: -9999;" id="copy-target-${codeIndex}">${str.replace(
/<\/textarea>/g,
'&lt;/textarea>'
)}</textarea>`
if (lang && hl.getLanguage(lang)) {
const langHtml = `<span class="lang-name">${lang}</span>`
// 处理代码高亮
const preCode = hl.highlight(lang, str, true).value
const preCode = hl.highlight(str, { language: lang }).value
// 将代码包裹在 pre 中
return `<pre class="code-container"><code class="language-${lang} hljs">${preCode}</code>${copyBtn} ${langHtml}</pre>`
}
@@ -84,50 +90,52 @@ const md = require('markdown-it')({
// 处理代码高亮
const preCode = md.utils.escapeHtml(str)
// 将代码包裹在 pre 中
return `<pre class="code-container"><code class="language-${lang} hljs">${preCode}</code>${copyBtn}</pre>`
}
});
return `<pre class="code-container">${code}${copyBtn}</pre>`
},
})
md.use(mathjaxPlugin)
const onLoad = () => {
httpGet('/api/chat/history?chat_id=' + chatId).then(res => {
// 加载状态结束
finished.value = true;
const data = res.data
if (data && data.length > 0) {
for (let i = 0; i < data.length; i++) {
if (data[i].type === "prompt") {
chatData.value.push(data[i]);
continue;
httpGet('/api/chat/history?chat_id=' + chatId)
.then((res) => {
// 加载状态结束
finished.value = true
const data = res.data
if (data && data.length > 0) {
for (let i = 0; i < data.length; i++) {
if (data[i].type === 'prompt') {
chatData.value.push(data[i])
continue
}
data[i].orgContent = data[i].content
data[i].content = md.render(processContent(data[i].content))
chatData.value.push(data[i])
}
data[i].orgContent = data[i].content;
data[i].content = md.render(processContent(data[i].content))
chatData.value.push(data[i]);
}
nextTick(() => {
hl.configure({ignoreUnescapedHTML: true})
const blocks = document.querySelector("#message-list-box").querySelectorAll('pre code');
blocks.forEach((block) => {
hl.highlightElement(block)
nextTick(() => {
hl.configure({ ignoreUnescapedHTML: true })
const blocks = document.querySelector('#message-list-box').querySelectorAll('pre code')
blocks.forEach((block) => {
hl.highlightElement(block)
})
})
})
}
}).catch(() => {
error.value = true
})
httpGet(`/api/chat/detail?chat_id=${chatId}`).then(res => {
title.value = res.data.title
model.value = res.data.model
role.value = res.data.role_name
}).catch(e => {
showFailToast('加载对话失败:' + e.message)
})
};
}
})
.catch(() => {
error.value = true
})
httpGet(`/api/chat/detail?chat_id=${chatId}`)
.then((res) => {
title.value = res.data.title
model.value = res.data.model
role.value = res.data.role_name
})
.catch((e) => {
showFailToast('加载对话失败:' + e.message)
})
}
</script>
<style scoped lang="stylus">
.chat-export-mobile {
@@ -171,4 +179,4 @@ const onLoad = () => {
}
}
}
</style>
</style>

View File

@@ -120,11 +120,13 @@
<script setup>
import ChatPrompt from '@/components/mobile/ChatPrompt.vue'
import ChatReply from '@/components/mobile/ChatReply.vue'
import { checkSession, getClientId } from '@/store/cache'
import { checkSession } from '@/store/cache'
import { getUserToken } from '@/store/session'
import { useSharedStore } from '@/store/sharedata'
import { showMessageError } from '@/utils/dialog'
import { httpGet } from '@/utils/http'
import { processContent, randString, renderInputText, UUID } from '@/utils/libs'
import { fetchEventSource } from '@microsoft/fetch-event-source'
import Clipboard from 'clipboard'
import hl from 'highlight.js'
import 'highlight.js/styles/a11y-dark.css'
@@ -134,6 +136,7 @@ import mathjaxPlugin from 'markdown-it-mathjax3'
import { showImagePreview, showNotify, showToast } from 'vant'
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
const winHeight = ref(0)
const navBarRef = ref(null)
const bottomBarRef = ref(null)
@@ -267,65 +270,10 @@ onMounted(() => {
clipboard.on('error', () => {
showNotify({ type: 'danger', message: '复制失败', duration: 2000 })
})
store.addMessageHandler('chat', (data) => {
if (data.channel !== 'chat' || data.clientId !== getClientId()) {
return
}
if (data.type === 'error') {
showMessageError(data.body)
return
}
if (isNewMsg.value) {
if (!title.value) {
title.value = previousText.value
}
lineBuffer.value = data.body
isNewMsg.value = false
const reply = chatData.value[chatData.value.length - 1]
if (reply) {
reply['content'] = lineBuffer.value
}
} else if (data.type === 'end') {
// 消息接收完毕
enableInput()
lineBuffer.value = '' // 清空缓冲
isNewMsg.value = true
} else {
lineBuffer.value += data.body
const reply = chatData.value[chatData.value.length - 1]
reply['orgContent'] = lineBuffer.value
reply['content'] = md.render(processContent(lineBuffer.value))
nextTick(() => {
hl.configure({ ignoreUnescapedHTML: true })
const lines = document.querySelectorAll('.message-line')
const blocks = lines[lines.length - 1].querySelectorAll('pre code')
blocks.forEach((block) => {
hl.highlightElement(block)
})
scrollListBox()
const items = document.querySelectorAll('.message-line')
const imgs = items[items.length - 1].querySelectorAll('img')
for (let i = 0; i < imgs.length; i++) {
if (!imgs[i].src) {
continue
}
imgs[i].addEventListener('click', (e) => {
e.stopPropagation()
showImagePreview([imgs[i].src])
})
}
})
}
})
})
onUnmounted(() => {
store.removeMessageHandler('chat')
// Remove WebSocket handler cleanup
})
const newChat = (item) => {
@@ -360,7 +308,9 @@ const loadChatHistory = () => {
type: 'reply',
id: randString(32),
icon: role.icon,
content: role.hello_msg,
content: {
text: role.hello_msg,
},
orgContent: role.hello_msg,
})
return
@@ -373,7 +323,7 @@ const loadChatHistory = () => {
}
data[i].orgContent = data[i].content
data[i].content = md.render(processContent(data[i].content))
data[i].content.text = md.render(processContent(data[i].content.text))
chatData.value.push(data[i])
}
@@ -427,17 +377,106 @@ const scrollListBox = () => {
.scrollTo(0, document.getElementById('message-list-box').scrollHeight + 46)
}
// 发送 SSE 请求
const sendSSERequest = async (message) => {
try {
await fetchEventSource('/api/chat/message', {
method: 'POST',
headers: {
Authorization: getUserToken(),
},
body: JSON.stringify(message),
openWhenHidden: true,
onopen(response) {
if (response.ok && response.status === 200) {
console.log('SSE connection opened')
} else {
throw new Error(`Failed to open SSE connection: ${response.status}`)
}
},
onmessage(msg) {
try {
const data = JSON.parse(msg.data)
if (data.type === 'error') {
showMessageError(data.body)
enableInput()
return
}
if (data.type === 'end') {
enableInput()
lineBuffer.value = '' // 清空缓冲
isNewMsg.value = true
return
}
if (data.type === 'text') {
if (isNewMsg.value) {
isNewMsg.value = false
lineBuffer.value = data.body
const reply = chatData.value[chatData.value.length - 1]
if (reply) {
reply['content']['text'] = lineBuffer.value
}
} else {
lineBuffer.value += data.body
const reply = chatData.value[chatData.value.length - 1]
reply['orgContent'] = lineBuffer.value
reply['content']['text'] = md.render(processContent(lineBuffer.value))
nextTick(() => {
hl.configure({ ignoreUnescapedHTML: true })
const lines = document.querySelectorAll('.message-line')
const blocks = lines[lines.length - 1].querySelectorAll('pre code')
blocks.forEach((block) => {
hl.highlightElement(block)
})
scrollListBox()
const items = document.querySelectorAll('.message-line')
const imgs = items[items.length - 1].querySelectorAll('img')
for (let i = 0; i < imgs.length; i++) {
if (!imgs[i].src) {
continue
}
imgs[i].addEventListener('click', (e) => {
e.stopPropagation()
showImagePreview([imgs[i].src])
})
}
})
}
}
} catch (error) {
console.error('Error processing message:', error)
enableInput()
showMessageError('消息处理出错,请重试')
}
},
onerror(err) {
console.error('SSE Error:', err)
enableInput()
showMessageError('连接已断开,请重试')
},
onclose() {
console.log('SSE connection closed')
enableInput()
},
})
} catch (error) {
console.error('Failed to send message:', error)
enableInput()
showMessageError('发送消息失败,请重试')
}
}
// 发送消息
const sendMessage = () => {
if (canSend.value === false) {
showToast('AI 正在作答中,请稍后...')
return
}
if (store.socket.conn.readyState !== WebSocket.OPEN) {
showToast('连接断开,正在重连...')
return
}
if (prompt.value.trim().length === 0) {
showToast('请输入需要 AI 回答的问题')
return false
@@ -448,7 +487,7 @@ const sendMessage = () => {
type: 'prompt',
id: randString(32),
icon: loginUser.value.avatar,
content: renderInputText(prompt.value),
content: { text: renderInputText(prompt.value) },
created_at: new Date().getTime(),
})
// 添加空回复消息
@@ -459,7 +498,9 @@ const sendMessage = () => {
type: 'reply',
id: randString(32),
icon: _role['icon'],
content: '',
content: {
text: '',
},
})
nextTick(() => {
@@ -467,31 +508,23 @@ const sendMessage = () => {
})
disableInput(false)
store.socket.conn.send(
JSON.stringify({
channel: 'chat',
type: 'text',
body: {
role_id: roleId.value,
model_id: modelId.value,
chat_id: chatId.value,
content: prompt.value,
stream: stream.value,
},
})
)
// 发送 SSE 请求
sendSSERequest({
user_id: loginUser.value.id,
role_id: roleId.value,
model_id: modelId.value,
chat_id: chatId.value,
prompt: prompt.value,
stream: stream.value,
})
previousText.value = prompt.value
prompt.value = ''
return true
}
const stopGenerate = () => {
showStopGenerate.value = false
httpGet('/api/chat/stop?session_id=' + getClientId()).then(() => {
enableInput()
})
}
// 重新生成
const reGenerate = () => {
disableInput(false)
const text = '重新生成上述问题的答案:' + previousText.value
@@ -502,19 +535,16 @@ const reGenerate = () => {
icon: loginUser.value.avatar,
content: renderInputText(text),
})
store.socket.conn.send(
JSON.stringify({
channel: 'chat',
type: 'text',
body: {
role_id: roleId.value,
model_id: modelId.value,
chat_id: chatId.value,
content: previousText.value,
stream: stream.value,
},
})
)
// 发送 SSE 请求
sendSSERequest({
user_id: loginUser.value.id,
role_id: roleId.value,
model_id: modelId.value,
chat_id: chatId.value,
prompt: previousText.value,
stream: stream.value,
})
}
const showShare = ref(false)

View File

@@ -30,28 +30,36 @@
<div class="opt" v-if="isLogin">
<van-row :gutter="10">
<van-col :span="8">
<van-button round block @click="showPasswordDialog = true" size="small">修改密码</van-button>
<van-button round block @click="showPasswordDialog = true" size="small"
>修改密码</van-button
>
</van-col>
<van-col :span="8">
<van-button round block @click="logout" size="small">退出登录</van-button>
</van-col>
<van-col :span="8">
<van-button round block @click="showSettings = true" icon="setting" size="small">设置</van-button>
<van-button round block @click="showSettings = true" icon="setting" size="small"
>设置</van-button
>
</van-col>
</van-row>
</div>
<div class="product-list">
<h3>充值套餐</h3>
<div class="product-list" v-if="menuList['/member']">
<h3 class="py-3">充值套餐</h3>
<div class="item" v-for="item in products" :key="item.id">
<div class="title">
<span class="name">{{ item.name }}</span>
<div class="pay-btn">
<div v-for="payWay in payWays" @click="pay(item, payWay)" :key="payWay">
<span>
<van-button type="primary" size="small" v-if="payWay.pay_type === 'alipay'"> <i class="iconfont icon-alipay"></i> 支付宝 </van-button>
<van-button type="success" size="small" v-if="payWay.pay_type === 'wxpay'"> <i class="iconfont icon-wechat-pay"></i> 微信支付 </van-button>
<van-button type="primary" size="small" v-if="payWay.pay_type === 'alipay'">
<i class="iconfont icon-alipay"></i> 支付宝
</van-button>
<van-button type="success" size="small" v-if="payWay.pay_type === 'wxpay'">
<i class="iconfont icon-wechat-pay"></i> 微信支付
</van-button>
</span>
</div>
</div>
@@ -100,7 +108,10 @@
<van-cell-group inset>
<van-field name="switch" label="暗黑主题">
<template #input>
<van-switch v-model="dark" @change="(val) => store.setTheme(val ? 'dark' : 'light')" />
<van-switch
v-model="dark"
@change="(val) => store.setTheme(val ? 'dark' : 'light')"
/>
</template>
</van-field>
@@ -130,163 +141,151 @@
</template>
<script setup>
import { onMounted, ref } from "vue";
import { showFailToast, showLoadingToast, showNotify, showSuccessToast } from "vant";
import { httpGet, httpPost } from "@/utils/http";
import { dateFormat, showLoginDialog } from "@/utils/libs";
import { ElMessage } from "element-plus";
import { checkSession, getSystemInfo } from "@/store/cache";
import { useRouter } from "vue-router";
import { removeUserToken } from "@/store/session";
import { useSharedStore } from "@/store/sharedata";
import { checkSession, getSystemInfo } from '@/store/cache'
import { removeUserToken } from '@/store/session'
import { useSharedStore } from '@/store/sharedata'
import { httpGet, httpPost } from '@/utils/http'
import { dateFormat, showLoginDialog } from '@/utils/libs'
import { ElMessage } from 'element-plus'
import { showFailToast, showLoadingToast, showNotify, showSuccessToast } from 'vant'
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
const form = ref({
username: "GeekMaster",
nickname: "极客学长@001",
mobile: "1300000000",
avatar: "",
username: 'GeekMaster',
nickname: '极客学长@001',
mobile: '1300000000',
avatar: '',
power: 0,
});
})
const fileList = ref([
{
url: "/images/user-info.png",
message: "上传中...",
url: '/images/user-info.png',
message: '上传中...',
},
]);
])
const products = ref([]);
const vipMonthPower = ref(0);
const payWays = ref({});
const router = useRouter();
const userId = ref(0);
const isLogin = ref(false);
const showSettings = ref(false);
const store = useSharedStore();
const stream = ref(store.chatStream);
const dark = ref(store.theme === "dark");
const products = ref([])
const vipMonthPower = ref(0)
const payWays = ref({})
const router = useRouter()
const userId = ref(0)
const isLogin = ref(false)
const showSettings = ref(false)
const store = useSharedStore()
const stream = ref(store.chatStream)
const dark = ref(store.theme === 'dark')
const menuList = ref({})
onMounted(() => {
checkSession()
.then((user) => {
userId.value = user.id;
isLogin.value = true;
httpGet("/api/user/profile")
userId.value = user.id
isLogin.value = true
httpGet('/api/user/profile')
.then((res) => {
form.value = res.data;
fileList.value[0].url = form.value.avatar;
form.value = res.data
fileList.value[0].url = form.value.avatar
})
.catch((e) => {
console.log(e.message);
showFailToast("获取用户信息失败");
});
console.log(e.message)
showFailToast('获取用户信息失败')
})
})
.catch(() => {});
.catch(() => {})
// 获取产品列表
httpGet("/api/product/list")
httpGet('/api/product/list')
.then((res) => {
products.value = res.data;
products.value = res.data
})
.catch((e) => {
showFailToast("获取产品套餐失败:" + e.message);
});
showFailToast('获取产品套餐失败:' + e.message)
})
getSystemInfo()
.then((res) => {
vipMonthPower.value = res.data["vip_month_power"];
vipMonthPower.value = res.data['vip_month_power']
})
.catch((e) => {
showFailToast("获取系统配置失败:" + e.message);
});
showFailToast('获取系统配置失败:' + e.message)
})
httpGet("/api/payment/payWays")
httpGet('/api/payment/payWays')
.then((res) => {
payWays.value = res.data;
payWays.value = res.data
})
.catch((e) => {
ElMessage.error("获取支付方式失败:" + e.message);
});
});
ElMessage.error('获取支付方式失败:' + e.message)
})
// const afterRead = (file) => {
// file.status = 'uploading';
// file.message = '上传中...';
// // 压缩图片并上传
// new Compressor(file.file, {
// quality: 0.6,
// success(result) {
// const formData = new FormData();
// formData.append('file', result, result.name);
// // 执行上传操作
// httpPost('/api/upload', formData).then((res) => {
// form.value.avatar = res.data.url
// file.status = 'success'
// httpPost('/api/user/profile/update', form.value).then(() => {
// showSuccessToast('上传成功')
// }).catch(() => {
// showFailToast('上传失败')
// })
// }).catch((e) => {
// showNotify({type: 'danger', message: '上传失败:' + e.message})
// })
// },
// error(err) {
// console.log(err.message);
// },
// });
// }
getMenuList()
})
const showPasswordDialog = ref(false);
// 获取菜单列表
const getMenuList = () => {
httpGet('/api/menu/list')
.then((res) => {
res.data.forEach((item) => {
menuList.value[item.url] = item
})
})
.catch((e) => {
showFailToast('获取菜单列表失败:' + e.message)
})
}
const showPasswordDialog = ref(false)
const pass = ref({
old: "",
new: "",
renew: "",
});
old: '',
new: '',
renew: '',
})
const beforeClose = (action) => {
new Promise((resolve) => {
resolve(action === "confirm");
});
};
resolve(action === 'confirm')
})
}
// 提交修改密码
const updatePass = () => {
if (pass.value.old === "") {
return showNotify({ type: "danger", message: "请输入旧密码" });
if (pass.value.old === '') {
return showNotify({ type: 'danger', message: '请输入旧密码' })
}
if (!pass.value.new || pass.value.new.length < 8) {
return showNotify({ type: "danger", message: "密码的长度为8-16个字符" });
return showNotify({ type: 'danger', message: '密码的长度为8-16个字符' })
}
if (pass.value.renew !== pass.value.new) {
return showNotify({ type: "danger", message: "两次输入密码不一致" });
return showNotify({ type: 'danger', message: '两次输入密码不一致' })
}
httpPost("/api/user/password", {
httpPost('/api/user/password', {
old_pass: pass.value.old,
password: pass.value.new,
repass: pass.value.renew,
})
.then(() => {
showSuccessToast("更新成功!");
showPasswordDialog.value = false;
showSuccessToast('更新成功!')
showPasswordDialog.value = false
})
.catch((e) => {
showFailToast("更新失败," + e.message);
showPasswordDialog.value = false;
});
};
showFailToast('更新失败,' + e.message)
showPasswordDialog.value = false
})
}
const pay = (product, payWay) => {
if (!isLogin.value) {
return showLoginDialog(router);
return showLoginDialog(router)
}
showLoadingToast({
message: "正在创建订单",
message: '正在创建订单',
forbidClick: true,
});
let host = process.env.VUE_APP_API_HOST;
if (host === "") {
host = `${location.protocol}//${location.host}`;
})
let host = process.env.VUE_APP_API_HOST
if (host === '') {
host = `${location.protocol}//${location.host}`
}
httpPost(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, {
product_id: product.id,
@@ -294,27 +293,27 @@ const pay = (product, payWay) => {
pay_type: payWay.pay_type,
user_id: userId.value,
host: host,
device: "wechat",
device: 'wechat',
})
.then((res) => {
location.href = res.data;
location.href = res.data
})
.catch((e) => {
showFailToast("生成支付订单失败:" + e.message);
});
};
showFailToast('生成支付订单失败:' + e.message)
})
}
const logout = function () {
httpGet("/api/user/logout")
httpGet('/api/user/logout')
.then(() => {
removeUserToken();
store.setIsLogin(false);
router.push("/");
removeUserToken()
store.setIsLogin(false)
router.push('/')
})
.catch(() => {
showFailToast("注销失败!");
});
};
showFailToast('注销失败!')
})
}
</script>
<style lang="stylus">