Browse Source

Merge branch 'refs/heads/milestone-20251104-现金二期' into lihui/feature-20251104165712-现金二期

zhangrenyuan/feature-20251104133449-现金管理二期
lihui 3 weeks ago
parent
commit
15b574e312
  1. 4
      .env.development
  2. 4
      src/router/index.js
  3. 2
      src/utils/menuTreePermission.js
  4. 7
      src/utils/menuUtils.js
  5. 8
      src/views/audit/bean/beanAudit.vue
  6. 676
      src/views/channelManage/cart/cart.vue
  7. 657
      src/views/channelManage/fans/fans.vue
  8. 700
      src/views/channelManage/reward/reward.vue
  9. 339
      src/views/moneyManage/receiveDetail/receiveFinance.vue
  10. 1174
      src/views/moneyManage/receiveDetail/receiveManage.vue
  11. 8
      src/views/moneyManage/receiveDetail/receiveService.vue
  12. 13
      src/views/moneyManage/receiveDetail/utils/util.js
  13. 61
      src/views/permissions/rolePermission.vue

4
.env.development

@ -1,4 +1,4 @@
# VITE_API_BASE='https://hwjb.homilychart.com/dev/admin'
VITE_API_BASE='https://hwjb.homilychart.com/dev/admin'
# 测试环境 # 测试环境
# VITE_API_BASE='http://54.255.212.181:10704/' # VITE_API_BASE='http://54.255.212.181:10704/'
# 正式环境 # 正式环境
@ -13,7 +13,7 @@ VITE_UPLOAD_URL=http://39.101.133.168:8828/hljw/api/aws/upload
# 本地 # 本地
# VITE_API_BASE='http://localhost:8081/' # VITE_API_BASE='http://localhost:8081/'
# 孙加倍 # 孙加倍
VITE_API_BASE='http://192.168.40.12:8081'
# VITE_API_BASE='http://192.168.40.12:8081'
# Lijianlin # Lijianlin
# VITE_API_BASE='http://192.168.9.41:8081/' # VITE_API_BASE='http://192.168.9.41:8081/'

4
src/router/index.js

@ -319,7 +319,7 @@ const routes = [
{ {
path: 'receiveManager', path: 'receiveManager',
name: "receiveManager", name: "receiveManager",
component: () => import("../views/moneyManage/receiveDetail/receiveManage.vue"),
component: () => import("../views/moneyManage/receiveDetail/receiveFinance.vue"),
meta: { permissionId: [67, 79] } meta: { permissionId: [67, 79] }
}, },
{//地区财务 {//地区财务
@ -385,7 +385,7 @@ const routes = [
}, },
// 频道管理 // 频道管理
{ {
path: '/channelManage',
path: 'channelManage',
name: 'channelManage', name: 'channelManage',
meta: { permissionId: 124 }, meta: { permissionId: 124 },
children: [ children: [

2
src/utils/menuTreePermission.js

@ -187,7 +187,7 @@ export const findMenuById = (menuList, targetId) => {
// 递归判断某个 menuId 是否存在 // 递归判断某个 menuId 是否存在
export const hasMenuPermission = (tree, targetId) => { export const hasMenuPermission = (tree, targetId) => {
for (const node of tree) { for (const node of tree) {
console.log(node.id)
// console.log(node.id)
if (node.id === targetId) return true; if (node.id === targetId) return true;
if (node.children && hasMenuPermission(node.children, targetId)) return true; if (node.children && hasMenuPermission(node.children, targetId)) return true;
} }

7
src/utils/menuUtils.js

@ -91,8 +91,13 @@ export const getRoutePath = (menu) => {
'退款-总部财务':'/moneyManage/refundDetail/refundHeader', '退款-总部财务':'/moneyManage/refundDetail/refundHeader',
'执行明细': '/moneyManage/executor', '执行明细': '/moneyManage/executor',
};
'频道管理': '/channelManage',
'打赏管理': '/channelManage/reward',
'铁粉管理': '/channelManage/fans',
'小黄车管理': '/channelManage/cart',
};
// console.log('1111',menu.menuName)
// 未匹配的菜单默认使用id作为路由(可根据实际需求调整) // 未匹配的菜单默认使用id作为路由(可根据实际需求调整)
return routeMap[menu.menuName] || '/noPermission' return routeMap[menu.menuName] || '/noPermission'

8
src/views/audit/bean/beanAudit.vue

@ -173,6 +173,9 @@ const reason = ref('')
const rejectRow = ref({ const rejectRow = ref({
id: null id: null
})// })//
const passRow = ref({
id: null
})//
const popconfirmRef = ref(null) const popconfirmRef = ref(null)
// //
@ -337,13 +340,14 @@ const showApproveDialog = (row) => {
ElMessage.error('暂无权限') ElMessage.error('暂无权限')
return return
} }
passRow.value.id = row.id
approveDialogVisible.value = true approveDialogVisible.value = true
} }
// //
// 使handleApproveConfirm使handleApprove // 使handleApproveConfirm使handleApprove
// handleApprove // handleApprove
const handleApproveConfirm = async (row) => {
const handleApproveConfirm = async function() {// rowrow
if (!hasbeanWaitThough) { if (!hasbeanWaitThough) {
ElMessage.error('暂无权限') ElMessage.error('暂无权限')
return return
@ -351,7 +355,7 @@ const handleApproveConfirm = async (row) => {
clicked.value = true clicked.value = true
try { try {
const params = { const params = {
id: row.id,
id: passRow.value.id,
auditName: adminData.value.adminName auditName: adminData.value.adminName
} }
await API({ url: '/beanAudit/status1', data: params }) await API({ url: '/beanAudit/status1', data: params })

676
src/views/channelManage/cart/cart.vue

@ -0,0 +1,676 @@
<script setup>
import { computed, onMounted, ref } from 'vue'
import { dayjs, ElMessage } from 'element-plus'
import request from '@/util/http.js'
import API from '@/util/http.js'
import moment from 'moment'
import { ar } from 'element-plus/es/locales.mjs'
//
const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
]
/*
====================工具方法==============================
*/
//
const formatTime = (val) => val ? dayjs(val).format('YYYY-MM-DD HH:mm:ss') : ''
/*
====================数据=================================
*/
//
const adminData = ref({})
//
const tableData = ref([])
// articleVideo
const beanConsumeArticle = ref({
jwcode: null,
dept: "",
type: "",
payMode: "",
articleId: "",
articleName: "",
author: "",
startTime: '',
endTime: '',
})
//
const channels = ref([])
//
const consumeTypes = ref([
{ label: '打赏', value: 9 },
{ label: '打赏', value: 10 },
{ label: '付费购买', value: 11 },
])
// payMode
const handlePayModeChange = (value) => {
beanConsumeArticle.value.payMode = value;
//
ConsumeSelectBy();
}
//------------------------
//
const activeTimeRange = ref('')
//
const handleDatePickerChange = () => {
activeTimeRange.value = ''
}
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref({
startTime: '',
endTime: ''
})
//
const dept = ref([])
//
const getDept = async function () {
try {
//
const result = await request({
// url: '/general/dept',
url: '/beanConsume/getDept', // todo
data: { account: adminData.value.account }
})
console.log('请求地区列表成功', result)
//
dept.value = result.data
console.log('地区数据', dept.value)
} catch (error) {
console.log('请求地区列表失败', error)
ElMessage({
type: 'error',
message: '获取地区列表失败,请稍后重试'
})
}
}
// //
// const filterChannel = (query) => {
// if (query) {
// return channels.value.filter(item => item.toLowerCase().includes(query.toLowerCase()));
// }
// return channels.value;
// };
//
const sortField = ref('')
const sortOrder = ref('')
//
const permanentBean = ref(0)
const freeBean = ref(0)
const totalNum = ref(0)
/*
====================方法=================================
*/
//
const getAdminData = async function () {
try {
const result = await request({
url: '/admin/userinfo',
data: {}
})
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
const ConsumeSelectBy = async function (val) {
try {
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value.startTime != '' && getTime.value.endTime != '') {
beanConsumeArticle.value.startTime = formatTime(getTime.value[0])
beanConsumeArticle.value.endTime = formatTime(getTime.value[1])
}
} else {
beanConsumeArticle.value.startTime = ''
beanConsumeArticle.value.endTime = ''
}
beanConsumeArticle.value.sortField = sortField.value
beanConsumeArticle.value.sortOrder = sortOrder.value
console.log('搜索参数_时间', beanConsumeArticle.value.startTime)
console.log('搜索参数1', getObj.value)
console.log('搜索参数2', beanConsumeArticle.value)
// POST
const result = await request({
url: '/beanConsume/selectArticleBy',
data: {
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize,
beanConsumeArticle: {
...beanConsumeArticle.value,
jwcode: beanConsumeArticle.value.jwcode,
dept: beanConsumeArticle.value.dept,
payMode: beanConsumeArticle.value.payMode,
articleId: beanConsumeArticle.value.articleId,
articleName: beanConsumeArticle.value.articleName,
author: beanConsumeArticle.value.author,
startTime: beanConsumeArticle.value.startTime,
endTime: beanConsumeArticle.value.endTime,
sortField: beanConsumeArticle.value.sortField,
sortOrder: beanConsumeArticle.value.sortOrder,
}
}
})
console.log('请求成功4', sortField)
console.log('接口响应结果', result); //
if (result.code === 200 && result.data && result.data.list) {
// type payMode
const filteredList = result.data.list.filter(item => {
if (beanConsumeArticle.value.payMode === '0') {
return [9, 10].includes(Number(item.type));
} else if (beanConsumeArticle.value.payMode === '1') {
return Number(item.type) === 11;
}
return true;
});
tableData.value = filteredList;
}
//
// beanConsumeArticle.value payType 8
const sumConsumeParams = {
payType: 8, // payType 8
beanConsumeArticle: {
...beanConsumeArticle.value,
}
};
// POST
const resultTotalGold = await request({
url: '/beanConsume/sumConsumeGold',
data: sumConsumeParams
});
console.log("总计", resultTotalGold);
const data = resultTotalGold.data || resultTotalGold;
console.log('请求成功3', resultTotalGold.data)
console.log('permanentBean3', data.permanentBean)
// permanentBeanfreeBeantotalNum
permanentBean.value = Number(data.permanentBean) || 0;
freeBean.value = Number(data.freeBean) || 0;
totalNum.value = Number(data.totalNum) || 0;
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const search = function () {
getObj.value.pageNum = 1
if (beanConsumeArticle.value.jwcode) {
const numRef = /^\d{1,9}$/;
if (!numRef.test(beanConsumeArticle.value.jwcode)) {
ElMessage.error('请检查精网号格式')
return
}
}
if (beanConsumeArticle.value.articleId) {
const numRef = /^\d{1,9}$/;
if (!numRef.test(beanConsumeArticle.value.articleId)) {
ElMessage.error('请检查文章ID格式')
return
}
}
ConsumeSelectBy()
}
//
const reset = function () {
console.log('文章/视频的重置')
beanConsumeArticle.value.jwcode = null
beanConsumeArticle.value.dept = ''
beanConsumeArticle.value.type = ''
beanConsumeArticle.value.payMode = ''
beanConsumeArticle.value.articleId = ''
beanConsumeArticle.value.articleName = ''
beanConsumeArticle.value.author = ''
beanConsumeArticle.value.startTime = ''
beanConsumeArticle.value.endTime = ''
sortField.value = ''
sortOrder.value = ''
getTime.value = {}
activeTimeRange.value = '' //
//
ConsumeSelectBy()
console.log(' beanConsumeArticle', beanConsumeArticle.value)
}
//
const getToday = function () {
const today = dayjs()
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = 'today' //
ConsumeSelectBy()
}
//
const getYesterday = function () {
const today = dayjs()
const startTime = today.subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.subtract(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = 'yesterday' //
ConsumeSelectBy()
}
// 7
const get7Days = function () {
const today = dayjs()
const startTime = today.subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = '7days' //
ConsumeSelectBy()
}
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'beanNum') {
sortField.value = 'beanNum'
} else if (column.prop === 'consumeTime') {
sortField.value = 'consumeTime'
} else if (column.prop === 'buyBean') {
sortField.value = 'buyBean'
} else if (column.prop === 'freeBean') {
sortField.value = 'freeBean'
}
sortOrder.value = column.order === 'ascending' ? 'DESC' : 'ASC'
ConsumeSelectBy()
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
ConsumeSelectBy()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
ConsumeSelectBy()
}
/*
====================计算属性=================================
*/
//
// const totalBean = computed(() => permanentBean.value + freeBean.value)
/*
====================监听=================================
*/
/*
====================挂载=================================
*/
const format3 = (num) => {
//
return num.toLocaleString('en-US')
}
onMounted(async function () {
await getAdminData()
await ConsumeSelectBy()
await getDept()
})
const exportExcel = async function () {
const params = { //
...getObj.value,
"beanConsumeArticle": {
...beanConsumeArticle.value,
sortField: sortField.value,
sortOrder: sortOrder.value,
},
}
const res = await API({ url: '/export/exportArticle', data: params })
if (res.code === 200) {
ElMessage.success('导出成功')
}
}
const exportListVisible = ref(false)
//
const openExportList = () => {
getExportList()
exportListVisible.value = true
}
//
const exportList = ref([])
//
const exportListLoading = ref(false)
//
const getExportList = async () => {
exportListLoading.value = true
try {
const result = await API({ url: '/export/export' })
if (result.code === 200) {
const filteredData = result.data.filter(item => {
return item.type === 8; //4 // todo type 8/
});
exportList.value = filteredData
} else {
ElMessage.error(result.msg || '获取导出列表失败')
}
} catch (error) {
console.error('获取导出列表出错:', error)
ElMessage.error('获取导出列表失败,请稍后重试')
} finally {
exportListLoading.value = false
}
}
//
const downloadExportFile = (item) => {
if (item.state === 2) {
const link = document.createElement('a')
link.href = item.url
link.download = item.fileName
link.click()
} else {
ElMessage.warning('文件还在导出中,请稍后再试')
}
}
//
const getTagType = (state) => {
switch (state) {
case 0:
return 'info';
case 1:
return 'primary';
case 2:
return 'success';
case 3:
return 'danger';
default:
return 'info';
}
}
//
const getTagText = (state) => {
switch (state) {
case 0:
return '待执行';
case 1:
return '执行中';
case 2:
return '执行完成';
case 3:
return '执行出错';
default:
return '未知状态';
}
}
</script>
<template>
<el-card class="card1" style="margin-bottom: 0.5vh">
<el-col style="margin-bottom: 1vh; ">
<div class="select">
<div class="selectRow">
<el-text class="text" size="large">精网号</el-text>
<el-input class="selectContent" v-model="beanConsumeArticle.jwcode" placeholder="请输入精网号" clearable />
</div>
<div class="selectRow">
<el-text class="text" size="large">所属地区</el-text>
<el-select class="selectContent" v-model="beanConsumeArticle.dept" placeholder="请选择地区" clearable>
<el-option v-for="(item, index) in dept" :key="index" :label="item" :value="item" />
</el-select>
</div>
<div class="selectRow">
<el-text class="text" size="large">商品名称</el-text>
<el-select class="selectContent" style="width: 20px" v-model="beanConsumeArticle.payMode" placeholder="请选择类型"
clearable @change="handlePayModeChange">
<el-option label="打赏" value="0" />
<el-option label="付费购买" value="1" />
<el-option label="其他" value="2" />
</el-select>
</div>
<div class="selectRow">
<el-text class="text">频道名称</el-text>
<el-select class="selectContent" placeholder="请选择频道" clearable filterable>
<el-option v-for="(item, index) in channels" :key="index" :label="item" :value="item" />
</el-select>
</div>
</div>
</el-col>
<el-col>
<div class="select">
<div class="selectRow" style="width: 33vw;">
<el-text class="text" size="large">下单时间</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" range-separator=""
start-placeholder="起始时间" end-placeholder="结束时间" style="width:25vw" @change="handleDatePickerChange"
value-format="YYYY-MM-DD HH:mm:ss" :default-time="defaultTime" />
<div v-if="false">
<el-button @click="getToday()" :type="activeTimeRange === 'today' ? 'primary' : ''"></el-button>
<el-button @click="getYesterday()" :type="activeTimeRange === 'yesterday' ? 'primary' : ''"></el-button>
<el-button @click="get7Days()" :type="activeTimeRange === '7days' ? 'primary' : ''">近7天</el-button>
</div>
</div>
<div class="selectRow">
<el-text class="text" size="large">直播间名称</el-text>
<el-input class="selectContent" placeholder="请输入直播间" clearable />
</div>
</div>
</el-col>
<el-col>
<div class="selectButton">
<el-button type="primary" @click="search()">查询</el-button>
<el-button type="primary" @click="exportExcel()">导出Excel</el-button>
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
<el-button type="success" @click="reset()">重置</el-button>
</div>
</el-col>
</el-card>
<el-card class="card2">
<div class="goldStatistics">
金豆总数{{ format3(Math.abs(permanentBean + freeBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆数{{ format3(Math.abs(permanentBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆数{{ format3(Math.abs(freeBean)) }}
</div>
<div style="overflow-y: auto">
<el-table :data="tableData" style="width: 82vw" height="65vh" @sort-change="handleSortChange"
:row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="110px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<!-- 固定姓名列 -->
<el-table-column prop="name" label="姓名" width="140px" fixed="left" show-overflow-tooltip />
<!-- 固定精网号列 -->
<el-table-column prop="jwcode" label="精网号" width="140px" fixed="left" />
<el-table-column prop="dept" label="地区" width="140px" />
<el-table-column prop="type" label="商品名称" width="160px"/>
<el-table-column prop="beanNum" label="金币数量" sortable="custom" width="140px" />
<el-table-column prop="buyBean" label="频道名称" width="160px" show-overflow-tooltip />
<el-table-column prop="freeBean" label="直播间名称" width="160px" show-overflow-tooltip />
<el-table-column prop="consumeTime" label="下单时间" sortable="custom" width="180px">
<template #default="scope">
{{ formatTime(scope.row.consumeTime) }}
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination">
<el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
</el-card>
<!-- 导出弹窗 -->
<el-dialog v-model="exportListVisible" title="导出列表" width="80%">
<el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
<el-table-column prop="fileName" label="文件名" />
<el-table-column prop="state" label="状态">
<template #default="scope">
<el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
{{ getTagText(scope.row.state) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="scope">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
:disabled="scope.row.state !== 2">
下载
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button text @click="exportListVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
height: 78vh;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.pagination {
display: flex;
margin-top: 20px;
}
/** 搜索的样式 */
.selectButton {
margin-left: 1vw;
margin-top: 1vh;
}
.select {
display: flex;
.selectRow {
width: 16vw;
display: flex;
align-items: center;
justify-content: center;
padding: 0 0.5vw;
.text {
width: 5vw;
font-size: 15px;
}
.textB {
width: 7vw;
font-size: 15px;
}
.selectContent {
flex: 1;
}
}
}
</style>

657
src/views/channelManage/fans/fans.vue

@ -0,0 +1,657 @@
<script setup>
import { computed, onMounted, ref } from 'vue'
import { dayjs, ElMessage } from 'element-plus'
import request from '@/util/http.js'
import API from '@/util/http.js'
import moment from 'moment'
//
/*
====================工具方法==============================
*/
const format3 = (num) => {
//
return num.toLocaleString('en-US')
}
//
const formatTime = (val) => val ? dayjs(val).format('YYYY-MM-DD HH:mm:ss') : ''
const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
]
/*
====================数据=================================
*/
//
const adminData = ref({})
//
const tableData = ref([])
// beanConsumeFan
const beanConsumeFan = ref({
jwcode: null,
dept: "",
type: "",
gift: "",
channel: "",
liveRoom: "",
startTime: '',
endTime: '',
})
//
const channels = ref([])
//
const getChannel = async function () {
try {
const result = await request({
url: '/beanConsume/getLiveChannel', // todo
data: { account: adminData.value.account }
})
console.log('请求频道列表成功', result)
//
channels.value = result.data
console.log('频道数据', channels.value)
} catch (error) {
console.log('请求频道列表失败', error)
ElMessage({
type: 'error',
message: '获取频道列表失败,请稍后重试'
})
}
}
// //
// const filterChannel = (query) => {
// if (query) {
// return channels.value.filter(item => item.toLowerCase().includes(query.toLowerCase()));
// }
// return channels.value;
// };
//
const consumeTypes = ref([
{ label: '发礼物', value: 1 },
{ label: '发红包', value: 2 },
{ label: '发福袋', value: 3 },
{ label: '付费直播', value: 4 },
{ label: '加入粉丝团', value: 5 },
{ label: '发弹幕', value: 6 },
{ label: '单次付费', value: 7 },
{ label: '连续包月', value: 8 }
])
// //
// const handleTypeChange = (value) => {
// if (value !== 1) {
// beanConsumeFan.value.gift = ''
// }
// }
//------------------------
//
const activeTimeRange = ref('')
//
const handleDatePickerChange = () => {
activeTimeRange.value = ''
}
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref({
startTime: '',
endTime: ''
})
//
// const activity = ref([])
//
const dept = ref([])
//
const sortField = ref('')
const sortOrder = ref('')
//
const permanentBean = ref(0)
const freeBean = ref(0)
const totalNum = ref(0)
/*
====================方法=================================
*/
//
const getAdminData = async function () {
try {
const result = await request({
url: '/admin/userinfo',
data: {}
})
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
const ConsumeSelectBy = async function (val) {
try {
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value.startTime != '' && getTime.value.endTime != '') {
beanConsumeFan.value.startTime = formatTime(getTime.value[0])
beanConsumeFan.value.endTime = formatTime(getTime.value[1])
}
} else {
beanConsumeFan.value.startTime = ''
beanConsumeFan.value.endTime = ''
}
beanConsumeFan.value.sortField = sortField.value
beanConsumeFan.value.sortOrder = sortOrder.value
console.log('搜索参数_时间', beanConsumeFan.value.startTime)
console.log('搜索参数1', getObj.value)
console.log('搜索参数2', beanConsumeFan.value)
// POST
const result = await request({
url: '/beanConsume/selectFanBy',
data: {
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize,
beanConsumeFan: {
...beanConsumeFan.value,
jwcode: beanConsumeFan.value.jwcode ? String(beanConsumeFan.value.jwcode) : '',
dept: beanConsumeFan.value.dept || '',
channel: beanConsumeFan.value.channel || '',
startTime: beanConsumeFan.value.startTime || '',
endTime: beanConsumeFan.value.endTime || '',
sortField: beanConsumeFan.value.sortField || 'consumeTime',
sortOrder: beanConsumeFan.value.sortOrder || 'desc'
}
}
})
console.log('请求成功3', sortField)
console.log('接口响应结果', result);
if (result.code === 200 && result.data && result.data.list) {
tableData.value = result.data.list;
total.value = result.data.total;
}
//
// beanConsumeFan.value payType 1 7
const sumConsumeParams = {
payType: 7, // payType 7
beanConsumeFan: {
...beanConsumeFan.value,
}
};
// POST
const resultTotalGold = await request({
url: '/beanConsume/sumConsumeGold',
data: sumConsumeParams
});
console.log("总计2", resultTotalGold);
const data = resultTotalGold.data || resultTotalGold;
console.log('请求成功2', resultTotalGold.data)
console.log('permanentBean2', data.permanentBean)
// permanentBeanfreeBeantotalNum
permanentBean.value = Number(data.permanentBean) || 0;
freeBean.value = Number(data.freeBean) || 0;
totalNum.value = Number(data.totalNum) || 0;
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const search = function () {
getObj.value.pageNum = 1
if (beanConsumeFan.value.jwcode) {
const numRef = /^\d{1,9}$/;
if (!numRef.test(beanConsumeFan.value.jwcode)) {
ElMessage.error('请检查精网号格式')
return
}
}
ConsumeSelectBy()
}
//
const reset = function () {
console.log('兄弟,你点了重置')
beanConsumeFan.value.jwcode = null
beanConsumeFan.value.type = ''
beanConsumeFan.value.gift = ''
beanConsumeFan.value.channel = ''
beanConsumeFan.value.liveRoom = ''
beanConsumeFan.value.dept = ''
beanConsumeFan.value.startTime = ''
beanConsumeFan.value.endTime = ''
sortField.value = ''
sortOrder.value = ''
getTime.value = {}
activeTimeRange.value = '' //
//
ConsumeSelectBy()
console.log(' beanConsumeFan', beanConsumeFan.value)
}
//
const getToday = function () {
const today = dayjs()
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = 'today' //
ConsumeSelectBy()
}
//
const getYesterday = function () {
const today = dayjs()
const startTime = today.subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.subtract(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = 'yesterday' //
console.log('昨', getTime.value)
ConsumeSelectBy()
}
// 7
const get7Days = function () {
const today = dayjs()
const startTime = today.subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = '7days' //
ConsumeSelectBy()
}
//
const getDept = async function () {
try {
//
const result = await request({
// url: '/general/dept',
url: '/beanConsume/getDept', // todo
data: { account: adminData.value.account }
})
console.log('请求地区列表成功', result)
//
dept.value = result.data
console.log('地区数据', dept.value)
} catch (error) {
console.log('请求地区列表失败', error)
ElMessage({
type: 'error',
message: '获取地区列表失败,请稍后重试'
})
}
}
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'beanNum') {
sortField.value = 'beanNum'
} else if (column.prop === 'consumeTime') {
sortField.value = 'consumeTime'
} else if (column.prop === 'buyBean') {
sortField.value = 'buyBean'
} else if (column.prop === 'freeBean') {
sortField.value = 'freeBean'
}
sortOrder.value = column.order === 'ascending' ? 'DESC' : 'ASC'
ConsumeSelectBy()
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
ConsumeSelectBy()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
ConsumeSelectBy()
}
/*
====================计算属性=================================
*/
//
// const totalBean = computed(() => permanentBean.value + freeBean.value)
/*
====================监听=================================
*/
/*
====================挂载=================================
*/
onMounted(async function () {
await getAdminData()
await ConsumeSelectBy()
await getChannel()
await getDept()
})
const exportExcel = async function () {
const params = { //
...getObj.value,
"beanConsumeFan": {
...beanConsumeFan.value,
sortField: sortField.value,
sortOrder: sortOrder.value,
},
}
const res = await API({ url: '/export/exportFan', data: params })
if (res.code === 200) {
ElMessage.success('导出成功')
}
}
const exportListVisible = ref(false)
//
const openExportList = () => {
getExportList()
exportListVisible.value = true
}
//
const exportList = ref([])
//
const exportListLoading = ref(false)
//
const getExportList = async () => {
exportListLoading.value = true
try {
const result = await API({ url: '/export/export' })
if (result.code === 200) {
const filteredData = result.data.filter(item => {
return item.type === 7; //4 // todo type 7
});
exportList.value = filteredData
} else {
ElMessage.error(result.msg || '获取导出列表失败')
}
} catch (error) {
console.error('获取导出列表出错:', error)
ElMessage.error('获取导出列表失败,请稍后重试')
} finally {
exportListLoading.value = false
}
}
//
const downloadExportFile = (item) => {
if (item.state === 2) {
const link = document.createElement('a')
link.href = item.url
link.download = item.fileName
link.click()
} else {
ElMessage.warning('文件还在导出中,请稍后再试')
}
}
//
const getTagType = (state) => {
switch (state) {
case 0:
return 'info';
case 1:
return 'primary';
case 2:
return 'success';
case 3:
return 'danger';
default:
return 'info';
}
}
//
const getTagText = (state) => {
switch (state) {
case 0:
return '待执行';
case 1:
return '执行中';
case 2:
return '执行完成';
case 3:
return '执行出错';
default:
return '未知状态';
}
}
</script>
<template>
<el-card class="card1" style="margin-bottom: 0.5vh;">
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
<el-text class="text">精网号</el-text>
<el-input class="selectContent" v-model="beanConsumeFan.jwcode" placeholder="请输入精网号" clearable />
</div>
<div class="selectRow">
<el-text class="text">地区</el-text>
<el-select class="selectContent" v-model="beanConsumeFan.dept" placeholder="请选择地区" clearable>
<el-option v-for="(item, index) in dept" :key="index" :label="item" :value="item" />
</el-select>
</div>
<div class="selectRow">
<el-text class="text">频道</el-text>
<el-select class="selectContent" v-model="beanConsumeFan.channel" placeholder="请选择频道" clearable filterable>
<el-option v-for="(item, index) in channels" :key="index" :label="item" :value="item" />
</el-select>
</div>
</div>
</el-col>
<el-col>
<div class="select">
<div class="selectRow" style="width: 36vw;">
<el-text class="text" size="large">消费时间</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" range-separator=""
start-placeholder="起始时间" end-placeholder="结束时间" style="margin-right:1vw;width:25vw"
@change="handleDatePickerChange" value-format="YYYY-MM-DD HH:mm:ss" :default-time="defaultTime" />
<div v-if="false">
<el-button @click="getToday()" :type="activeTimeRange === 'today' ? 'primary' : ''"></el-button>
<el-button @click="getYesterday()" :type="activeTimeRange === 'yesterday' ? 'primary' : ''"></el-button>
<el-button @click="get7Days()" :type="activeTimeRange === '7days' ? 'primary' : ''">近7天</el-button>
</div>
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button type="primary" @click="search()">查询</el-button>
<el-button type="primary" @click="exportExcel()">导出Excel</el-button>
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
<el-button type="success" @click="reset()">重置</el-button>
</div>
</div>
</el-col>
</el-card>
<el-card class="card2">
<div class="goldStatistics">
金豆总数{{ format3(Math.abs(permanentBean + freeBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆数{{ format3(Math.abs(permanentBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆数{{ format3(Math.abs(freeBean)) }}
</div>
<div style="overflow-y: auto">
<el-table :data="tableData" style="width: 82vw" height="68vh" @sort-change="handleSortChange"
:row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="80px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<!-- 固定姓名列 -->
<el-table-column prop="name" label="姓名" width="150px" fixed="left" show-overflow-tooltip />
<!-- 固定精网号列 -->
<el-table-column prop="jwcode" label="精网号" width="110px" fixed="left" />
<el-table-column prop="dept" label="地区" width="110px" />
<el-table-column prop="beanNum" label="金豆数量" sortable="custom" width="120px" />
<el-table-column prop="buyBean" label="付费金豆数" sortable="custom" width="120px" />
<el-table-column prop="freeBean" label="免费金豆数" sortable="custom" width="120px" />
<el-table-column prop="channel" label="频道" width="190px" show-overflow-tooltip />
<el-table-column prop="type" label="会员类型" width="120px">
<template #default="scope">
{{consumeTypes.find(item => item.value === Number(scope.row.type))?.label || '未知类型'}}
</template>
</el-table-column>
<el-table-column prop="consumeTime" label="加入时间" sortable="custom" width="180px" />
</el-table>
</div>
<!-- 分页 -->
<div class="pagination">
<el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
</el-card>
<!-- 导出弹窗 -->
<el-dialog v-model="exportListVisible" title="导出列表" width="80%">
<el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
<el-table-column prop="fileName" label="文件名" />
<el-table-column prop="state" label="状态">
<template #default="scope">
<el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
{{ getTagText(scope.row.state) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="scope">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
:disabled="scope.row.state !== 2">
下载
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button text @click="exportListVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
height: 81vh;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.pagination {
display: flex;
margin-top: 20px;
}
/** 搜索的样式 */
.select {
display: flex;
.selectRow {
width: 17vw;
display: flex;
align-items: center;
justify-content: center;
padding: 0 0.5vw;
.text {
width: 5vw;
font-size: 15px;
}
.selectContent {
flex: 1;
}
}
}
</style>

700
src/views/channelManage/reward/reward.vue

@ -0,0 +1,700 @@
<script setup>
import { computed, onMounted, ref } from 'vue'
import { dayjs, ElMessage } from 'element-plus'
import request from '@/util/http.js'
import API from '@/util/http.js'
import moment from 'moment'
//
/*
====================工具方法==============================
*/
const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
]
const format3 = (num) => {
//
return num.toLocaleString('en-US')
}
//
const formatTime = (val) => val ? dayjs(val).format('YYYY-MM-DD HH:mm:ss') : ''
/*
====================数据=================================
*/
//
const adminData = ref({})
//
const tableData = ref([])
// beanConsumeLive
const beanConsumeLive = ref({
jwcode: null,
dept: "",
type: "",
gift: "",
liveChannel: "",
liveName: "",
startTime: '',
endTime: '',
sortField: '',
sortOrder: ''
})
//
const gifts = ref([])
//
const getGift = async function () {
try {
const result = await request({
url: '/beanConsume/getLiveGift', // todo
data: { account: adminData.value.account }
})
console.log('请求礼物列表成功', result)
//
gifts.value = result.data
console.log('礼物数据', gifts.value)
} catch (error) {
console.log('请求礼物列表失败', error)
ElMessage({
type: 'error',
message: '获取礼物列表失败,请稍后重试'
})
}
}
//
const channels = ref([])
//
const getChannel = async function () {
try {
const result = await request({
url: '/beanConsume/getLiveChannel', // todo
data: { account: adminData.value.account }
})
console.log('请求频道列表成功', result)
//
channels.value = result.data
console.log('频道数据', channels.value)
} catch (error) {
console.log('请求频道列表失败', error)
ElMessage({
type: 'error',
message: '获取频道列表失败,请稍后重试'
})
}
}
//
const consumeTypes = ref([
{ label: '发礼物', value: 1 },
{ label: '发红包', value: 2 },
{ label: '发福袋', value: 3 },
{ label: '付费直播', value: 4 },
{ label: '加入粉丝团', value: 5 },
{ label: '发弹幕', value: 6 }
])
//
const handleTypeChange = (value) => {
if (value !== 1) {
beanConsumeLive.value.gift = ''
}
}
//------------------------
//
const activeTimeRange = ref('')
//
const handleDatePickerChange = () => {
activeTimeRange.value = ''
}
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref({
startTime: '',
endTime: ''
})
//
const dept = ref([])
//
const getDept = async function () {
try {
//
const result = await request({
// url: '/general/dept',
url: '/beanConsume/getDept', // todo
data: { account: adminData.value.account }
})
console.log('请求地区列表成功', result)
//
dept.value = result.data
console.log('地区数据', dept.value)
} catch (error) {
console.log('请求地区列表失败', error)
ElMessage({
type: 'error',
message: '获取地区列表失败,请稍后重试'
})
}
}
//
const sortField = ref('')
const sortOrder = ref('')
//
const permanentBean = ref(0)
const freeBean = ref(0)
const totalNum = ref(0)
/*
====================方法=================================
*/
//
const getAdminData = async function () {
try {
const result = await request({
url: '/admin/userinfo',
data: {}
})
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
const selectLiveBy = async function (val) {
try {
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
//
if (Array.isArray(getTime.value) && getTime.value.length === 2) {
beanConsumeLive.value.startTime = formatTime(getTime.value[0])
beanConsumeLive.value.endTime = formatTime(getTime.value[1])
} else {
beanConsumeLive.value.startTime = ''
beanConsumeLive.value.endTime = ''
}
//
beanConsumeLive.value.sortField = sortField.value
beanConsumeLive.value.sortOrder = sortOrder.value
console.log('搜索参数_时间', beanConsumeLive.value.startTime)
console.log('搜索参数1', getObj.value)
console.log('搜索参数2', beanConsumeLive.value)
// POST
const result = await request({
url: '/beanConsume/selectLiveBy',
data: {
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize,
beanConsumeLive: {
...beanConsumeLive.value,
jwcode: beanConsumeLive.value.jwcode ? String(beanConsumeLive.value.jwcode) : '',
dept: beanConsumeLive.value.dept || '',
type: beanConsumeLive.value.type || '',
gift: beanConsumeLive.value.gift || '',
beanNum: beanConsumeLive.value.beanNum || '',
isBackpack: beanConsumeLive.value.isBackpack || '',
liveChannel: beanConsumeLive.value.liveChannel || '',
liveName: beanConsumeLive.value.liveName || '',
startTime: beanConsumeLive.value.startTime || '',
endTime: beanConsumeLive.value.endTime || '',
sortField: beanConsumeLive.value.sortField || 'consumeTime',
sortOrder: beanConsumeLive.value.sortOrder || 'desc'
}
}
})
console.log('请求成功2', sortField)
console.log('接口响应结果', result); //
if (result.code === 200 && result.data && result.data.list) {
tableData.value = result.data.list;
total.value = result.data.total;
}
// beanConsumeLive.value payType 1
const sumConsumeParams = {
payType: 1, // payType 1
beanConsumeLive: {
...beanConsumeLive.value,
}
};
// POST
const resultTotalGold = await request({
url: '/beanConsume/sumConsumeGold',
data: sumConsumeParams
});
console.log("总计", resultTotalGold);
const data = resultTotalGold.data || resultTotalGold;
console.log('请求成功1', resultTotalGold.data) //undifined
console.log('permanentBean1', data.permanentBean)
// permanentBeanfreeBeantotalNum
permanentBean.value = Number(data.permanentBean) || 0;
freeBean.value = Number(data.freeBean) || 0;
totalNum.value = Number(data.totalNum) || 0;
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const search = function () {
getObj.value.pageNum = 1
if (beanConsumeLive.value.jwcode) {
const numRef = /^\d{1,9}$/;
if (!numRef.test(beanConsumeLive.value.jwcode)) {
ElMessage.error('请检查精网号格式')
return
}
}
selectLiveBy()
}
//
const reset = function () {
console.log('直播的重置')
beanConsumeLive.value.jwcode = null
beanConsumeLive.value.type = ''
beanConsumeLive.value.gift = ''
beanConsumeLive.value.liveChannel = ''
beanConsumeLive.value.liveName = ''
beanConsumeLive.value.dept = ''
beanConsumeLive.value.startTime = ''
beanConsumeLive.value.endTime = ''
sortField.value = ''
sortOrder.value = ''
getTime.value = {}
activeTimeRange.value = '' //
//
selectLiveBy()
console.log(' beanConsumeLive', beanConsumeLive.value)
}
//
const getToday = function () {
const today = dayjs()
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = 'today' //
selectLiveBy()
}
//
const getYesterday = function () {
const today = dayjs()
const startTime = today.subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.subtract(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = 'yesterday' //
selectLiveBy()
}
// 7
const get7Days = function () {
const today = dayjs()
const startTime = today.subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
getTime.value = [startTime, endTime]
console.log('getTime', getTime.value)
activeTimeRange.value = '7days' //
selectLiveBy()
}
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'beanNum') {
sortField.value = 'beanNum'
} else if (column.prop === 'consumeTime') {
sortField.value = 'consumeTime'
} else if (column.prop === 'buyBean') {
sortField.value = 'buyBean'
} else if (column.prop === 'freeBean') {
sortField.value = 'freeBean'
}
sortOrder.value = column.order === 'ascending' ? 'DESC' : 'ASC'
selectLiveBy()
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
selectLiveBy()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
selectLiveBy()
}
/*
====================计算属性=================================
*/
//
// const totalBean = computed(() => permanentBean.value + freeBean.value)
/*
====================监听=================================
*/
/*
====================挂载=================================
*/
onMounted(async function () {
await getAdminData()
await selectLiveBy()
await getDept()
await getGift()
await getChannel()
})
const exportExcel = async function () {
console.log('1')
const params = {
...getObj.value,
"beanConsumeLive": {
...beanConsumeLive.value,
jwcode: beanConsumeLive.value.jwcode ? String(beanConsumeLive.value.jwcode) : '',
dept: beanConsumeLive.value.dept || '',
type: beanConsumeLive.value.type || '',
gift: beanConsumeLive.value.gift || '',
liveChannel: beanConsumeLive.value.liveChannel || '',
liveName: beanConsumeLive.value.liveName || '',
startTime: beanConsumeLive.value.startTime || '',
endTime: beanConsumeLive.value.endTime || '',
sortField: sortField.value || 'consumeTime',
sortOrder: sortOrder.value || 'desc'
}
}
// 便
console.log('导出请求参数:', params);
try {
console.log('2')
const res = await API({ url: '/export/exportLive', data: params });
console.log('导出请求响应:', res);
if (res.code === 200) {
ElMessage.success('导出成功');
} else {
ElMessage.error(res.message || '导出失败,请稍后重试');
}
} catch (error) {
console.error('导出请求出错:', error);
ElMessage.error('导出失败,请稍后重试');
}
}
const exportListVisible = ref(false)
//
const openExportList = () => {
getExportList()
exportListVisible.value = true
}
//
const exportList = ref([])
//
const exportListLoading = ref(false)
//
const getExportList = async () => {
exportListLoading.value = true
try {
const result = await API({ url: '/export/export' })
if (result.code === 200) {
const filteredData = result.data.filter(item => {
return item.type === 6; //4 // todo type 6
});
exportList.value = filteredData
} else {
ElMessage.error(result.msg || '获取导出列表失败')
}
} catch (error) {
console.error('获取导出列表出错:', error)
ElMessage.error('获取导出列表失败,请稍后重试')
} finally {
exportListLoading.value = false
}
}
//
const downloadExportFile = (item) => {
if (item.state === 2) {
const link = document.createElement('a')
link.href = item.url
link.download = item.fileName
link.click()
} else {
ElMessage.warning('文件还在导出中,请稍后再试')
}
}
//
const getTagType = (state) => {
switch (state) {
case 0:
return 'info';
case 1:
return 'primary';
case 2:
return 'success';
case 3:
return 'danger';
default:
return 'info';
}
}
//
const getTagText = (state) => {
switch (state) {
case 0:
return '待执行';
case 1:
return '执行中';
case 2:
return '执行完成';
case 3:
return '执行出错';
default:
return '未知状态';
}
}
</script>
<template>
<el-card class="card1" style="margin-bottom: 0.5vh;">
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
<el-text class="text">精网号</el-text>
<el-input class="selectContent" v-model="beanConsumeLive.jwcode" placeholder="请输入精网号" clearable />
</div>
<div class="selectRow">
<el-text class="text">地区</el-text>
<el-select class="selectContent" v-model="beanConsumeLive.dept" placeholder="请选择地区" clearable>
<el-option v-for="(item, index) in dept" :key="index" :label="item" :value="item" />
</el-select>
</div>
<div class="selectRow" style="width: 14vw;">
<el-text class="text">礼物名称</el-text>
<el-select class="selectContent" v-model="beanConsumeLive.gift" placeholder="请选择礼物名称" clearable filterable
allow-create default-first-option>
<el-option v-for="(item, index) in gifts" :key="index" :label="item" :value="item" />
</el-select>
</div>
<div class="selectRow" style="width: 12vw;">
<el-text class="textB" size="large">频道</el-text>
<el-select class="selectContent" v-model="beanConsumeLive.liveChannel" placeholder="请选择频道" clearable
filterable allow-create default-first-option>
<el-option v-for="(item, index) in channels" :key="index" :label="item" :value="item" />
</el-select>
</div>
<div class="selectRow" style="width: 12vw;">
<el-text class="textB" size="large">直播间</el-text>
<el-input class="selectContent" v-model="beanConsumeLive.liveName" placeholder="请输入直播间" clearable />
</div>
</div>
</el-col>
<el-col>
<div class="select">
<div class="selectRow" style="width: 31.4vw;">
<el-text class="text">消费时间</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" range-separator=""
start-placeholder="起始时间" end-placeholder="结束时间" style="margin-right:1vw;width:480px"
@change="handleDatePickerChange" :default-time="defaultTime" />
<div v-if="false">
<el-button @click="getToday()" :type="activeTimeRange === 'today' ? 'primary' : ''"> </el-button>
<el-button @click="getYesterday()" :type="activeTimeRange === 'yesterday' ? 'primary' : ''"> </el-button>
<el-button @click="get7Days()" :type="activeTimeRange === '7days' ? 'primary' : ''"> 近7天</el-button>
</div>
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button type="primary" @click="search()">查询</el-button>
<el-button type="primary" @click="exportExcel()">导出excel</el-button>
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
<el-button type="success" @click="reset()">重置</el-button>
</div>
</div>
</el-col>
</el-card>
<el-card class="card2">
<div class="goldStatistics">
金豆总数{{ format3(Math.abs(permanentBean + freeBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆数{{ format3(Math.abs(permanentBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆数{{ format3(Math.abs(freeBean)) }}
</div>
<div style="overflow-y: auto">
<el-table :data="tableData" style="width: 82vw" height="68vh" @sort-change="handleSortChange"
:row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="80px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<!-- 固定姓名列 -->
<el-table-column prop="name" label="姓名" width="150px" fixed="left" show-overflow-tooltip />
<!-- 固定精网号列 -->
<el-table-column prop="jwcode" label="精网号" width="110px" fixed="left" />
<el-table-column prop="dept" label="地区" width="110px" />
<el-table-column prop="gift" label="礼物" width="140px">
</el-table-column>
<el-table-column prop="beanNum" label="金豆数量" sortable="custom" width="120px" />
<el-table-column prop="isBackpack" label="背包礼物" width="120px">
<template #default="scope">
{{ scope.row.isBackpack == 1 ? '是' : '否' }}
</template>
</el-table-column>
<el-table-column prop="buyBean" label="付费金豆数" sortable="custom" width="120px" />
<el-table-column prop="freeBean" label="免费金豆数" sortable="custom" width="120px" />
<el-table-column prop="liveChannel" label="频道" width="120px" show-overflow-tooltip />
<el-table-column prop="liveName" label="直播间名称" width="160px" show-overflow-tooltip />
<el-table-column prop="consumeTime" label="消费时间" sortable="custom" width="180px" />
</el-table>
</div>
<el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]" style="margin-top: 20px;"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</el-card>
<!-- 导出弹窗 -->
<el-dialog v-model="exportListVisible" title="导出列表" width="80%">
<el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
<el-table-column prop="fileName" label="文件名" />
<el-table-column prop="state" label="状态">
<template #default="scope">
<el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
{{ getTagText(scope.row.state) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="scope">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
:disabled="scope.row.state !== 2">
下载
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button text @click="exportListVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
height: 81vh;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.pagination {
display: flex;
margin-top: 20px;
}
/** 搜索的样式 */
.select {
display: flex;
.selectRow {
width: 14.7vw;
display: flex;
align-items: center;
justify-content: center;
padding: 0 0.5vw;
.text {
width: 5vw;
font-size: 15px;
}
.selectContent {
flex: 1;
}
}
}
</style>

339
src/views/moneyManage/receiveDetail/receiveFinance.vue

@ -190,8 +190,7 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- 地区财务表格操作待审核审核已通过编辑 --> <!-- 地区财务表格操作待审核审核已通过编辑 -->
<el-table-column fixed="right" label="操作" width="120px"
v-if="activeTab != 'reject' && activeTab != 'done'">
<el-table-column fixed="right" label="操作" width="120px" v-if="activeTab != 'reject'">
<template #default=scope> <template #default=scope>
<el-link v-if="activeTab == 'wait'" style="color: #2741DE;" <el-link v-if="activeTab == 'wait'" style="color: #2741DE;"
@click="openAuditForm(scope.row)">审核 @click="openAuditForm(scope.row)">审核
@ -200,18 +199,37 @@
v-else-if="activeTab == 'pass' && !(scope.row.status == 6 || scope.row.status == 4)" v-else-if="activeTab == 'pass' && !(scope.row.status == 6 || scope.row.status == 4)"
style="color: #2741DE;" @click="openEditForm(scope.row)">编辑 style="color: #2741DE;" @click="openEditForm(scope.row)">编辑
</el-link> </el-link>
<el-link
v-else-if="activeTab == 'done' && scope.row.status == 4 && startsWith(scope.row.orderCode, 'GOLDCOIN')"
style="color: #2741DE;" @click="openRefundConfirm(scope.row)">退款
</el-link>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<div class="pagination"> <div class="pagination">
<el-pagination background :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper" :total="total"
@size-change="handlePagination('size', $event)"
<el-pagination background :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize"
:page-sizes="[5, 10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper"
:total="total" @size-change="handlePagination('size', $event)"
@current-change="handlePagination('page', $event)"></el-pagination> @current-change="handlePagination('page', $event)"></el-pagination>
</div> </div>
</el-card> </el-card>
</div> </div>
<!-- 退款确认弹窗 -->
<div class="recallDialog" v-show="refundConfirmDialog">
<div class="close">
<button @click="closeConfirmRefund" class="Btn">关闭</button>
</div>
<div class="text">
<text class="txt">{{ textContent }}</text>
</div>
<div class="cancle">
<button @click="closeConfirmRefund" class="Btn">取消</button>
</div>
<div class="confirm">
<button @click="openRefundDialog" class="Btn">确定</button>
</div>
</div>
<!-- 仅保留地区财务相关弹窗审核弹窗编辑手续费弹窗 --> <!-- 仅保留地区财务相关弹窗审核弹窗编辑手续费弹窗 -->
<!-- 审核弹窗 --> <!-- 审核弹窗 -->
@ -406,6 +424,108 @@
</div> </div>
</div> </div>
</el-dialog> </el-dialog>
<!-- 新增退款 -->
<el-dialog v-model="refundDialog" title="退款" class="refundDialog" overflow draggable style="width: 40vw;"
:before-close="closeRefundForm">
<div style="display: flex;">
<div class="left">
<div class="add-item">
<el-text style="width:4vw;">精网号</el-text>
<el-input v-model="refundFormData.jwcode" style="width:10vw;" disabled />
</div>
<div class="add-item">
<el-text style="width:4vw;">客户姓名</el-text>
<el-input v-model="refundFormData.name" style="width:10vw;" disabled />
</div>
<div class="add-item">
<el-text style="width:4vw;">所属地区</el-text>
<el-input v-model="refundFormData.marketName" style="width:10vw;" disabled />
</div>
<div class="add-item">
<el-text style="width:4vw;">活动名称</el-text>
<el-input v-model="refundFormData.activity" style="width:10vw;" disabled />
</div>
<div class="add-item">
<el-text style="width:4vw;">产品名称</el-text>
<el-input v-model="refundFormData.goodsName" style="width:10vw;" disabled />
</div>
<div v-show="!isRefundGold" class="add-item">
<el-text style="width:4vw;">产品数量</el-text>
<el-input style="padding-right: 10px; width:10.5vw;" v-model="refundFormData.goodNum"
placeholder="请输入产品数量" disabled />
</div>
<div v-show="isRefundGold" style="display: flex; margin-bottom: 10px;">
<div style=" display: flex; align-items: center;justify-content: center; ">
<span style="color: #999999; white-space: nowrap;">永久金币</span>
<el-input style="padding-right: 10px; height: 30px; width: 70px;"
v-model="refundFormData.permanentGold" disabled />
</div>
<div style=" display: flex; align-items: center;justify-content: center; ">
<span
style="color: #999999; white-space: nowrap;">免费金币</span>
<el-input style="padding-right: 10px; height: 30px; width: 70px;"
v-model="refundFormData.freeGold" disabled />
</div>
</div>
<div class="add-item">
<el-text style="width:4vw;">付款币种</el-text>
<el-input v-model="refundFormData.paymentCurrency" style="width:10vw;" disabled />
</div>
<div class="add-item">
<el-text style="width:4vw;">付款金额</el-text>
<el-input v-model="refundFormData.paymentAmount" style="width:10vw;" disabled />
</div>
<div class="add-item">
<el-text style="width:4vw;">支付方式</el-text>
<el-input v-model="refundFormData.payType" style="width:10vw;" disabled />
</div>
<div class="add-item">
<el-text style="width:4vw;">付款时间</el-text>
<el-date-picker v-model="refundFormData.payTime" type="datetime" style="width:10vw;" disabled />
</div>
<div class="add-item">
<el-text style="width:4vw;" size="small">转账凭证</el-text>
<el-form-item :rules="{ required: true, message: '请上传图片', trigger: 'change' }">
<el-upload ref="uploadRef" :auto-upload="false" list-type="picture-card"
:show-file-list="false">
<template #default>
<img v-if="refundFormData.voucher" :src="refundFormData.voucher"
style="width: 100%; height: 100%; object-fit: cover;">
<el-icon v-else>
<Plus />
</el-icon>
</template>
</el-upload>
</el-form-item>
</div>
<div class="add-item">
<el-text style="width:4vw;">备注</el-text>
<el-input v-model="refundFormData.remark" style="width:10vw;" :rows="2" type="textarea"
maxLength="100" disabled show-word-limit />
</div>
</div>
<div class="right">
<div class="add-item">
<el-text style="width:4vw;">退款模式</el-text>
<el-radio-group v-model="refundFormData.refundModel">
<el-radio value="0">全部退款</el-radio>
<el-radio value="1">部分退款</el-radio>
</el-radio-group>
</div>
<div class="add-item">
<el-text style="width:4vw;">退款理由</el-text>
<el-input v-model="refundFormData.refundReason" style="width:10vw;" :rows="5" maxlength="150"
show-word-limit type="textarea" />
</div>
<div>ps:请在退款理由表明用户的退款需求</div>
<div style="display:flex;justify-content: center;margin-top: 5vh;">
<el-button type="default" @click="">重置</el-button>
<el-button type="primary" @click="throttledsubmitRefund">提交</el-button>
</div>
</div>
</div>
</el-dialog>
</div> </div>
</template> </template>
@ -419,6 +539,7 @@ import request from '@/util/http.js';
import moment from 'moment'; import moment from 'moment';
import _ from 'lodash'; import _ from 'lodash';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import { startsWith } from './utils/util.js'
// //
import CurrencySelect from '@/components/MoneyManage/CurrencySelect.vue'; import CurrencySelect from '@/components/MoneyManage/CurrencySelect.vue';
@ -474,7 +595,38 @@ const tooltipContent = ref('');
const tooltipLeft = ref(0); const tooltipLeft = ref(0);
const tooltipTop = ref(0); const tooltipTop = ref(0);
//
// 退
const refundConfirmDialog = ref(false)
const textContent = ref('')
//退
const refundDialog = ref(false)
const refundFormData = ref({})
const openRefundDialog = () => {
refundDialog.value = true
closeConfirmRefund()
}
const closeRefundForm = () => {
refundDialog.value = false
refundFormData.value = {}
}
const isRefundGold = ref(false)
const ifRefundGold = () => {
if (refundFormData.value.goodsName === '金币充值') {
isRefundGold.value = true
refundFormData.value.goodNum = 0
} else {
isRefundGold.value = false
}
}
//
const adminData = ref({}); const adminData = ref({});
const activityList = ref([]); const activityList = ref([]);
const customOptions = ref(['美元(USD)', '港币(HKD)', '新币(SGD)', '马币(MYR)', '泰铢(THB)', '加币(CAD)', '越南盾(VDN)', '韩元(KRW)']); const customOptions = ref(['美元(USD)', '港币(HKD)', '新币(SGD)', '马币(MYR)', '泰铢(THB)', '加币(CAD)', '越南盾(VDN)', '韩元(KRW)']);
@ -482,6 +634,23 @@ const paytypeList = ["Stripe-链接收款", "PaymentAsia-链接收款", "Ipay88-
const paytypeOptions = ref([...paytypeList]); const paytypeOptions = ref([...paytypeList]);
// ===================== 2. ===================== // ===================== 2. =====================
//退
const openRefundConfirm = (row) => {
textContent.value = '将要对该订单退款!'
refundConfirmDialog.value = true
refundFormData.value = { ...row }
ifRefundGold()
console.log(row);
}
const closeConfirmRefund = () => {
refundConfirmDialog.value = false
textContent.value = ''
}
// 2.1 // 2.1
const getlist = async () => { const getlist = async () => {
try { try {
@ -544,6 +713,54 @@ const getlist = async () => {
} }
}; };
//退
const submitRefund = async () => {
try {
const result = await request({
url: '/Money/add',
data: {
jwcode: refundFormData.value.jwcode, //
name: refundFormData.value.name, //
market: refundFormData.value.marketName, //
activity: refundFormData.value.activity, //
bankCode: refundFormData.value.bankCode, //
goodsName: refundFormData.value.goodsName, //
goodNum: refundFormData.value.goodNum, // 0
paymentCurrency: refundFormData.value.paymentCurrency, //
paymentAmount: (refundFormData.value.paymentAmount) * 100, //
receivedCurrency: refundFormData.value.receivedCurrency, //
receivedAmount: (refundFormData.value.receivedAmount) * 100, //
handlingCharge: (refundFormData.value.handlingCharge) * 100, //
receivedMarket: refundFormData.value.receivedMarket, //
payType: refundFormData.value.payType, //
payTime: refundFormData.value.payTime, // yyyy-MM-dd HH:mm:ss
receivedTime: refundFormData.value.receivedTime, // yyyy-MM-dd HH:mm:ss
areaServise: adminData.value.adminName, //
submitterId: adminData.value.id,
voucher: refundFormData.value.voucher, // URL
remark: refundFormData.value.remark, //
refundReason: refundFormData.value.refundReason, // 退-
refundModel: refundFormData.value.refundModel, // 退0-1-
id: refundFormData.value.id, //id
orderCode: refundFormData.value.orderCode,
permanentGold: (refundFormData.value.permanentGold) * 100 || 0,
freeGold: (refundFormData.value.freeGold) * 100 || 0
}
})
if (result.code == 200) {
ElMessage.success('新增退款成功')
getlist()
closeRefundForm()
} else {
ElMessage.error(result.msg)
getlist()
}
console.log('返回参数:', result);
} catch (error) {
console.log(error);
}
}
// 2.2 // 2.2
const search = () => { const search = () => {
getlist(); getlist();
@ -823,6 +1040,9 @@ onMounted(async () => {
window.history.back(); window.history.back();
}); });
} }
//
const bgImg = new Image();
bgImg.src = '/src/assets/收款明细撤回背景.png';
}); });
// 2.10 使 // 2.10 使
@ -1102,6 +1322,37 @@ const handlePagination = (type, val) => {
font-weight: 800; font-weight: 800;
padding-bottom: 15px; padding-bottom: 15px;
} }
.refundDialog {
.left {
width: 50%;
height: 70vh;
min-height: 700px;
padding: 0 2vw;
.add-item {
display: flex;
align-items: center;
margin-bottom: 1vh;
}
.image {
width: 4vw !important;
height: 4vw !important;
}
}
.right {
width: 50%;
height: 50vh;
.add-item {
display: flex;
align-items: center;
margin-bottom: 1vh;
}
}
}
} }
// //
@ -1130,4 +1381,80 @@ const handlePagination = (type, val) => {
overflow-y: auto; overflow-y: auto;
white-space: pre-wrap; white-space: pre-wrap;
} }
.recallDialog {
//
height: 392px;
width: 700px;
background-image: url('/src/assets/收款明细撤回背景.png');
position: fixed; //
top: 50%; // 50%
left: 50%; // 50%
transform: translate(-50%, -50%); // 50%
z-index: 1000; //
.close {
position: absolute;
left: 625px;
top: 20px;
height: 38px;
width: 38px;
opacity: 0;
.Btn {
height: 100%;
width: 100%;
border-radius: 10px;
}
}
.text {
position: absolute;
left: 185px;
top: 190px;
height: 67px;
width: 500px;
.txt {
height: 100%;
width: 100%;
color: #001a42;
font-family: "PingFang SC";
font-size: 48px;
font-style: normal;
font-weight: 900;
line-height: normal;
}
}
.cancle {
position: absolute;
left: 185px;
top: 304px;
height: 55px;
width: 150px;
opacity: 0;
.Btn {
height: 100%;
width: 100%;
border-radius: 20px;
}
}
.confirm {
position: absolute;
left: 375px;
top: 304px;
height: 55px;
width: 150px;
opacity: 0;
.Btn {
height: 100%;
width: 100%;
border-radius: 20px;
}
}
}
</style> </style>

1174
src/views/moneyManage/receiveDetail/receiveManage.vue
File diff suppressed because it is too large
View File

8
src/views/moneyManage/receiveDetail/receiveService.vue

@ -363,6 +363,14 @@
<el-radio value="1">部分退款</el-radio> <el-radio value="1">部分退款</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<div class="add-item" v-show="refundFormData.goodsName === '金币充值' && refundFormData.refundModel === '1'">
<el-text style="width:4vw;">永久金币</el-text>
<el-input v-model="refundFormData.aaa" style="width:5vw;" />&nbsp;&nbsp;
</div>
<div class="add-item" v-show="refundFormData.goodsName === '金币充值' && refundFormData.refundModel === '1'">
<el-text style="width:4vw;">免费金币</el-text>
<el-input v-model="refundFormData.bbb" style="width:5vw;" />&nbsp;&nbsp;
</div>
<div class="add-item"> <div class="add-item">
<el-text style="width:4vw;">退款理由</el-text> <el-text style="width:4vw;">退款理由</el-text>
<el-input v-model="refundFormData.refundReason" style="width:10vw;" :rows="5" maxlength="150" <el-input v-model="refundFormData.refundReason" style="width:10vw;" :rows="5" maxlength="150"

13
src/views/moneyManage/receiveDetail/utils/util.js

@ -0,0 +1,13 @@
//判断是否为线上订单
export const startsWith = (mainStr, prefix) => {
// 处理前缀为空字符串的情况(空字符串是所有字符串的前缀)
if (prefix === '') {
return true;
}
// 处理主字符串长度小于前缀长度的情况
if (mainStr.length < prefix.length) {
return false;
}
// 比较主字符串开头与前缀相同长度的部分
return mainStr.substring(0, prefix.length) === prefix;
}

61
src/views/permissions/rolePermission.vue

@ -9,6 +9,7 @@ import { storeToRefs } from "pinia"
const adminStore = useAdminStore(); const adminStore = useAdminStore();
const { adminData, menuTree } = storeToRefs(adminStore); const { adminData, menuTree } = storeToRefs(adminStore);
import { permissionMapping, findMenuById } from "@/utils/menuTreePermission.js" import { permissionMapping, findMenuById } from "@/utils/menuTreePermission.js"
import { tr } from 'element-plus/es/locales.mjs'
// ref // ref
const Ref = ref(null) const Ref = ref(null)
@ -35,7 +36,7 @@ const addRole = ref({
market: '' market: ''
}) })
const addRoleMarket = ref([]) const addRoleMarket = ref([])
const channelList = ref(['美股', '港股', 'hc第一频道'])
const getRoleList = async function (val) { const getRoleList = async function (val) {
if (!findMenuById(menuTree.value, permissionMapping.view_role_information)) { if (!findMenuById(menuTree.value, permissionMapping.view_role_information)) {
ElMessage.error('无此权限') ElMessage.error('无此权限')
@ -196,7 +197,8 @@ const handleAddRole = async function () {
"roleName": addRole.value.roleName, "roleName": addRole.value.roleName,
"menuIds": finalCheckedKeys, "menuIds": finalCheckedKeys,
"fatherId": addRole.value.parentId, "fatherId": addRole.value.parentId,
"market": addRole.value.market
"market": addRole.value.market,
channel: addRole.value.channel
} }
}) })
if (res.code === 200) { if (res.code === 200) {
@ -317,6 +319,7 @@ const handleEditRolePermissionCheck = (checkedNodes, checkedInfo) => {
// //
if (allCheckedNodes.length === 0) { if (allCheckedNodes.length === 0) {
permissionEditRoleObj.value.checkedKeys = [] permissionEditRoleObj.value.checkedKeys = []
ifHasChannel.value = false
return return
} }
@ -326,13 +329,22 @@ const handleEditRolePermissionCheck = (checkedNodes, checkedInfo) => {
console.log('编辑角色选中的权限ID:', checkedKeys) console.log('编辑角色选中的权限ID:', checkedKeys)
console.log('选中的节点数量:', allCheckedNodes.length) console.log('选中的节点数量:', allCheckedNodes.length)
if (checkedKeys.includes(124) || checkedKeys.includes(125) || checkedKeys.includes(126) || checkedKeys.includes(127)) {
ifHasChannel.value = true
} else {
ifHasChannel.value = false
}
}; };
//
const ifHasChannel = ref(false)
const handleCheckChange = async (checkedNodes, checkedInfo) => { const handleCheckChange = async (checkedNodes, checkedInfo) => {
const { checkedKeys, checkedNodes: allCheckedNodes } = checkedInfo const { checkedKeys, checkedNodes: allCheckedNodes } = checkedInfo
// //
if (allCheckedNodes.length === 0) { if (allCheckedNodes.length === 0) {
addRole.value.checkedKeys = [] addRole.value.checkedKeys = []
ifHasChannel.value = false
return return
} }
@ -348,6 +360,12 @@ const handleCheckChange = async (checkedNodes, checkedInfo) => {
// Set // Set
addRole.value.checkedKeys = Array.from(allKeys) addRole.value.checkedKeys = Array.from(allKeys)
console.log('新增角色包含所有父级的选中项:', addRole.value.checkedKeys) console.log('新增角色包含所有父级的选中项:', addRole.value.checkedKeys)
if (addRole.value.checkedKeys.includes(124)) {
ifHasChannel.value = true
console.log('勾选了频道');
} else {
ifHasChannel.value = false
}
} }
const selectParentNodes = (treeData, nodeId, checkedKeys) => { const selectParentNodes = (treeData, nodeId, checkedKeys) => {
if (!Array.isArray(treeData)) return false if (!Array.isArray(treeData)) return false
@ -413,18 +431,38 @@ const collectIds2 = (tree) => {
return ids return ids
} }
const collectIdsAll = (tree) => {
let ids = []
tree.forEach((node) => {
ids.push(node.id)
// children children
if (node.children || node.children.length === 0) {
ids = ids.concat(collectIdsAll(node.children))
}
})
return ids
}
// //
const permissionEditRoleInit = async function (row) { const permissionEditRoleInit = async function (row) {
console.log('row', row) console.log('row', row)
console.log('row.tree', row.tree) console.log('row.tree', row.tree)
let EditIds = collectIdsAll(row.tree)
console.log(EditIds);
permissionEditRoleObj.value = {} permissionEditRoleObj.value = {}
permissionEditRoleObj.value.id = row.id permissionEditRoleObj.value.id = row.id
permissionEditRoleObj.value.roleName = row.roleName permissionEditRoleObj.value.roleName = row.roleName
permissionEditRoleObj.value.market = row.market permissionEditRoleObj.value.market = row.market
permissionEditRoleObj.value.parentId = row.fatherId permissionEditRoleObj.value.parentId = row.fatherId
permissionEditRoleObj.value.parentName = row.fatherName permissionEditRoleObj.value.parentName = row.fatherName
permissionEditRoleObj.value.channel = row.channel
if (EditIds.includes(124)) {
ifHasChannel.value = true
} else {
ifHasChannel.value = false
}
try { try {
let roleId = permissionEditRoleObj.value.parentId; let roleId = permissionEditRoleObj.value.parentId;
// id // id
@ -636,9 +674,9 @@ onMounted(async function () {
</div> </div>
<div style="margin-top: 20px;display: flex;"> <div style="margin-top: 20px;display: flex;">
<el-pagination background :current-page="getRoleObj.pageNum" :page-size="getRoleObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper" :total="roleTotal" @size-change="handleRolePageSizeChange"
@current-change="handleRoleCurrentChange"></el-pagination>
<el-pagination background :current-page="getRoleObj.pageNum" :page-size="getRoleObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" :total="roleTotal"
@size-change="handleRolePageSizeChange" @current-change="handleRoleCurrentChange"></el-pagination>
</div> </div>
</el-card> </el-card>
</div> </div>
@ -686,6 +724,11 @@ onMounted(async function () {
<span style="color: #999;">暂无数据</span> <span style="color: #999;">暂无数据</span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item v-show="ifHasChannel" prop="channel" label="频道名称:" required>
<el-select v-model="addRole.channel" placeholder="请选择频道" style="width: 220px" clearable>
<el-option v-for="item in channelList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-form> </el-form>
<div> <div>
@ -729,6 +772,12 @@ onMounted(async function () {
<span style="color: #999;">暂无数据</span> <span style="color: #999;">暂无数据</span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item v-show="ifHasChannel" prop="channel" label="频道名称:" required>
<el-select v-model="permissionEditRoleObj.channel" placeholder="请选择频道" style="width: 220px" clearable>
<el-option v-for="item in channelList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-form> </el-form>
<div> <div>

Loading…
Cancel
Save