Browse Source

Merge remote-tracking branch 'origin/milestone-20250728-金币前端三期' into milestone-20250728-金币前端三期

zhangrenyuan/feature-20250728113353-金币前端三期
lihui 3 weeks ago
parent
commit
e2211fa360
  1. 69
      src/router/index.js
  2. 11
      src/views/consume/addBeanConsume.vue
  3. 11
      src/views/consume/articleVideo.vue
  4. 136
      src/views/consume/beanConsume.vue
  5. 11
      src/views/consume/dieHardFan.vue
  6. 11
      src/views/consume/liveStream.vue
  7. 265
      src/views/recharge/addBeanRecharge.vue
  8. 8
      src/views/recharge/beanOnlineRecharge.vue
  9. 106
      src/views/recharge/beanRecharge.vue
  10. 8
      src/views/recharge/beanSystemRecharge.vue

69
src/router/index.js

@ -79,6 +79,44 @@ const routes = [
}
]
},
// 金豆消耗
{
path: '/beanConsume',
name: "beanConsume",
component: () => import("../views/consume/beanConsume.vue"),
meta: {permissionId: 6},
children: [
// 金豆新增消耗
{
path: 'add',
name: "addBeanConsume",
component: () => import("../views/consume/addBeanConsume.vue"),
meta: {permissionId: 23} // 对应"提交金豆消耗"id=?
},
// 直播
{
path: 'live',
name: "liveStream",
component: () => import("../views/consume/liveStream.vue"),
meta: {permissionId: 24} // 对应"直播"id=?
},
// 铁粉
{
path: 'fan',
name: "dieHardFan",
component: () => import("../views/consume/dieHardFan.vue"),
meta: {permissionId: 25} // 对应"铁粉"id=?
},
// 文章视频
{
path: 'article',
name: "articleVideo",
component: () => import("../views/consume/articleVideo.vue"),
meta: {permissionId: 26} // 对应"文章视频"id=?
}
]
},
// 汇率管理
{
@ -111,6 +149,37 @@ const routes = [
]
},
// 金豆充值
{
path: '/beanRecharge',
name: "beanRecharge",
component: () => import("../views/recharge/beanRecharge.vue"),
// redirect: '/coinRecharge/add',
children: [
// 金豆新增充值
{
path: 'add',
name: "addBeanRecharge",
component: () => import("../views/recharge/addBeanRecharge.vue"),
meta: {permissionId: 17} // 对应"提交金币充值"id=17
},
// 金豆系统充值
{
path: 'system',
name: "beanSystemRecharge",
component: () => import("../views/recharge/beanSystemRecharge.vue"),
meta: {permissionId: 18} // 对应"查看金币充值明细"id=18
},
// 金豆线上充值
{
path: 'online',
name: "beanOnlineRecharge",
component: () => import("../views/recharge/beanOnlineRecharge.vue"),
meta: {permissionId: 18} // 对应"查看金币充值明细"id=18
}
]
},
// 金币退款
{
path: '/coinRefund',

11
src/views/consume/addBeanConsume.vue

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
<div>addBeanConsume</div>
</template>
<style scoped>
</style>

11
src/views/consume/articleVideo.vue

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
<div>article videos</div>
</template>
<style scoped>
</style>

136
src/views/consume/beanConsume.vue

@ -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');
//coinConsumeDetaildetailadd
//coinConsumeadd
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>

11
src/views/consume/dieHardFan.vue

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
<div>die-hard fans</div>
</template>
<style scoped>
</style>

11
src/views/consume/liveStream.vue

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
<div>live stream</div>
</template>
<style scoped>
</style>

265
src/views/recharge/addBeanRecharge.vue

@ -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>

8
src/views/recharge/beanOnlineRecharge.vue

@ -0,0 +1,8 @@
<script setup lang="ts">
</script>
<template>
线上充值
</template>
<style>
</style>

106
src/views/recharge/beanRecharge.vue

@ -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');
//coinConsumeDetaildetailadd
//coinConsumeadd
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>

8
src/views/recharge/beanSystemRecharge.vue

@ -0,0 +1,8 @@
<script setup lang="ts">
</script>
<template>
金豆系统充值
</template>
<style>
</style>
Loading…
Cancel
Save