Browse Source

Token打通前端更改

liyanshuang
liyanshuang 5 days ago
parent
commit
a7d8d8560c
  1. 2
      src/api/AIxiaocaishen.js
  2. 4
      src/store/chat.js
  3. 457
      src/views/homePage.vue

2
src/api/AIxiaocaishen.js

@ -102,7 +102,7 @@ export const getAnnouncementAPI = function () {
export const getUserCountAPI = function (params) {
return request({
// 'http://39.101.133.168:8828/link/api/aiEmotion/client/getRemainNum',
url: `${APIurl}/api/aiEmotion/client/getRemainNum`,
url: `${APIurl}/api/aiEmotion/client/getRemainTokenNum`,
method: "POST",
data: params,
// headers: {

4
src/store/chat.js

@ -32,7 +32,9 @@ export const useChatStore = defineStore("chat", {
token: localStorage.getItem("localToken"),
source: activeTab == 'deepNine' ? '2' : '1',
});
this.UserCount = result.data;
this.UserCount = result.data.remain_num;
this.FreeCount = result.data.remain_free_num;
this.PaidCount = result.data.remain_pay_num;
},
setLoading(status) {
this.isLoading = status;

457
src/views/homePage.vue

@ -50,6 +50,13 @@ import VConsole from "vconsole";
const vConsole = new VConsole();
const isMobile = ref(null);
//Token
const freeTokenExpireTime = ref("2026-06-30");
// Token
const tokenClearTimeRange = ref({
startTime: '2025-07-01',
endTime: '2025-12-31'
});
// AiEmotion ref
const aiEmotionRef = ref(null);
@ -66,6 +73,125 @@ const deepNineStore = useDeepNineStore();
//
const emotionAudioStore = useEmotionAudioStore();
const audioStore = useAudioStore();
// Token
const tokenRecordVisible = ref(false);
const tokenRecordList = ref([
]);
import axios from 'axios'
// Token
const getTokenChangeLogs = async () => {
try {
const APIurl = import.meta.env.VITE_APP_API_BASE_URL
const res = await axios.post(
`${APIurl}/api/aiEmotion/client/viewTokenChangeLogs`,
{
token: localStorage.getItem('localToken')
}
)
if (res.data.code === 200) {
//
const records = res.data.data.map((item, index) => ({
id: index + 1,
change: item.count,
type: item.token_type === 1 ? '付费' : '免费',
time: item.created_at,
remark: item.reason
}))
tokenRecordList.value = records
} else {
ElMessage.error(res.data.msg || '获取Token流水失败')
}
} catch (error) {
ElMessage.error(error.message || '网络异常')
}
}
// Token
const getTokenExpireInfo = async () => {
try {
const APIurl = import.meta.env.VITE_APP_API_BASE_URL
const res = await axios.post(
`${APIurl}/api/aiEmotion/client/getCleanUpFreeTokenTime`,
{
token: localStorage.getItem('localToken')
}
)
if (res.data.code === 200) {
//
if (res.data.data.expiredTime) {
freeTokenExpireTime.value = res.data.data.expiredTime.split(' ')[0]
}
//
if (res.data.data.startTime && res.data.data.endTime) {
tokenClearTimeRange.value = {
startTime: res.data.data.startTime,
endTime: res.data.data.endTime
}
}
}
} catch (error) {
console.error('获取Token过期信息失败', error)
}
}
// Token
const showTokenClearDialog = ref(false)
//
const currentClearText = ref('')
// Token
const showTokenRecord = async () => {
await getTokenChangeLogs()
tokenRecordVisible.value = true
};
const APIurl = import.meta.env.VITE_APP_API_BASE_URL
//
const clearPopupReminder = async () => {
try {
const res = await axios.post(
`${APIurl}/api/aiEmotion/client/clearPopupReminder`,
{
token: localStorage.getItem('localToken')
}
)
console.log('clearPopupReminder 接口返回:', res.data)
if (res.data.code === 200) {
// data true
if (res.data.data === true) {
console.log('设置 showTokenClearDialog = true')
showTokenClearDialog.value = true
}
} else {
ElMessage.error(res.data.msg || '获取清除提醒状态失败')
}
} catch (error) {
ElMessage.error(error.message || '网络异常')
}
}
//Token
const checkTokenClearTip = () => {
// 1.
const hasShowClearTip = localStorage.getItem('hasShowTokenClearTip')
if (hasShowClearTip === '1') return
//
const formatDate = (dateStr) => {
const date = new Date(dateStr)
return `${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}${String(date.getDate()).padStart(2, '0')}`
}
const startTime = formatDate(tokenClearTimeRange.value.startTime)
const endTime = formatDate(tokenClearTimeRange.value.endTime)
currentClearText.value = `【通知】${startTime} - ${endTime} 期间获得的免费 Token 已统一清除,过期未使用额度不予保留、不累计、不顺延。`
showTokenClearDialog.value = true
}
// Token
const closeTokenClearDialog = () => {
showTokenClearDialog.value = false
localStorage.setItem('hasShowTokenClearTip', '1')
}
// store
const getCurrentAudioStore = () => {
return activeTab.value === "AiEmotion" ? emotionAudioStore : audioStore;
@ -166,13 +292,19 @@ const getSelectedOptionImage = () => {
};
//
onMounted(() => {
onMounted(async () => {
document.addEventListener("click", (e) => {
const container = document.querySelector(".custom-select-container");
if (container && !container.contains(e.target) && isDropdownOpen.value) {
isDropdownOpen.value = false;
}
});
// Token
getTokenExpireInfo()
//
await clearPopupReminder()
// Token
checkTokenClearTip()
});
//
@ -271,6 +403,12 @@ const ensureAIchat = () => {
//
const UserCount = computed(() => chatStore.UserCount);
//Token
const totalToken = computed(() => chatStore.UserCount);
//Token
const paidToken = computed(() => chatStore.PaidCount);
//Token
const freeToken = computed(() => chatStore.FreeCount);
const getCount = () => {
console.log("点击了获取次数的按钮");
@ -868,8 +1006,8 @@ watch(
activeTab.value == "AIchat"
? 1
: activeTab.value == "AiEmotion"
? 2
: 3;
? 2
: 3;
const result = historyRecordRef.value.getHistoryList({
model: model,
token: localStorage.getItem("localToken"),
@ -1838,6 +1976,20 @@ onUnmounted(() => {
<div>点击查看详情</div>
</div>
</div>
<div class="token-info-row">
<div class="token-info-left">
<div class="token-total1">Token总数{{ totalToken }}</div>
<div class="token-paid">永久Token{{ paidToken }}</div>
<div class="token-free">
免费Token{{ freeToken }}
(到期时间{{ freeTokenExpireTime }})
</div>
</div>
<div class="token-info-right" @click="showTokenRecord">
查看Token变动记录
</div>
</div>
<div class="changeLevel">
<div class="changeLevelTitle">兑换Token</div>
<div class="changeLevelContent">
@ -1886,19 +2038,28 @@ onUnmounted(() => {
/>
</div>
<div class="changeContent">
<div class="changeJwcode">精网号{{ userInfo.jwcode }}</div>
<div class="changeJwcode">{{ userInfo.jwcode }}</div>
</div>
</div>
</div>
<div class="changeLevel">
<div class="changeLevelTitle">
兑换Token
<div class="changeRule" @click="openTokenRuleDialog">
(兑换规则{{ changeRule.gold }}金币={{ changeRule.token }}Token)
兑换规则{{ changeRule.gold }}金币={{ changeRule.token }}Token
<div>点击查看详情</div>
</div>
</div>
</div>
<div class="changeLevel">
<div class="token-record">
<div class="token-row-top">
<div class="token-total-mobile">Token总数{{ totalToken }}</div>
<div class="token-change" @click="showTokenRecord">查看Token变动记录</div>
</div>
<div class="token-paid-mobile">付费Token{{ paidToken }}</div>
<div class="token-free-mobile">免费Token{{ freeToken }}
<br>
(到期时间{{ freeTokenExpireTime }})
</div>
</div>
<div class="changeLevelContent">
<div
class="changeLevelItems"
@ -1931,6 +2092,49 @@ onUnmounted(() => {
</div>
<div class="changeBtn" @click="changeToken">立即兑换</div>
</el-dialog>
<!-- Token变动记录弹窗 -->
<el-dialog
v-model="tokenRecordVisible"
:width="isMobile ? '90%' : '60%'"
:show-close="true"
>
<!-- 顶部统计区 -->
<div class="token-record-header">
<div class="token-total">Token总数{{ totalToken }}</div>
<div class="token-row">
<div class="token-free">免费Token{{ freeToken }}
<br>
(到期时间{{ freeTokenExpireTime }})</div>
<div class="token-permanent">永久Token{{ paidToken }}</div>
</div>
</div>
<!-- 表格区 -->
<div class="token-record-table">
<table>
<thead>
<tr>
<th>序号</th>
<th>数量变化</th>
<th>Token类型</th>
<th>操作时间</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in tokenRecordList" :key="item.id">
<td>{{ index + 1 }}</td>
<td :class="{ 'token-plus': item.change > 0, 'token-minus': item.change < 0 }">
{{ item.change > 0 ? '+' : '' }}{{ item.change }}
</td>
<td>{{ item.type }}</td>
<td>{{ item.time }}</td>
<td>{{ item.remark }}</td>
</tr>
</tbody>
</table>
</div>
</el-dialog>
<el-dialog
v-model="rechargeDialogVisible"
@ -2002,6 +2206,19 @@ onUnmounted(() => {
</button>
</div>
</el-dialog>
<!-- 免费Token清除提示弹窗 -->
<el-dialog v-model="showTokenClearDialog" :width="isMobile ? '80%' : '40%'" :show-close="false" align-center>
<div class="tokenClearDialogTitle">通知</div>
<div class="tokenClearDialogContent">
{{ currentClearText }}
</div>
<div class="tokenClearDialogFooter">
<button class="tokenClearDialogBtn" @click="closeTokenClearDialog">
我已知晓
</button>
</div>
</el-dialog>
<!-- Token规则提示框 -->
<div
@ -2144,6 +2361,44 @@ onUnmounted(() => {
padding: 6px 10px;
}
}
/* Token清除弹窗样式 */
.tokenClearDialogTitle {
font-size: 1.7rem;
color: #4e86fe;
display: flex;
justify-content: center;
align-items: center;
letter-spacing: 10px;
}
.tokenClearDialogContent {
padding: 20px;
font-size: 1.2rem;
line-height: 1.8;
color: #333;
}
.tokenClearDialogFooter {
display: flex;
justify-content: center;
padding: 0 20px 20px;
}
.tokenClearDialogBtn {
color: white;
background-color: #4e86fe;
padding: 10px 30px;
border-radius: 13px;
cursor: pointer;
border: none;
font-size: 1rem;
transition: all 0.3s ease;
}
.tokenClearDialogBtn:hover {
background-color: #3a73e6;
}
</style>
<style scoped>
@ -2724,6 +2979,190 @@ body {
transform: translateY(-2px);
}
.token-info-row {
display: flex;
width: 100%;
margin-bottom: 30px;
justify-content: center;
gap: 20px;
}
.token-info-left {
display: flex;
flex-direction: column;
justify-content: center;
gap: 6px;
background-color: #f8f8f8;
border-radius: 5px;
padding: 10px 20px;
width: 40%;
font-weight: bold;
}
.token-info-right {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
white-space: nowrap;
gap: 6px;
background-color: #f8f8f8;
border-radius: 5px;
padding: 10px 20px;
color: #4e86fe;
min-width: 40%;
transition: all 0.3s ease;
cursor: pointer;
}
.token-info-right:hover {
background-color: #e8f0ff;
box-shadow: 0 2px 8px rgba(78, 134, 254, 0.2);
transform: translateY(-2px);
}
/* Token变动记录弹窗样式 */
.token-record-header {
background-color: #f8f8f8;
border-radius: 8px;
padding: 15px 20px;
margin-bottom: 20px;
}
.token-total {
font-size: 20px;
color: #20303d;
font-weight: 500;
text-align: center;
margin-bottom: 10px;
}
.token-row {
display: flex;
justify-content: space-between;
font-size: 16px;
}
.token-total1 {
color: #20303d;
}
.token-paid {
color: #20303d;
}
.token-free {
color: #20303d;
}
.token-permanent {
color: #20303d;
}
.token-record-table {
width: 100%;
max-height: 300px;
overflow-x: auto;
overflow-y: auto;
}
.token-record-table table {
width: 100%;
border-collapse: collapse;
}
.token-record-table th,
.token-record-table td {
padding: 12px 8px;
text-align: center;
border-bottom: 1px solid #eee;
}
.token-record-table th {
background-color: #f8f8f8;
font-weight: 500;
}
.token-plus {
color: #00b42a;
}
.token-minus {
color: #ff4d4f;
}
/* 移动端适配 */
@media (max-width: 768px) {
.changeMsg {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
gap: 0;
}
.changeInfo {
display: flex;
align-items: center;
width: auto;
padding: 0;
margin: 0;
}
.changeImgClass {
width: 40px !important;
height: 40px !important;
border-radius: 4px !important;
}
.changeLevelTitle {
align-items: left;
width: auto;
padding: 0;
margin: 0 !important;
}
.changeRule {
margin: 0 !important;
padding: 0 !important;
align-items: center !important;
}
.token-record {
background: #f5f5f5 !important;
padding: 16px !important;
border-radius: 4px !important;
margin-bottom: 20px !important;
}
.token-row-top {
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin-bottom: 5px !important;
}
.token-total-mobile {
font-size: 16px !important;
color: #222 !important;
}
.token-change {
font-size: 16px !important;
color: #4e86fe !important;
font-weight: bold;
}
.token-paid-mobile,
.token-free-mobile {
font-size: 16px !important;
line-height: 2 !important;
color: #222 !important;
}
}
.changeLevel {
display: flex;
flex-direction: column;

Loading…
Cancel
Save