Browse Source
Merge remote-tracking branch 'origin/milestone-20250728-金币前端三期' into milestone-20250728-金币前端三期
zhangrenyuan/feature-20250728113353-金币前端三期
Merge remote-tracking branch 'origin/milestone-20250728-金币前端三期' into milestone-20250728-金币前端三期
zhangrenyuan/feature-20250728113353-金币前端三期
10 changed files with 630 additions and 6 deletions
-
69src/router/index.js
-
11src/views/consume/addBeanConsume.vue
-
11src/views/consume/articleVideo.vue
-
136src/views/consume/beanConsume.vue
-
11src/views/consume/dieHardFan.vue
-
11src/views/consume/liveStream.vue
-
265src/views/recharge/addBeanRecharge.vue
-
8src/views/recharge/beanOnlineRecharge.vue
-
106src/views/recharge/beanRecharge.vue
-
8src/views/recharge/beanSystemRecharge.vue
@ -0,0 +1,11 @@ |
|||
<script setup lang="ts"> |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
<div>addBeanConsume</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
|
|||
</style> |
@ -0,0 +1,11 @@ |
|||
<script setup lang="ts"> |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
<div>article videos</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
|
|||
</style> |
@ -1,11 +1,137 @@ |
|||
<script setup lang="ts"> |
|||
<template> |
|||
<div> |
|||
<!-- 这里放置标签切换的按钮 --> |
|||
<el-button-group> |
|||
<!-- 切换后状态显示 primary 样式否则是默认样式 --> |
|||
<el-button |
|||
:type="activeTab === 'add' ? 'primary' : 'default'" |
|||
@click="goToAdd" |
|||
class="uniform-btn" |
|||
> |
|||
新增消耗 |
|||
</el-button> |
|||
<el-button |
|||
:type="activeTab === 'live' ? 'primary' : 'default'" |
|||
@click="goToLive" |
|||
class="uniform-btn" |
|||
> |
|||
直播 |
|||
</el-button> |
|||
<el-button |
|||
:type="activeTab === 'fan' ? 'primary' : 'default'" |
|||
@click="goToFan" |
|||
class="uniform-btn" |
|||
> |
|||
铁粉 |
|||
</el-button> |
|||
<el-button |
|||
:type="activeTab === 'article' ? 'primary' : 'default'" |
|||
@click="goToArticle" |
|||
class="uniform-btn" |
|||
> |
|||
文章/视频 |
|||
</el-button> |
|||
</el-button-group> |
|||
<!-- 渲染子路由组件 --> |
|||
<router-view></router-view> |
|||
</div> |
|||
</template> |
|||
|
|||
</script> |
|||
<script setup> |
|||
import {onMounted, ref, watch} from 'vue'; |
|||
import {useRouter, useRoute} from 'vue-router'; |
|||
import {storeToRefs} from "pinia"; |
|||
import {useAdminStore} from "@/store/index.js"; |
|||
|
|||
<template> |
|||
const router = useRouter();// 获取路由实例 |
|||
const route = useRoute();// 获取当前路由信息 |
|||
// 定义响应式变量 activeTab 来跟踪当前激活的标签 |
|||
const activeTab = ref(route.name === 'liveStream' ? 'live' : 'add'); |
|||
//也就是说如果当前在coinConsumeDetail页面,那么就是detail,否则默认情况都展示add页面 |
|||
//此时获取到的路由信息是coinConsume,所以默认是add |
|||
const adminStore = useAdminStore(); |
|||
const {menuTree} = storeToRefs(adminStore); |
|||
|
|||
</template> |
|||
const goToAdd = () => { |
|||
// 点击按钮时更新 activeTab 为 add |
|||
activeTab.value = 'add'; |
|||
router.push({name: 'addBeanConsume'}); |
|||
}; |
|||
|
|||
<style scoped> |
|||
const goToLive = () => { |
|||
// 点击按钮时更新 activeTab 为 live |
|||
activeTab.value = 'live'; |
|||
router.push({name: 'liveStream'}); |
|||
}; |
|||
const goToFan = () => { |
|||
// 点击按钮时更新 activeTab 为 fan |
|||
activeTab.value = 'fan'; |
|||
router.push({name: 'dieHardFan'}); |
|||
}; |
|||
const goToArticle = () => { |
|||
// 点击按钮时更新 activeTab 为 article |
|||
activeTab.value = 'article'; |
|||
router.push({name: 'articleVideo'}); |
|||
}; |
|||
|
|||
// 导航方法 |
|||
const navigateTo = (name) => { |
|||
activeTab.value = name; |
|||
if (name === 'add') { |
|||
router.push({name: 'addBeanConsume'}); |
|||
} else if (name === 'live') { |
|||
router.push({name: 'liveStream'}); |
|||
} else if (name === 'fan') { |
|||
router.push({name: 'dieHardFan'}); |
|||
} else if (name === 'article') { |
|||
router.push({name: 'articleVideo'}); |
|||
} |
|||
}; |
|||
|
|||
// 递归判断某个 menuName 是否存在 |
|||
const hasMenuPermission = (tree, targetName) => { |
|||
for (const node of tree) { |
|||
if (node.menuName === targetName) return true; |
|||
if (node.children && hasMenuPermission(node.children, targetName)) return true; |
|||
} |
|||
return false; |
|||
}; |
|||
|
|||
// 默认路由判断 |
|||
const getDefaultRoute = () => { |
|||
if (!menuTree.value) return 'add'; |
|||
const hasRecharge = hasMenuPermission(menuTree.value, '提交金豆消耗'); |
|||
return hasRecharge ? 'add' : 'live'; |
|||
}; |
|||
|
|||
|
|||
// 监听路由变化更新标签状态 |
|||
watch(() => route.name, (newName) => { |
|||
if (newName === 'add' || newName === 'live') { |
|||
activeTab.value = newName; |
|||
} else if (newName === 'beanConsume') { |
|||
const defaultRoute = getDefaultRoute(); |
|||
navigateTo(defaultRoute); |
|||
} |
|||
}); |
|||
|
|||
// 初始化逻辑 |
|||
onMounted(() => { |
|||
if (route.name === 'beanConsume') { |
|||
const defaultRoute = getDefaultRoute(); |
|||
navigateTo(defaultRoute); |
|||
} else { |
|||
// 非父路由初始化当前标签状态 |
|||
if (route.name === 'add' || route.name === 'live') { |
|||
activeTab.value = route.name; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
</script> |
|||
|
|||
<style scoped> |
|||
.uniform-btn { |
|||
width: 120px; |
|||
} |
|||
</style> |
@ -0,0 +1,11 @@ |
|||
<script setup lang="ts"> |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
<div>die-hard fans</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
|
|||
</style> |
@ -0,0 +1,11 @@ |
|||
<script setup lang="ts"> |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
<div>live stream</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
|
|||
</style> |
@ -0,0 +1,265 @@ |
|||
<script setup> |
|||
import { ref, onMounted, reactive, computed, watch, nextTick } from 'vue' |
|||
import { ElMessage } from 'element-plus' |
|||
import { Plus } from '@element-plus/icons-vue' |
|||
import axios from 'axios' |
|||
import { ElMessageBox } from 'element-plus' |
|||
import API from '@/util/http' |
|||
import { uploadFile } from '@/util/request'; |
|||
import moment from 'moment' |
|||
import { range, re } from 'mathjs' |
|||
import { utils, read } from 'xlsx' |
|||
import throttle from 'lodash/throttle' |
|||
|
|||
const user = ref({}) |
|||
const getUser = async function (jwcode) { |
|||
if (addForm.value.jwcode) { |
|||
addForm.value.jwcode = addForm.value.jwcode.replace(/\s/g, ''); |
|||
} |
|||
try { |
|||
|
|||
|
|||
const result = await API({ |
|||
url: '/user/selectUser', |
|||
data: { |
|||
jwcode: addForm.value.jwcode |
|||
} |
|||
}) |
|||
|
|||
|
|||
if (result.code === 0) { |
|||
ElMessage.error(result.msg); |
|||
} else if (result.data === null) { |
|||
ElMessage.error("用户不存在"); |
|||
} else { |
|||
user.value = result.data; |
|||
console.log("用户信息", user.value); |
|||
ElMessage.success("查询成功"); |
|||
} |
|||
} catch (error) { |
|||
console.log("请求失败", error); |
|||
ElMessage.error("精网号错误"); |
|||
} |
|||
} |
|||
const addForm = ref({ |
|||
jwcode: '', |
|||
gode: '', |
|||
freeGode: '', |
|||
remark: '', |
|||
adminId: '' |
|||
}) |
|||
const Ref = ref(null) |
|||
|
|||
// const rules = reactive({ |
|||
// jwcode: [{ required: true, validator: validateJwCode, trigger: 'blur' }], |
|||
// gode: [ |
|||
// { required: true, message: '请输入永久金币数', trigger: 'blur' }, |
|||
// { |
|||
// validator: (rule, value, callback) => { |
|||
// // 检查是否包含特殊符号 |
|||
// if (/[^0-9.]/.test(value)) { |
|||
// callback(new Error('不能包含特殊符号或负数')); |
|||
// return; |
|||
// } |
|||
|
|||
// // 检查整数位数 |
|||
// const integerPart = value.split('.')[0]; |
|||
// if (integerPart.length > 6) { |
|||
// callback(new Error('整数位数不能超过6位')); |
|||
// return; |
|||
// } |
|||
|
|||
// // 检查小数位数 |
|||
// if (value.includes('.')) { |
|||
// const decimalPart = value.split('.')[1]; |
|||
// if (decimalPart.length > 2) { |
|||
// callback(new Error('小数位数不能超过两位')); |
|||
// return; |
|||
// } |
|||
// } |
|||
|
|||
// const numValue = Number(value); |
|||
// if (isNaN(numValue)) { |
|||
// callback(new Error('请输入有效的数字')); |
|||
// } else if (numValue < 0) { |
|||
// callback(new Error('输入金额不能小于0')); |
|||
// } else { |
|||
// callback(); |
|||
// } |
|||
// }, |
|||
// trigger: 'blur' |
|||
// } |
|||
// ], |
|||
// freeGode: [ |
|||
// { required: true, message: '请输入免费金币数', trigger: 'blur' }, |
|||
// { |
|||
// validator: (rule, value, callback) => { |
|||
// // 检查是否包含特殊符号 |
|||
// if (/[^0-9.]/.test(value)) { |
|||
// callback(new Error('不能包含特殊符号或负数')); |
|||
// return; |
|||
// } |
|||
|
|||
// // 检查整数位数 |
|||
// const integerPart = value.split('.')[0]; |
|||
// if (integerPart.length > 6) { |
|||
// callback(new Error('整数位数不能超过6位')); |
|||
// return; |
|||
// } |
|||
|
|||
// // 检查小数位数 |
|||
// if (value.includes('.')) { |
|||
// const decimalPart = value.split('.')[1]; |
|||
// if (decimalPart.length > 2) { |
|||
// callback(new Error('小数位数不能超过两位')); |
|||
// return; |
|||
// } |
|||
// } |
|||
|
|||
// const numValue = Number(value); |
|||
// if (isNaN(numValue)) { |
|||
// callback(new Error('请输入有效的数字')); |
|||
// } else if (numValue < 0) { |
|||
// callback(new Error('输入金额不能小于0')); |
|||
// } else { |
|||
// callback(); |
|||
// } |
|||
// }, |
|||
// trigger: 'blur' |
|||
// } |
|||
// ], |
|||
// }); |
|||
|
|||
//重置表单 |
|||
const deleteAddForm = function () { |
|||
addForm.value = { |
|||
jwcode: '', |
|||
gode: '', |
|||
freeGode: '', |
|||
remark: '', |
|||
adminId: '' |
|||
} |
|||
} |
|||
|
|||
const handleAddForm = () => { |
|||
|
|||
} |
|||
</script> |
|||
<template> |
|||
<div> |
|||
<el-form :model="addForm" ref="Ref" label-width="auto" style="max-width: 600px" class="add-form"> |
|||
<el-form-item prop="jwcode" label="精网号"> |
|||
<el-input v-model="addForm.jwcode" style="width: 220px" /> |
|||
<el-button type="primary" @click="getUser(addForm.jwcode)" style="margin-left: 20px">查询</el-button> |
|||
</el-form-item> |
|||
|
|||
<el-form-item prop="permanentGold" label="付费金豆"> |
|||
<el-input v-model="addForm.gode" style="width: 100px" /> |
|||
<p>个</p> |
|||
|
|||
</el-form-item> |
|||
<el-form-item prop="freeGold" label="免费金豆"> |
|||
|
|||
<el-input v-model="addForm.freeGode" style="width: 100px" /> |
|||
<p>个</p> |
|||
</el-form-item> |
|||
<el-form-item prop="remark" label="备注"> |
|||
<el-input v-model="addForm.remark" style="width: 300px" :rows="2" maxlength="100" show-word-limit |
|||
type="textarea" /> |
|||
</el-form-item> |
|||
<el-form-item prop="adminId" label="提交人"> |
|||
<el-input style="width: 300px" :value="adminData.adminName" disabled placeholder="提交人姓名" /> |
|||
</el-form-item> |
|||
<el-button @click="deleteAddForm" style="margin-left: 280px" type="success">重置</el-button> |
|||
<el-button type="primary" @click="handleAddForm"> 提交 </el-button> |
|||
</el-form> |
|||
|
|||
<!-- 客户信息栏 --> |
|||
<el-card v-if="user.jwcode" style="width: 800px; float: right" class="customer-info"> |
|||
<el-form :model="user" label-width="auto" style="max-width: 1000px" label-position="left"> |
|||
<el-text size="large" style="margin-left: 20px">客户信息</el-text> |
|||
|
|||
<!-- 第一行:姓名 + 历史金币 --> |
|||
<el-row style="margin-top: 20px"> |
|||
<el-col :span="9"> |
|||
<el-form-item label="姓名:"> |
|||
<p>{{ user.name }}</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="14"> |
|||
<el-form-item label="历史金币总数"> |
|||
<!-- 检查 user.historySumGold 是否为有效的数字 --> |
|||
<p style="color: #2fa1ff; margin-right: 5px" v-if="!isNaN(Number(user.historySumGold))"> |
|||
{{ Number(user.historySumGold) / 100 }} |
|||
</p> |
|||
|
|||
<!-- 如果不是有效的数字,显示默认值 --> |
|||
<p v-else></p> |
|||
</el-form-item> |
|||
<el-form-item style="margin-top: -23px"> |
|||
<span style="display: inline; white-space: nowrap; color: #b1b1b1" |
|||
v-if="user.historyPermanentGold !== undefined">(永久金币:{{ user.historyPermanentGold / 100 }};免费金币:{{ |
|||
(user.historyFreeGold) / 100 |
|||
}};任务金币:{{ user.historyTaskGold / 100 }})</span> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
|
|||
<!-- 第二行:精网号 + 当前金币(独立行) --> |
|||
<el-row style="margin-top:-23px"> |
|||
<el-col :span="9"> |
|||
<el-form-item label="精网号"> |
|||
<p>{{ user.jwcode }}</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="14"> |
|||
<el-form-item label="当前金币总数" style="width: 500px"> |
|||
<span style="color: #2fa1ff; margin-right: 5px" v-if="user.nowSumGold !== undefined">{{ user.nowSumGold |
|||
/100}}</span> |
|||
</el-form-item> |
|||
<!-- 金币详情独立显示 --> |
|||
<el-form-item style="margin-top: -23px"> <!-- 负边距减少间距 --> |
|||
<span style="color: #b1b1b1; margin-left: 0px" v-if="user.nowPermanentGold !== undefined">(永久金币:{{ |
|||
user.nowPermanentGold /100}}; |
|||
免费金币:{{ user.nowFreeGold / 100 }}; |
|||
任务金币:{{ user.nowTaskGold / 100 }})</span> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
|
|||
<!-- 第三行:首次充值日期 + 充值次数 --> |
|||
<el-row style="margin-top:-23px"> |
|||
<el-col :span="9"> |
|||
<el-form-item label="首次充值日期"> |
|||
<p v-if="user.firstRecharge"> |
|||
{{ moment(user.firstRecharge).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="14"> |
|||
<el-form-item label="充值次数"> |
|||
<p style="color: #2fa1ff">{{ user.rechargeNum }}</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
|
|||
<!-- 第四行:消费次数 + 所属门店 --> |
|||
<el-row> |
|||
<el-col :span="9"> |
|||
<el-form-item label="消费次数"> |
|||
<p style="color: #2fa1ff">{{ user.consumeNum }}</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="9"> |
|||
<el-form-item label="所属门店"> |
|||
<p>{{ user.market }}</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
</el-form> |
|||
</el-card> |
|||
|
|||
|
|||
</div> |
|||
</template> |
|||
<style></style> |
@ -0,0 +1,8 @@ |
|||
<script setup lang="ts"> |
|||
</script> |
|||
<template> |
|||
|
|||
线上充值 |
|||
</template> |
|||
<style> |
|||
</style> |
@ -1,9 +1,113 @@ |
|||
<script setup lang="ts"> |
|||
import {onMounted, ref, watch} from 'vue'; |
|||
import {useRouter, useRoute} from 'vue-router'; |
|||
import {storeToRefs} from "pinia"; |
|||
import {useAdminStore} from "@/store/index.js"; |
|||
|
|||
const router = useRouter();// 获取路由实例 |
|||
const route = useRoute();// 获取当前路由信息 |
|||
// 定义响应式变量 activeTab 来跟踪当前激活的标签 |
|||
const activeTab = ref(route.name === 'addBeanRecharge' ? 'detail' : 'add'); |
|||
//也就是说如果当前在coinConsumeDetail页面,那么就是detail,否则默认情况都展示add页面 |
|||
//此时获取到的路由信息是coinConsume,所以默认是add |
|||
const adminStore = useAdminStore(); |
|||
const {menuTree} = storeToRefs(adminStore); |
|||
const goToAdd = () => { |
|||
// 点击按钮时更新 activeTab 为 add |
|||
activeTab.value = 'add'; |
|||
router.push({name: 'addBeanRecharge'}); |
|||
}; |
|||
|
|||
const goToSystem = () => { |
|||
// 点击按钮时更新 activeTab 为 detail |
|||
activeTab.value = 'system'; |
|||
router.push({name: 'beanSystemRecharge'}); |
|||
}; |
|||
const goToOnline = () => { |
|||
// 点击按钮时更新 activeTab 为 detail |
|||
activeTab.value = 'online'; |
|||
router.push({name: 'beanOnlineRecharge'}); |
|||
}; |
|||
|
|||
// 导航方法 |
|||
const navigateTo = (name) => { |
|||
activeTab.value = name; |
|||
if (name === 'add') { |
|||
router.push({name: 'addBeanRecharge'}); |
|||
} else if (name === 'system') { |
|||
router.push({name: 'beanSystemRecharge'}); |
|||
}else if(name === 'online'){ |
|||
router.push({name: 'beanOnlineRecharge'}); |
|||
} |
|||
}; |
|||
// 递归判断某个 menuName 是否存在 |
|||
const hasMenuPermission = (tree, targetName) => { |
|||
for (const node of tree) { |
|||
if (node.menuName === targetName) return true; |
|||
if (node.children && hasMenuPermission(node.children, targetName)) return true; |
|||
} |
|||
return false; |
|||
}; |
|||
|
|||
// 默认路由判断 |
|||
const getDefaultRoute = () => { |
|||
if (!menuTree.value) return 'add'; |
|||
const hasRecharge = hasMenuPermission(menuTree.value, '提交金币充值'); |
|||
return hasRecharge ? 'add' : 'detail'; |
|||
}; |
|||
|
|||
|
|||
// 监听路由变化更新标签状态 |
|||
watch(() => route.name, (newName) => { |
|||
if (newName === 'add' || newName === 'system' || newName =='online') { |
|||
activeTab.value = newName; |
|||
} else if (newName === 'coinRecharge') { |
|||
const defaultRoute = getDefaultRoute(); |
|||
navigateTo(defaultRoute); |
|||
} |
|||
}); |
|||
|
|||
// 初始化逻辑 |
|||
onMounted(() => { |
|||
if (route.name === 'coinRecharge') { |
|||
const defaultRoute = getDefaultRoute(); |
|||
navigateTo(defaultRoute); |
|||
} else { |
|||
// 非父路由初始化当前标签状态 |
|||
if (route.name === 'add' || route.name === 'detail' || route.name =='online') { |
|||
activeTab.value = route.name; |
|||
} |
|||
} |
|||
}); |
|||
</script> |
|||
|
|||
<template> |
|||
|
|||
<div> |
|||
<!-- 这里放置标签切换的按钮 --> |
|||
<el-button-group> |
|||
<!-- 切换后状态显示 primary 样式否则是默认样式 --> |
|||
<el-button |
|||
:type="activeTab === 'add' ? 'primary' : 'default'" |
|||
@click="goToAdd" |
|||
> |
|||
新增充值 |
|||
</el-button> |
|||
<el-button |
|||
:type="activeTab === 'system' ? 'primary' : 'default'" |
|||
@click="goToSystem" |
|||
> |
|||
系统充值 |
|||
</el-button> |
|||
<el-button |
|||
:type="activeTab === 'online' ? 'primary' : 'default'" |
|||
@click="goToOnline" |
|||
> |
|||
线上充值 |
|||
</el-button> |
|||
</el-button-group> |
|||
<!-- 渲染子路由组件 --> |
|||
<router-view></router-view> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
|
@ -0,0 +1,8 @@ |
|||
<script setup lang="ts"> |
|||
</script> |
|||
<template> |
|||
|
|||
金豆系统充值 |
|||
</template> |
|||
<style> |
|||
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue