Browse Source

Merge branch 'milestone-20250711-金币前端二期' of http://39.101.133.168:8807/huangqizhen/gold-vue into zhangyong/feature-20250716164232-金币前端

zhangrenyuan/feature-20250714163943-金币前端二期
zhangyongQINGHU 3 weeks ago
parent
commit
5b7cda5880
  1. 84
      src/components/PasswordSuccess.vue
  2. 326
      src/components/changePassword.vue
  3. 28
      src/router/index.js
  4. 10
      src/views/consume/addCoinConsume.vue
  5. 131
      src/views/consume/coinConsumeDetail.vue
  6. 44
      src/views/home.vue
  7. 251
      src/views/permissions/permission.vue
  8. 49
      src/views/recharge/addCoinRecharge.vue
  9. 2
      src/views/recharge/coinRechargeDetail.vue
  10. 474
      src/views/refund/addCoinRefund.vue
  11. 4
      src/views/refund/coinRefundDetail.vue
  12. 77
      src/views/usergold/clientCountBalance.vue
  13. 24
      src/views/usergold/clientCountDetail.vue
  14. 163
      src/views/workspace/index.vue

84
src/components/PasswordSuccess.vue

@ -0,0 +1,84 @@
<template>
<div class="success-popup">
<div class="popup-content">
<div class="icon">
<el-icon :size="48" color="#67c23a">
<SuccessFilled />
</el-icon>
</div>
<div class="title">修改密码成功</div>
<div class="desc">系统将在 {{ countdown }} 秒后自动跳转至登录页</div>
<el-button type="primary" @click="immediateJump">立即跳转</el-button>
</div>
</div>
</template>
<script setup>
import {ref, onMounted} from 'vue';
import {ElIcon, ElButton} from 'element-plus';
import {SuccessFilled} from '@element-plus/icons-vue';
import {useRouter} from 'vue-router';
const countdown = ref(3);
const router = useRouter();
//
const startCountdown = () => {
const timer = setInterval(() => {
countdown.value--;
if (countdown.value === 0) {
clearInterval(timer);
//
// 使 window.location.href
// window.location.href = '/login';
router.replace ('/login');
// router.push('/login');
}
}, 1000);
};
const immediateJump = () => {
// window.location.href = '/login';
//
router.replace ('/login');
};
onMounted(() => {
startCountdown();
});
</script>
<style scoped>
.success-popup {
position: fixed;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
width: 100%;
height: 100%;
}
.popup-content {
background: #fff;
padding: 30px;
border-radius: 8px;
text-align: center;
}
.icon {
margin-bottom: 16px;
}
.title {
font-size: 18px;
font-weight: bold;
margin-bottom: 8px;
}
.desc {
margin-bottom: 24px;
color: #999;
}
</style>

326
src/components/changePassword.vue

@ -0,0 +1,326 @@
<template>
<div class="form-container">
<el-form
ref="passwdFormRef"
:model="passwd"
:rules="rules"
label-width="100px"
class="password-form"
>
<h3 class="form-title">修改密码</h3>
<!-- 原密码 -->
<el-form-item prop="oldPassword" label="原密码">
<el-input
v-model.trim="passwd.oldPassword"
type="password"
placeholder="请输入原密码"
show-password
/>
</el-form-item>
<!-- 新密码 -->
<el-form-item prop="newPassword" label="新密码">
<el-input
v-model.trim="passwd.newPassword"
type="password"
placeholder="请输入新密码"
show-password
/>
</el-form-item>
<!-- 重复密码 -->
<el-form-item prop="againPassword" label="重复密码">
<el-input
v-model.trim="passwd.againPassword"
type="password"
placeholder="请再次输入新密码"
show-password
/>
</el-form-item>
<!-- 密码规则提示 -->
<div class="rule-tips">
<div :class="isLengthValid ? 'tip pass' : 'tip neutral'">
<el-icon>
<component :is="isLengthValid ? SuccessFilled : SuccessFilled"/>
</el-icon>
密码由8-16位数字字母或符号组成
</div>
<div :class="isComplexValid ? 'tip pass' : 'tip neutral'">
<el-icon>
<component :is="isComplexValid ? SuccessFilled : SuccessFilled"/>
</el-icon>
至少含2种以上字符
</div>
<div v-if="errorMsg" class="tip fail">
<el-icon>
<CircleCloseFilled/>
</el-icon>
{{ errorMsg }}
</div>
</div>
<!-- 按钮 -->
<div class="button-group">
<el-button
type="primary"
@click="onSubmit"
style="width: 300px"
:loading="loading"
:disabled="!isLengthValid || !isComplexValid"
>
{{ loading ? '修改中...' : '确定' }}
</el-button>
</div>
</el-form>
</div>
</template>
<script setup>
import {ref, reactive, computed, watch, onMounted} from 'vue'
import {CircleCloseFilled, SuccessFilled} from '@element-plus/icons-vue'
import {ElMessage} from "element-plus";
import API from '@/util/http'
import PasswordSuccess from './PasswordSuccess.vue';
import router from "@/router/index.js";
//
const emit = defineEmits(['confirm'])
const passwdFormRef = ref(null)
const passwd = reactive({
account: '',
oldPassword: '',
newPassword: '',
againPassword: ''
})
const errorMsg = ref('')
//account
const getAccount= async function() {
try {
const adminData = ref({})
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
console.log('管理员用户信息', adminData.value)
passwd.account = adminData.value.account
} catch (error) {
console.log('请求失败', error)
}
}
//
const isLengthValid = computed(() => passwd.newPassword.length >= 8 && passwd.newPassword.length <= 16)
const isComplexValid = computed(() => {
const rules = [/\d/, /[a-z]/, /[A-Z]/, /[^a-zA-Z0-9]/]
return rules.filter((r) => r.test(passwd.newPassword)).length >= 2
})
watch(() => passwd.newPassword, (val) => {
if (val && val === passwd.oldPassword) {
errorMsg.value = '新密码不能与旧密码一致'
} else {
errorMsg.value = ''
}
})
//
const loading = ref(false)
//
const rules = reactive({
oldPassword: [{required: true, message: '请输入原密码', trigger: 'blur'}],
newPassword: [
{required: true, message: '新密码不能为空', trigger: 'blur'},
{
validator: (rule, value, callback) => {
if (value === passwd.oldPassword) {
callback(new Error('新密码不能与旧密码一致'))
} else if (value.length < 8 || value.length > 16) {
callback(new Error('长度应在 8 到 16 个字符'))
} else {
const types = [/\d/, /[a-z]/, /[A-Z]/, /[^a-zA-Z0-9]/]
const matchCount = types.filter((r) => r.test(value)).length
if (matchCount < 2) {
callback(new Error('密码至少包含两种类型(数字、字母或符号)'))
} else {
callback()
}
}
},
trigger: 'blur'
}
],
againPassword: [
{required: true, message: '请再次输入新密码', trigger: 'blur'},
{
validator: (rule, value, callback) => {
if (value !== passwd.newPassword) {
callback(new Error('两次输入密码不一致'))
} else {
callback()
}
},
trigger: 'blur'
}
]
})
//
const changePassword = async function () {
try {
const params = {
account: passwd.account,
oldPassword: passwd.oldPassword,
newPassword: passwd.newPassword,
againPassword: passwd.againPassword
}
const result = await API({url: '/admin/password', data: params})
console.log('@@@@@@@@@@@修改密码结果:', result)
if (result.code === 200) {
// 使
await router.push({ name: 'PasswordSuccess' });
// 使
// await router.push('/PasswordSuccess');
ElMessage.success('修改密码成功');
resetFields();
}else if(result.code === 400){
//
console.log('修改密码失败')
ElMessage.error('修改密码失败')
//todo
}
} catch (error) {
console.log('re:', result)
console.error('修改密码失败', error)
ElMessage.error('操作失败')
// finally
throw error
}
}
//
// const changePassword = async function () {
// try {
// // API
// const result = {
// status: 200,
// data: {success: true, message: ''}
// };
// console.log(':', result);
// //
// if (result.status === 200 ) {
// //
// ElMessage.success(result.data.message || '');
// //
// resetFields();
// router.replace ('/PasswordSuccess');
// return result;
// } else {
// // API
// const errorMsg = result.data.message || '';
// ElMessage.error(errorMsg);
// throw new Error(errorMsg);
// }
// } catch (error) {
// // API
// console.error(':', error);
// ElMessage.error(error.message || '');
// throw error;
// }
// };
//
const resetFields = () => {
passwdFormRef.value.resetFields()
errorMsg.value = ''
}
//
const onSubmit = () => {
//
if (loading.value) return
passwdFormRef.value.validate(async (valid) => {
if (valid) {
loading.value = true //
try {
await changePassword() //
emit('confirm')
} finally {
loading.value = false //
}
} else {
console.log('表单校验失败')
}
})
}
onMounted(() => {
getAccount()
})
</script>
<style scoped>
.form-container {
justify-content: center;
align-items: center;
}
.password-form {
border-radius: 8px;
}
.form-title {
text-align: left;
margin-bottom: 24px;
font-size: 20px;
font-weight: bold;
}
.button-group {
display: flex;
justify-content: center;
margin-top: 24px;
}
.rule-tips {
margin-left: 100px;
margin-bottom: 12px;
}
.tip {
font-size: 14px;
margin: 4px 0;
display: flex;
align-items: center;
}
.pass {
color: #67c23a;
}
.neutral {
color: #999;
}
.fail {
color: #f56c6c;
}
.rule-tips .el-icon {
margin-right: 6px;
}
</style>

28
src/router/index.js

@ -1,4 +1,5 @@
import { createRouter, createWebHashHistory } from 'vue-router'; import { createRouter, createWebHashHistory } from 'vue-router';
import axios from "axios";
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
@ -70,11 +71,35 @@ const router = createRouter({
// 没有权限 // 没有权限
{ path: '/noPermission', name: "noPermission", component: () => import("../views/noPermissionPage.vue") } { path: '/noPermission', name: "noPermission", component: () => import("../views/noPermissionPage.vue") }
] ]
}, },
// 跳转页面
{ path: '/PasswordSuccess', name: "PasswordSuccess", component: () => import("../components/PasswordSuccess.vue") },
] ]
}); });
// 全局拦截器 token 过期拦截
axios.interceptors.response.use(
response => response,
error => {
if (error.response && error.response.status === 401) {
// 清除本地存储的token
localStorage.removeItem('token');
// 跳转到登录页
router.push({
name: 'login',
query: { machineId: localStorage.getItem('machineId'), expired: true }
});
}
return Promise.reject(error);
}
);
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
const machineId = localStorage.getItem("machineId"); const machineId = localStorage.getItem("machineId");
@ -83,4 +108,7 @@ router.beforeEach((to, from, next) => {
} }
next(); next();
}) })
export default router; export default router;

10
src/views/consume/addCoinConsume.vue

@ -68,9 +68,9 @@ const rules = reactive({
{required: true, message: "请输入精网号", trigger: "blur"}, {required: true, message: "请输入精网号", trigger: "blur"},
// { type: 'number', message: "", trigger: "blur" } // { type: 'number', message: "", trigger: "blur" }
], ],
goodsName: [{required: true, message: "请选择消费商品", trigger: "blur"}],
goodsName: [{required: true, message: "请选择商品", trigger: "blur"}],
sumGold: [ sumGold: [
{ required: true, message: "消金币总数不能为空", trigger: "blur" },
{ required: true, message: "消金币总数不能为空", trigger: "blur" },
{ {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
// 00.10 // 00.10
@ -139,7 +139,7 @@ function validateInput() {
} }
// //
if (sumGold < 0) { if (sumGold < 0) {
ElMessage.warning("消金币总数不能为负数");
ElMessage.warning("消金币总数不能为负数");
addConsume.value.sumGold = null; addConsume.value.sumGold = null;
return false; return false;
} }
@ -184,7 +184,7 @@ function validateInput() {
// //
const totalAvailableGold = (user.value.nowSumGold) const totalAvailableGold = (user.value.nowSumGold)
if (user.value.jwcode && sumGold > totalAvailableGold) { if (user.value.jwcode && sumGold > totalAvailableGold) {
ElMessage.error("消金币总数超过可用金币总和");
ElMessage.error("消金币总数超过可用金币总和");
// sumGoldnull // sumGoldnull
addConsume.value.sumGold = null; addConsume.value.sumGold = null;
return false; return false;
@ -519,7 +519,7 @@ onMounted(async function () {
</div> </div>
<el-form-item prop="sumGold" label="消金币总数">
<el-form-item prop="sumGold" label="消金币总数">
<el-input <el-input
v-model="addConsume.sumGold" v-model="addConsume.sumGold"
style="width: 100px" style="width: 100px"

131
src/views/consume/coinConsumeDetail.vue

@ -1,6 +1,6 @@
<script setup> <script setup>
import { computed, onMounted, ref } from 'vue'
import { dayjs, ElMessage } from 'element-plus'
import {computed, onMounted, ref} from 'vue'
import {dayjs, ElMessage} from 'element-plus'
import request from '@/util/http' import request from '@/util/http'
import API from '@/util/http' import API from '@/util/http'
// //
@ -67,17 +67,21 @@ const consumePlatform = [
}, },
{ {
value: 'Homily Chart',
label: 'Homily Chart'
value: 'HomilyChart',
label: 'HomilyChart'
}, },
{ {
value: 'Homily Link',
label: 'Homily Link'
value: 'HomilyLink',
label: 'HomilyLink'
}, },
{ {
value: 'ERP', value: 'ERP',
label: 'ERP' label: 'ERP'
}
},
{
value: '其他',
label: '其他'
},
] ]
// //
@ -167,7 +171,7 @@ const ConsumeSelectBy = async function (val) {
// //
// detail.value // detail.value
const detailWithoutSort = { ...consumeUser.value }
const detailWithoutSort = {...consumeUser.value}
delete detailWithoutSort.sortField delete detailWithoutSort.sortField
delete detailWithoutSort.sortOrder delete detailWithoutSort.sortOrder
@ -271,14 +275,14 @@ const reset = function () {
const getToday = function () { const getToday = function () {
const today = new Date() const today = new Date()
const startTime = new Date( const startTime = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
today.getFullYear(),
today.getMonth(),
today.getDate()
) )
const endTime = new Date( const endTime = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
) )
getTime.value = [startTime, endTime] getTime.value = [startTime, endTime]
console.log('getTime', getTime.value) console.log('getTime', getTime.value)
@ -289,14 +293,14 @@ const getYesterday = function () {
const yesterday = new Date() const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1) yesterday.setDate(yesterday.getDate() - 1)
const startTime = new Date( const startTime = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
) )
const endTime = new Date( const endTime = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
) )
getTime.value = [startTime, endTime] getTime.value = [startTime, endTime]
console.log('getTime', getTime.value) console.log('getTime', getTime.value)
@ -306,14 +310,14 @@ const getYesterday = function () {
const get7Days = function () { const get7Days = function () {
const today = new Date() const today = new Date()
const startTime = new Date( const startTime = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
) )
const endTime = new Date( const endTime = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
) )
getTime.value = [startTime, endTime] getTime.value = [startTime, endTime]
console.log('getTime', getTime.value) console.log('getTime', getTime.value)
@ -378,18 +382,18 @@ const handleSortChange = (column) => {
} }
const exportExcel = async function () { const exportExcel = async function () {
const params = { const params = {
consumUser :{
jwcode:consumerUser.value.jwcode || '',
payPlatform:consumerUser.value.payPlatform || '',
market:consumerUser.value.market || '',
startTime:consumerUser.value.startTime || '',
endTime:consumerUser.value.endTime || '',
goodsName:consumerUser.value.goodsName || ''
consumUser: {
jwcode: consumeUser.value.jwcode || '',
payPlatform: consumeUser.value.payPlatform || '',
market: consumeUser.value.market || '',
startTime: consumeUser.value.startTime || '',
endTime: consumeUser.value.endTime || '',
goodsName: consumeUser.value.goodsName || ''
}, },
page:getObj.pageNum,
size:getObj.pageSize
page: getObj.pageNum,
size: getObj.pageSize
} }
const res = await API({ url: '/export/exportConsume', data: params })
const res = await API({url: '/export/exportConsume', data: params})
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('导出成功') ElMessage.success('导出成功')
} }
@ -439,7 +443,7 @@ onMounted(async function () {
<div class="head-card-element"> <div class="head-card-element">
<el-text size="large">精网号</el-text> <el-text size="large">精网号</el-text>
<el-input v-model="consumeUser.jwcode" placeholder="请输入精网号" size="large" style="width: 240px" <el-input v-model="consumeUser.jwcode" placeholder="请输入精网号" size="large" style="width: 240px"
clearable>
clearable>
</el-input> </el-input>
</div> </div>
</el-col> </el-col>
@ -447,26 +451,28 @@ onMounted(async function () {
<div class="head-card-element"> <div class="head-card-element">
<el-text class="mx-1" size="large">商品名称</el-text> <el-text class="mx-1" size="large">商品名称</el-text>
<el-select v-model="consumeUser.goodsName" placeholder="请选择商品名称" size="large" style="width: 180px" <el-select v-model="consumeUser.goodsName" placeholder="请选择商品名称" size="large" style="width: 180px"
clearable>
clearable>
<!-- 修改 v-for 绑定逻辑 --> <!-- 修改 v-for 绑定逻辑 -->
<el-option v-for="(item, index) in goods" :key="index" :label="item" :value="item" />
<el-option v-for="(item, index) in goods" :key="index" :label="item" :value="item"/>
</el-select> </el-select>
</div> </div>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<div class="head-card-element"> <div class="head-card-element">
<el-text class="mx-1" size="large">所属地区</el-text> <el-text class="mx-1" size="large">所属地区</el-text>
<el-select v-model="consumeUser.market" placeholder="请选择所属地区" size="large" style="width: 180px" clearable>
<el-option v-for="(item, index) in market" :key="index" :label="item" :value="item" />
<el-select v-model="consumeUser.market" placeholder="请选择所属地区" size="large" style="width: 180px"
clearable>
<el-option v-for="(item, index) in market" :key="index" :label="item" :value="item"/>
</el-select> </el-select>
</div> </div>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<div class="head-card-element"> <div class="head-card-element">
<el-text class="mx-1" size="large">消耗平台</el-text> <el-text class="mx-1" size="large">消耗平台</el-text>
<el-select v-model="consumeUser.payPlatform" placeholder="请选择消耗平台" size="large" style="width: 180px"
clearable>
<el-option v-for="item in consumePlatform" :key="item.value" :label="item.label" :value="item.value" />
<el-select v-model="consumeUser.payPlatform" placeholder="请选择消耗平台" size="large"
style="width: 180px"
clearable>
<el-option v-for="item in consumePlatform" :key="item.value" :label="item.label" :value="item.value"/>
</el-select> </el-select>
</div> </div>
</el-col> </el-col>
@ -474,9 +480,9 @@ onMounted(async function () {
<el-row> <el-row>
<el-col :span="21"> <el-col :span="21">
<div class="head-card-element"> <div class="head-card-element">
<el-text class="mx-1" size="large">时间</el-text>
<el-text class="mx-1" size="large">时间</el-text>
<el-date-picker v-model="getTime" type="datetimerange" range-separator="" start-placeholder="起始时间" <el-date-picker v-model="getTime" type="datetimerange" range-separator="" start-placeholder="起始时间"
end-placeholder="结束时间" />
end-placeholder="结束时间"/>
<el-button style="margin-left: 10px" @click="getToday()"> <el-button style="margin-left: 10px" @click="getToday()">
</el-button> </el-button>
<el-button @click="getYesterday()"></el-button> <el-button @click="getYesterday()"></el-button>
@ -506,20 +512,20 @@ onMounted(async function () {
<!-- 设置表格容器的高度和滚动样式 --> <!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 576px; overflow-y: auto"> <div style="height: 576px; overflow-y: auto">
<el-table :data="tableData" style="width: 100%" height="576px" @sort-change="handleSortChange"> <el-table :data="tableData" style="width: 100%" height="576px" @sort-change="handleSortChange">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<el-table-column type="index" label="序号" width="80px" fixed="left">
<template #default="scope"> <template #default="scope">
<span>{{ <span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 固定姓名列 --> <!-- 固定姓名列 -->
<el-table-column prop="name" label="姓名" width="150px" fixed="left" />
<el-table-column prop="name" label="姓名" width="150px" fixed="left"/>
<!-- 固定精网号列 --> <!-- 固定精网号列 -->
<el-table-column prop="jwcode" label="精网号" width="110px" fixed="left" />
<el-table-column prop="market" label="所属地区" width="110px" />
<el-table-column prop="goodsName" label="商品" width="160px" show-overflow-tooltip />
<el-table-column prop="payPlatform" label="消平台" width="120px">
<el-table-column prop="jwcode" label="精网号" width="110px" fixed="left"/>
<el-table-column prop="market" label="所属地区" width="110px"/>
<el-table-column prop="goodsName" label="商品" width="160px" show-overflow-tooltip/>
<el-table-column prop="payPlatform" label="消平台" width="120px">
<template #default="scope"> <template #default="scope">
<!-- 使用非严格相等比较 --> <!-- 使用非严格相等比较 -->
{{ scope.row.payPlatform }} {{ scope.row.payPlatform }}
@ -532,12 +538,12 @@ onMounted(async function () {
label="消费类型" label="消费类型"
width="120px" width="120px"
/> --> /> -->
<el-table-column prop="sumGold" label="消金币总数" width="120px">
<el-table-column prop="sumGold" label="消金币总数" width="120px">
<template #default="scope"> <template #default="scope">
{{ {{
(scope.row.taskGold + (scope.row.taskGold +
scope.row.freeGold +
scope.row.permanentGold) / 100
scope.row.freeGold +
scope.row.permanentGold) / 100
}} }}
</template> </template>
</el-table-column> </el-table-column>
@ -558,17 +564,18 @@ onMounted(async function () {
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="remark" label="备注" width="200px" show-overflow-tooltip />
<el-table-column prop="adminName" label="提交人" width="110px" />
<el-table-column prop="createTime" label="消时间" sortable="custom" width="180px" />
<el-table-column prop="remark" label="备注" width="200px" show-overflow-tooltip/>
<el-table-column prop="adminName" label="提交人" width="110px"/>
<el-table-column prop="createTime" label="消时间" sortable="custom" width="180px"/>
</el-table> </el-table>
</div> </div>
<!-- 分页 --> <!-- 分页 -->
<div class="pagination"> <div class="pagination">
<el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]" <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>
layout="total, sizes, prev, pager, next, jumper" :total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>

44
src/views/home.vue

@ -1,16 +1,14 @@
<script setup> <script setup>
// //
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import ElementPlus from 'element-plus'
import { VscGlobe } from 'vue-icons-plus/vsc'
import { ElMessage } from 'element-plus'
import axios from 'axios'
import {onMounted, ref} from 'vue'
import {useRouter} from 'vue-router'
import {ElMessage} from 'element-plus'
import API from '@/util/http' import API from '@/util/http'
import dmmn from '../assets/link.png' import dmmn from '../assets/link.png'
import { useRoute } from 'vue-router'
import moment from 'moment' import moment from 'moment'
import { ca } from 'element-plus/es/locales.mjs'
import ChangePassword from '@/components/changePassword.vue'
const router = useRouter() const router = useRouter()
const imgrule1 = dmmn const imgrule1 = dmmn
@ -86,7 +84,7 @@ const getTagType = (state) => {
return 'info'; return 'info';
case 1: case 1:
return 'primary'; return 'primary';
case 2:
case 2:
return'success'; return'success';
case 3: case 3:
return 'danger'; return 'danger';
@ -101,7 +99,7 @@ const getTagText = (state) => {
return '待执行'; return '待执行';
case 1: case 1:
return '执行中'; return '执行中';
case 2:
case 2:
return'执行完成'; return'执行完成';
case 3: case 3:
return '执行出错'; return '执行出错';
@ -143,12 +141,17 @@ const changeDataByArea = (item) => {
// //
const exportListVisible = ref(false) const exportListVisible = ref(false)
//
const showPasswordDialog = ref(false)
// //
const openExportList = () => { const openExportList = () => {
getExportList() getExportList()
exportListVisible.value = true exportListVisible.value = true
} }
//
const openChangePassword = () => {
showPasswordDialog.value = true
}
</script> </script>
<template> <template>
@ -259,6 +262,7 @@ const openExportList = () => {
<span style="margin-left: 10px">{{ adminData.name }}</span> <span style="margin-left: 10px">{{ adminData.name }}</span>
</template> </template>
<el-menu-item @click="message()">查看个人信息</el-menu-item> <el-menu-item @click="message()">查看个人信息</el-menu-item>
<el-menu-item @click="openChangePassword">修改密码</el-menu-item>
<el-menu-item @click="logout">退出登录</el-menu-item> <el-menu-item @click="logout">退出登录</el-menu-item>
<el-menu-item index="1-3" @click="openExportList">查看下载列表</el-menu-item> <el-menu-item index="1-3" @click="openExportList">查看下载列表</el-menu-item>
@ -272,6 +276,7 @@ const openExportList = () => {
</el-main> </el-main>
</el-container> </el-container>
</el-container> </el-container>
<!-- 查看个人信息 --> <!-- 查看个人信息 -->
<el-dialog v-model="messageVisible" title="查看个人信息" width="500px"> <el-dialog v-model="messageVisible" title="查看个人信息" width="500px">
<el-form :model="adminData"> <el-form :model="adminData">
@ -298,7 +303,7 @@ const openExportList = () => {
<!-- 导出列表弹窗 --> <!-- 导出列表弹窗 -->
<el-dialog v-model="exportListVisible" title="导出列表" width="80%"> <el-dialog v-model="exportListVisible" title="导出列表" width="80%">
<el-table :data="exportList" style="width: 100%" :loading="exportListLoading"> <el-table :data="exportList" style="width: 100%" :loading="exportListLoading">
<el-table-column prop="fileName" label="文件名" />
<el-table-column prop="fileName" label="文件名"/>
<el-table-column prop="state" label="状态"> <el-table-column prop="state" label="状态">
<template #default="scope"> <template #default="scope">
<el-tag :type="getTagType(scope.row.state)" <el-tag :type="getTagType(scope.row.state)"
@ -315,7 +320,7 @@ const openExportList = () => {
<el-table-column label="操作"> <el-table-column label="操作">
<template #default="scope"> <template #default="scope">
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)" <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
:disabled="scope.row.state !== 2">
:disabled="scope.row.state !== 2">
下载 下载
</el-button> </el-button>
</template> </template>
@ -327,6 +332,17 @@ const openExportList = () => {
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
<!-- 自定义密码修改弹窗组件 -->
<el-dialog
v-model="showPasswordDialog"
:center="true"
width="470px"
>
<ChangePassword @confirm="showPasswordDialog = false"/>
</el-dialog>
</div> </div>
</template> </template>
@ -335,10 +351,12 @@ const openExportList = () => {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
} }
.item { .item {
margin-top: 20px; margin-top: 20px;
margin-right: 40px; margin-right: 40px;
} }
.admin { .admin {
margin-left: auto; margin-left: auto;
} }

251
src/views/permissions/permission.vue

@ -1,10 +1,7 @@
<script setup> <script setup>
import { ref, onMounted, reactive, computed, watch } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import moment from 'moment'
import { UserFilled } from '@element-plus/icons-vue'
import {onMounted, ref} from 'vue'
import {ElMessage} from 'element-plus'
import {InfoFilled, UserFilled} from '@element-plus/icons-vue'
import _ from 'lodash' import _ from 'lodash'
import request from '@/util/http' import request from '@/util/http'
import API from '@/util/http' import API from '@/util/http'
@ -372,15 +369,59 @@ const editStatus = async function (row) {
}) })
console.log('请求成功2', result) console.log('请求成功2', result)
ElMessage.success( ElMessage.success(
permissionEditObj.value.adminStatus == 1 ? '启用成功' : '禁用成功'
permissionEditObj.value.adminStatus == 1 ? '启用成功' : '禁用成功'
) )
permissionEditObj.value = {} permissionEditObj.value = {}
get() get()
} catch (error) { } catch (error) {
console.log('修改用户权限失败', error) console.log('修改用户权限失败', error)
//
} }
} }
//
const resetConfirmVisible = ref(false)
//
const currentRow = ref(null)
//
const resetPassword = function (row) {
//
currentRow.value = row
resetConfirmVisible.value = true
}
//
const confirmResetPassword = async function () {
const params = {
account: currentRow.value.account,
}
console.log(params)
//
try {
const result = await request({
url: '/admin/reset',
method: 'post',
data: params // params
})
if (result.code === 200) { // 使
ElMessage.success('重置密码成功')
resetConfirmVisible.value = false //
} else {
ElMessage.error(result.message || '重置密码失败')
}
} catch (error) {
ElMessage.error('重置密码失败')
console.error('请求错误:', error)
}
}
//
const cancelResetPassword = function () {
resetConfirmVisible.value = false
}
// //
onMounted(async function () { onMounted(async function () {
await get() await get()
@ -551,18 +592,18 @@ const handleCheckChange = (checkedNodes, { checkedKeys }) => {
<div class="head-card"> <div class="head-card">
<div class="head-card-element"> <div class="head-card-element">
<el-text class="mx-1" size="large">OA号</el-text> <el-text class="mx-1" size="large">OA号</el-text>
<el-input v-model="admin.account" style="width: 240px" placeholder="请输入OA号" clearable />
<el-input v-model="admin.account" style="width: 240px" placeholder="请输入OA号" clearable/>
</div> </div>
<div class="head-card-element" style="margin-left: 50px"> <div class="head-card-element" style="margin-left: 50px">
<el-text class="mx-1" size="large">所属地区</el-text> <el-text class="mx-1" size="large">所属地区</el-text>
<el-select v-model="admin.market" placeholder="请选择所属地区" style="width: 240px" clearable> <el-select v-model="admin.market" placeholder="请选择所属地区" style="width: 240px" clearable>
<el-option v-for="item in market" :key="item" :label="item" :value="item" />
<el-option v-for="item in market" :key="item" :label="item" :value="item"/>
</el-select> </el-select>
</div> </div>
<div class="head-card-element" style="margin-left: 50px"> <div class="head-card-element" style="margin-left: 50px">
<el-text class="mx-1" size="large">职位名称</el-text> <el-text class="mx-1" size="large">职位名称</el-text>
<el-select v-model="admin.postiton" placeholder="请选择职位名称" style="width: 240px" clearable> <el-select v-model="admin.postiton" placeholder="请选择职位名称" style="width: 240px" clearable>
<el-option v-for="item in postiton" :key="item" :label="item" :value="item" />
<el-option v-for="item in postiton" :key="item" :label="item" :value="item"/>
</el-select> </el-select>
</div> </div>
@ -585,26 +626,35 @@ const handleCheckChange = (checkedNodes, { checkedKeys }) => {
</div> </div>
<div> <div>
<el-table :data="tableData" style="width: 100%" show-overflow-tooltip>
<el-table :data="tableData" style="width: 100% ">
<el-table-column type="index" label="序号" width="100px" fixed="left"> <el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope"> <template #default="scope">
<span>{{ <span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="account" label="OA号" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="market" label="所属地区" />
<el-table-column prop="postiton" label="职位" />
<el-table-column prop="account" label="OA号"/>
<el-table-column prop="name" label="姓名"/>
<el-table-column prop="market" label="所属地区"/>
<el-table-column prop="postiton" label="职位"/>
<el-table-column prop="roleName" label="部门权限"> <el-table-column prop="roleName" label="部门权限">
</el-table-column> </el-table-column>
<el-table-column prop="remark" label="备注" />
<el-table-column prop="operation" label="操作" width="200px">
<el-table-column prop="remark" label="备注"/>
<el-table-column prop="operation" label="操作" width="300px" align="center">
<template #default="scope"> <template #default="scope">
<el-button
type="warning"
text
@click="resetPassword(scope.row)"
:disabled="scope.row.adminStatus === 0"
>
重置密码
</el-button>
<el-button type="warning" text @click="permissionEditInit(scope.row)" <el-button type="warning" text @click="permissionEditInit(scope.row)"
:disabled="scope.row.adminStatus === 0">
:disabled="scope.row.adminStatus === 0">
修改权限 修改权限
</el-button> </el-button>
<el-popconfirm title="确定将此用户删除吗?" @confirm="delConfirm"> <el-popconfirm title="确定将此用户删除吗?" @confirm="delConfirm">
@ -625,10 +675,10 @@ const handleCheckChange = (checkedNodes, { checkedKeys }) => {
<el-table-column prop="adminStatus" label="状态"> <el-table-column prop="adminStatus" label="状态">
<template #default="scope"> <template #default="scope">
<el-switch v-model="scope.row.adminStatus" :active-value="1" :inactive-value="0" size="large" <el-switch v-model="scope.row.adminStatus" :active-value="1" :inactive-value="0" size="large"
@change="editStatus(scope.row)" style="
@change="editStatus(scope.row)" style="
--el-switch-on-color: #13ce66; --el-switch-on-color: #13ce66;
--el-switch-off-color: #ff4949; --el-switch-off-color: #ff4949;
" active-text="启用" inactive-text="禁用" inline-prompt />
" active-text="启用" inactive-text="禁用" inline-prompt/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -637,8 +687,9 @@ const handleCheckChange = (checkedNodes, { checkedKeys }) => {
<!-- 分页 --> <!-- 分页 -->
<div class="pagination" style="margin-top: 20px"> <div class="pagination" style="margin-top: 20px">
<el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]" <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>
layout="total, sizes, prev, pager, next, jumper" :total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
@ -649,43 +700,45 @@ const handleCheckChange = (checkedNodes, { checkedKeys }) => {
<!-- 居中显示 --> <!-- 居中显示 -->
<el-form ref="Ref" :model="addAdmin" label-width="auto" style="max-width: 600px; align-items: center"> <el-form ref="Ref" :model="addAdmin" label-width="auto" style="max-width: 600px; align-items: center">
<el-form-item prop="account" label="OA号:" required clearable>
<el-input v-model="addAdmin.account" placeholder="请输入OA号" style="width: 220px" />
<el-form-item prop="account" label="OA号:" required>
<el-input v-model="addAdmin.account" placeholder="请输入OA号" style="width: 220px"/>
</el-form-item> </el-form-item>
<el-form-item prop="name" label="用户名:" required clearable>
<el-input v-model="addAdmin.name" placeholder="请输入用户名" style="width: 220px" />
<el-form-item prop="name" label="用户名:" required>
<el-input v-model="addAdmin.name" placeholder="请输入用户名" style="width: 220px"/>
</el-form-item> </el-form-item>
<el-form-item prop="market" label="所属地区:" required clearable>
<el-select multiple v-model="addAdmin.market" placeholder="请选择所属地区" style="width: 440px" clearable>
<el-option v-for="item in market" :key="item" :label="item" :value="item" :disabled="includeHq(item)" />
<el-form-item prop="market" label="所属地区:" required>
<el-select v-model="addAdmin.market" placeholder="请选择所属地区" style="width: 220px"
@change="() => Ref.value.validateField('market')">
<el-option v-for="item in market" :key="item" :label="item" :value="item"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item prop="permission" label="角色名称:" required>
<el-select v-model="addAdmin.permission" placeholder="请选择角色名称" style="width: 220px" clearable>
<el-form-item prop="permission" label="权限类别:" required>
<el-select v-model="addAdmin.permission" placeholder="请选择权限" style="width: 220px"
@change="() => Ref.value.validateField('permission')">
<el-option v-for="item in permissionList" :key="item.value" :label="item.label" <el-option v-for="item in permissionList" :key="item.value" :label="item.label"
:value="item.value"></el-option>
:value="item.value"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item prop="postiton" label="职位:" required> <el-form-item prop="postiton" label="职位:" required>
<el-input v-model="addAdmin.postiton" placeholder="请输入职" style="width: 220px" clearable />
<el-input v-model="addAdmin.postiton" placeholder="请输入职" style="width: 220px"/>
</el-form-item> </el-form-item>
<el-form-item prop="machineId" label="机器码:" required> <el-form-item prop="machineId" label="机器码:" required>
<div style="display: flex; align-items: center; flex-wrap: wrap;"> <div style="display: flex; align-items: center; flex-wrap: wrap;">
<el-input v-model="addAdmin.machineId" placeholder="请输入机器码" style="width: 220px; margin-right: 10px;"
clearable />
<el-input v-model="addAdmin.machineId" placeholder="请输入机器码"
style="width: 220px; margin-right: 10px;"/>
<el-button type="primary" @click="addMachineIdInput">添加</el-button> <el-button type="primary" @click="addMachineIdInput">添加</el-button>
<!-- 动态添加的机器码输入框 --> <!-- 动态添加的机器码输入框 -->
<div v-for="(item, index) in addAdmin.machineIds" :key="index" style="margin-left: 10px;"> <div v-for="(item, index) in addAdmin.machineIds" :key="index" style="margin-left: 10px;">
<el-input v-model="addAdmin.machineIds[index]" placeholder="请输入机器码" <el-input v-model="addAdmin.machineIds[index]" placeholder="请输入机器码"
style="width: 180px; margin-right: 10px;" />
style="width: 180px; margin-right: 10px;"/>
</div> </div>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item prop="remark" label="备注"> <el-form-item prop="remark" label="备注">
<el-input v-model="addAdmin.remark" style="width: 300px" :rows="2" maxlength="100" show-word-limit <el-input v-model="addAdmin.remark" style="width: 300px" :rows="2" maxlength="100" show-word-limit
type="textarea" />
type="textarea"/>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -699,25 +752,59 @@ const handleCheckChange = (checkedNodes, { checkedKeys }) => {
</el-dialog> </el-dialog>
<!-- 这是编辑用户权限弹窗 --> <!-- 这是编辑用户权限弹窗 -->
<el-dialog v-model="userEditVisible" title="编辑用户权限" width="800px" :close-on-click-modal="false">
<el-form ref="Ref" :model="permissionEditObj" label-width="auto" style="max-width: 600px; align-items: center">
<el-form-item prop="userName" label="用户名称:" required>
<el-input v-model="permissionEditObj.userName" placeholder="请输入用户名" style="width: 220px" />
</el-form-item>
<el-form-item prop="roleName" label="角色名称:" required>
<el-input v-model="permissionEditObj.roleName" placeholder="请输入用户名" style="width: 220px" />
</el-form-item>
<el-form-item prop="parentName" label="上级角色:" required>
<el-select v-model="permissionEditObj.parentName" placeholder="请选择上级角色" style="width: 220px">
<el-option v-for="item in permissionList" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="permissionSelect" label="权限列表:" required>
<el-tree multiple v-model="permissionEditObj.permissionSelect" :data="data" :render-after-expand="false"
show-checkbox style="width: 700px" />
</el-form-item>
</el-form>
<el-dialog v-model="permissionEditVisible" title="编辑用户权限" width="800px" :close-on-click-modal="false">
<el-descriptions class="margin-top" :column="2" border label-width="200px">
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<UserFilled/>
</el-icon>
员工OA号
</div>
</template>
{{ permissionEditObj.account }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<User/>
</el-icon>
员工姓名
</div>
</template>
{{ permissionEditObj.name }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<location/>
</el-icon>
所属地区
</div>
</template>
{{ permissionEditObj.market }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<OfficeBuilding/>
</el-icon>
部门
</div>
</template>
{{ permissionEditObj.postiton }}
</el-descriptions-item>
</el-descriptions>
<el-divider>
<el-icon>
<star-filled/>
</el-icon>
</el-divider>
<div> <div>
</div> </div>
<template #footer> <template #footer>
@ -730,38 +817,34 @@ const handleCheckChange = (checkedNodes, { checkedKeys }) => {
</template> </template>
</el-dialog> </el-dialog>
<!-- 新增角色 -->
<el-dialog v-model="permissionAddVisible" title="新增角色" width="800px" :close-on-click-modal="false">
<!-- 重置密码确认弹窗 -->
<el-dialog
v-model="resetConfirmVisible" width="500px" :close-on-click-modal="false" :before-close="cancelResetPassword"
>
<el-row>
<el-col :span="4" style="margin-top: 20px">
<el-icon class="dialog-icon" color="#10AEFF" size="50">
<InfoFilled/>
</el-icon>
</el-col>
<el-col :span="20">
<h3>提示</h3>
<p class="dialog-title">确认重置该账号密码</p>
<p class="dialog-desc">重置后密码为: 123456请通知用户及时修改</p>
</el-col>
</el-row>
<template #footer> <template #footer>
<el-form ref="Ref" :model="addRole" label-width="auto" style="max-width: 600px; align-items: center">
<el-form-item prop="roleName" label="角色名称:" required>
<el-input v-model="addRole.roleName" placeholder="请输入用户名" style="width: 220px" />
</el-form-item>
<el-form-item prop="parentName" label="上级角色:">
<el-select v-model="addRole.parentName" placeholder="请选择上级角色" style="width: 220px" clearable>
<el-option v-for="item in permissionList" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="checkedKeys" label="权限列表:" required>
<el-tree :data="filteredData" show-checkbox node-key="value" :props="{ label: 'label', children: 'children' }"
:checked-keys="addRole.checkedKeys" @check="handleCheckChange" />
</el-form-item>
<el-form-item prop="grade" label="优先级:" required>
<el-input v-model="addRole.grade" placeholder="数字1~999" style="width: 220px" />
</el-form-item>
</el-form>
<div>
<el-button @click="closePermissionAddVisible()">取消</el-button>
<el-button type="primary" @click="handleAddRole">
提交
</el-button>
<div style="align-content: center ; gap: 30px">
<el-button @click="cancelResetPassword">取消</el-button>
<el-button type="primary" @click="confirmResetPassword">确定</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<style scoped> <style scoped>
.pagination { .pagination {
display: flex; display: flex;

49
src/views/recharge/addCoinRecharge.vue

@ -132,6 +132,19 @@ const add = async function () {
const addBefore = () => { const addBefore = () => {
Ref.value.validate(async (valid) => { Ref.value.validate(async (valid) => {
if (valid) { if (valid) {
//
try {
await getUser(recharge.value.jwcode);
if (!user.value.jwcode) {
ElMessage.error('请先验证有效的精网号');
return;
}
} catch (error) {
ElMessage.error('精网号验证失败');
return;
}
if (recharge.value.rateName == null || recharge.value.rateName == '' || recharge.value.rateName == undefined) { if (recharge.value.rateName == null || recharge.value.rateName == '' || recharge.value.rateName == undefined) {
ElMessage({ ElMessage({
type: 'error', type: 'error',
@ -173,9 +186,20 @@ const addBefore = () => {
// //
const Ref = ref(null) const Ref = ref(null)
const validateJwCode = (rule, value, callback) => {
if (!value) {
callback(new Error('精网号不能为空'));
return;
}
if (/[^0-9]/.test(value)) {
callback(new Error('精网号只能包含数字'));
return;
}
callback();
};
const rules = reactive({ const rules = reactive({
jwcode: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
jwcode: [{ required: true, validator: validateJwCode, trigger: 'blur' }],
activity: [{ required: true, message: '请选择活动名称', trigger: 'blur' }], activity: [{ required: true, message: '请选择活动名称', trigger: 'blur' }],
permanentGold: [ permanentGold: [
{ required: true, message: '请输入永久金币数', trigger: 'blur' }, { required: true, message: '请输入永久金币数', trigger: 'blur' },
@ -206,8 +230,8 @@ const rules = reactive({
const numValue = Number(value); const numValue = Number(value);
if (isNaN(numValue)) { if (isNaN(numValue)) {
callback(new Error('请输入有效的数字')); callback(new Error('请输入有效的数字'));
} else if (numValue <= 0) {
callback(new Error('输入金额必须大于0'));
} else if (numValue < 0) {
callback(new Error('输入金额不能小于0'));
} else { } else {
callback(); callback();
} }
@ -288,8 +312,8 @@ const rules = reactive({
const numValue = Number(value); const numValue = Number(value);
if (isNaN(numValue)) { if (isNaN(numValue)) {
callback(new Error('请输入有效的数字')); callback(new Error('请输入有效的数字'));
} else if (numValue <= 0) {
callback(new Error('输入金额必须大于0'));
} else if (numValue < 0) {
callback(new Error('输入金额不能小于0'));
} else { } else {
callback(); callback();
} }
@ -307,30 +331,27 @@ const getUser = async function (jwcode) {
trimJwCode(); trimJwCode();
try { try {
// POST
const result = await API({ const result = await API({
url: '/user/selectUser', url: '/user/selectUser',
data: { data: {
jwcode: recharge.value.jwcode jwcode: recharge.value.jwcode
} }
}) })
console.log('请求成功', result)
if (result.code === 0) { if (result.code === 0) {
ElMessage.error(result.msg); ElMessage.error(result.msg);
} else if (result.data === null) { } else if (result.data === null) {
ElMessage.error("用户不存在"); ElMessage.error("用户不存在");
recharge.value.jwcode = ''
} else { } else {
user.value = result.data; user.value = result.data;
console.log("用户信息", user.value); console.log("用户信息", user.value);
ElMessage.success(result.msg);
ElMessage.success("查询成功");
} }
} catch (error) { } catch (error) {
console.log("请求失败", error); console.log("请求失败", error);
ElMessage.error("精网号错误"); ElMessage.error("精网号错误");
recharge.value.jwcode = ''
} }
} }
@ -480,7 +501,7 @@ const payModel = [
function handleActivityChange(value) { function handleActivityChange(value) {
// //
console.log('选中的值:', value) console.log('选中的值:', value)
getActivityById(value)
// getActivityById(value)
console.log('看看', recharge.value) console.log('看看', recharge.value)
} }
@ -505,7 +526,7 @@ const deleteRecharge = function () {
onMounted(async function () { onMounted(async function () {
await getAdminData() await getAdminData()
// await getCurrency() // await getCurrency()
await getActivity()//
// await getActivity()//
}) })
onMounted(() => { onMounted(() => {
@ -525,10 +546,10 @@ onMounted(() => {
class="add-form" class="add-form"
> >
<el-form-item prop="jwcode" label="精网号"> <el-form-item prop="jwcode" label="精网号">
<el-input v-model="recharge.jwcode" style="width: 220px" @blur="getUser(recharge.jwcode)" />
<el-input v-model="recharge.jwcode" style="width: 220px" />
<el-button <el-button
type="primary" type="primary"
@click="getUser(recharge.jwcode)"
style="margin-left: 20px" style="margin-left: 20px"
>查询</el-button >查询</el-button

2
src/views/recharge/coinRechargeDetail.vue

@ -444,7 +444,7 @@ const handleSortChange = (column) => {
}}</span> }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column fixed="left" prop="name" label="姓名" width="80px" />
<el-table-column fixed="left" prop="name" label="姓名" width="150px" />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="110px" /> <el-table-column fixed="left" prop="jwcode" label="精网号" width="110px" />
<el-table-column prop="market" label="所属地区" width="100px" /> <el-table-column prop="market" label="所属地区" width="100px" />
<el-table-column prop="activity" label="活动名称" width="110px" show-overflow-tooltip/> <el-table-column prop="activity" label="活动名称" width="110px" show-overflow-tooltip/>

474
src/views/refund/addCoinRefund.vue

@ -1,11 +1,11 @@
<script setup> <script setup>
import { onMounted, reactive } from 'vue'
import { ref, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import {onMounted, reactive} from 'vue'
import {ref, computed, watch} from 'vue'
import {ElMessage} from 'element-plus'
import {Plus} from '@element-plus/icons-vue'
import axios from 'axios' import axios from 'axios'
import { ElMessageBox } from 'element-plus'
import {ElMessageBox} from 'element-plus'
import API from '@/util/http' import API from '@/util/http'
import moment from 'moment' import moment from 'moment'
// import _ from 'lodash' // import _ from 'lodash'
@ -15,12 +15,11 @@ const addRe = ref({
}) })
// //
const adminData = ref({}) const adminData = ref({})
const getAdminData = async function () { const getAdminData = async function () {
try { try {
const result = await API({ url: '/admin/userinfo', data: {} })
const result = await API({url: '/admin/userinfo', data: {}})
adminData.value = result adminData.value = result
addRefund.value.adminId = adminData.value.id addRefund.value.adminId = adminData.value.id
console.log('请求成功', result) console.log('请求成功', result)
@ -85,8 +84,9 @@ const add = async function () {
} }
// POST // POST
const result = await API({ url: '/refund/add',
data: processedRefund
const result = await API({
url: '/refund/add',
data: processedRefund
}) })
if (result.code === 0) { if (result.code === 0) {
ElMessage.error(result.msg) ElMessage.error(result.msg)
@ -106,14 +106,26 @@ const add = async function () {
const addBefore = () => { const addBefore = () => {
Ref.value.validate(async (valid) => { Ref.value.validate(async (valid) => {
if (valid) { if (valid) {
try {
await getUser(addRefund.value.jwcode);
if (!user.value.jwcode) {
ElMessage.error('请先验证有效的精网号');
return;
}
} catch (error) {
ElMessage.error('精网号验证失败');
return;
}
ElMessageBox.confirm('确认添加?') ElMessageBox.confirm('确认添加?')
.then(() => {
add()
console.log('添加成功')
})
.catch(() => {
console.log('取消添加')
})
.then(() => {
add()
console.log('添加成功')
})
.catch(() => {
console.log('取消添加')
})
} else { } else {
// //
ElMessage({ ElMessage({
@ -127,19 +139,30 @@ const addBefore = () => {
// //
// //
const Ref = ref(null) const Ref = ref(null)
const startChange = (val) => {}
const startChange = (val) => {
}
const validateJwCode = (rule, value, callback) => {
if (!value) {
callback(new Error('精网号不能为空'));
return;
}
if (/[^0-9]/.test(value)) {
callback(new Error('精网号只能包含数字'));
return;
}
callback();
};
const rules = reactive({ const rules = reactive({
jwcode: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
refundType: [{ required: true, message: '请选择退款类型', trigger: 'blur' }],
goodsName: [{ required: true, message: '请选择退款商品', trigger: 'blur' }],
taskGold: [{ required: true, message: '请输入任务金币', trigger: 'blur' }],
freeGold: [{ required: true, message: '请输入免费金币', trigger: 'blur' }],
jwcode: [{required: true, validator: validateJwCode, trigger: 'blur'}],
refundType: [{required: true, message: '请选择退款类型', trigger: 'blur'}],
goodsName: [{required: true, message: '请选择退款商品', trigger: 'blur'}],
taskGold: [{required: true, message: '请输入任务金币', trigger: 'blur'}],
freeGold: [{required: true, message: '请输入免费金币', trigger: 'blur'}],
permanentGold: [ permanentGold: [
{ required: true, message: '请输入永久金币', trigger: 'blur' }
{required: true, message: '请输入永久金币', trigger: 'blur'}
], ],
sumGold: [ sumGold: [
{ required: true, message: '请选择付款方式', trigger: 'blur' },
{required: true, message: '请选择付款方式', trigger: 'blur'},
{ {
validator: (rule, value) => { validator: (rule, value) => {
if (value === 0) { if (value === 0) {
@ -176,7 +199,7 @@ const user = ref({
}) })
const getUser = async function (jwcode) { const getUser = async function (jwcode) {
trimJwCode(); trimJwCode();
cancelExceptJwcode();
// cancelExceptJwcode();
try { try {
// POST // POST
const result = await API({ const result = await API({
@ -192,7 +215,6 @@ const getUser = async function (jwcode) {
ElMessage.error(result.msg); ElMessage.error(result.msg);
} else if (result.data === null) { } else if (result.data === null) {
ElMessage.error("用户不存在"); ElMessage.error("用户不存在");
addRefund.value.jwcode = ''; //
} else { } else {
// 100 // 100
const processedData = { const processedData = {
@ -209,17 +231,14 @@ const getUser = async function (jwcode) {
} }
} catch (error) { } catch (error) {
console.log("请求失败", error); console.log("请求失败", error);
ElMessage.error("查询失败,请检查精网号是否正确");
addRefund.value.jwcode = ''; //
ElMessage.error("精网号错误");
} }
} }
// 退退 // 退退
const refundType = ref([{ value: '商品退款', label: '商品退款' }]);
const refundType = ref([{value: '商品退款', label: '商品退款'}]);
// 退 // 退
// const getRefundTypes = async function () { // const getRefundTypes = async function () {
@ -244,8 +263,6 @@ const refundType = ref([{ value: '商品退款', label: '商品退款' }]);
// } // }
// //
const goodsName = ref([]) const goodsName = ref([])
const getGoods = async function (jwcode) { const getGoods = async function (jwcode) {
@ -296,7 +313,7 @@ const selectedGoodsGold = ref({
}) })
// 退退退退 // 退退退退
const handleRefundModelChange = () =>{
const handleRefundModelChange = () => {
if (addRe.value.typeR === '0') { if (addRe.value.typeR === '0') {
// 退 // 退
addRefund.value.permanentGold = selectedGoodsGold.value.permanentGold; addRefund.value.permanentGold = selectedGoodsGold.value.permanentGold;
@ -403,213 +420,214 @@ onMounted(async function () {
</script> </script>
<template> <template>
<div >
<el-form
:model="addRefund"
ref="Ref"
:rules="rules"
label-width="auto"
style="max-width: 750px"
class="form-style"
>
<el-form-item prop="jwcode" label="精网号">
<el-input
v-model="addRefund.jwcode"
style="width: 220px"
@change="getGoods(addRefund.jwcode)"
@blur="getUser(addRefund.jwcode)"
/>
<el-button
type="primary"
style="margin-left: 20px"
>查询</el-button
>
</el-form-item>
<el-form-item prop="refundType" label="退款类型">
<el-select
v-model="addRefund.refundType"
placeholder="请选择"
style="width: 300px"
>
<el-option
v-for="item in refundType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item prop="goodsName" label="商品名">
<el-select
v-model="addRefund.goodsName"
placeholder="请选择"
style="width: 300px"
@change="handleSelectionChange"
>
<el-option
v-for="item in goodsName"
:key="item.key"
:label="item.label"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item prop="refundModel" label="退款方式:">
<el-radio-group v-model="addRe.typeR" @change="handleRefundModelChange">
<el-radio value="0">全部退款</el-radio>
<el-radio value="1">部分退款</el-radio>
</el-radio-group>
</el-form-item>
<div style="display: flex; align-items: center">
<el-form-item prop="permanentGold" label="永久金币" style="float: left">
<div>
<el-form
:model="addRefund"
ref="Ref"
:rules="rules"
label-width="auto"
style="max-width: 750px"
class="form-style"
>
<el-form-item prop="jwcode" label="精网号">
<el-input <el-input
v-model="addRefund.permanentGold"
style="width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
@input="handlePermanentGoldInput($event)"
type="number"
v-model="addRefund.jwcode"
style="width: 220px"
@change="getGoods(addRefund.jwcode)"
/>
<el-button
type="primary"
@click="getUser(addRefund.jwcode)"
style="margin-left: 20px"
>查询
</el-button
> >
</el-form-item>
<el-form-item prop="refundType" label="退款类型">
<el-select
v-model="addRefund.refundType"
placeholder="请选择"
style="width: 300px"
>
<el-option
v-for="item in refundType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item prop="goodsName" label="商品名">
<el-select
v-model="addRefund.goodsName"
placeholder="请选择"
style="width: 300px"
@change="handleSelectionChange"
>
<el-option
v-for="item in goodsName"
:key="item.key"
:label="item.label"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item prop="refundModel" label="退款方式:">
<el-radio-group v-model="addRe.typeR" @change="handleRefundModelChange">
<el-radio value="0">全部退款</el-radio>
<el-radio value="1">部分退款</el-radio>
</el-radio-group>
</el-form-item>
<div style="display: flex; align-items: center">
<el-form-item prop="permanentGold" label="永久金币" style="float: left">
<el-input
v-model="addRefund.permanentGold"
style="width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
@input="handlePermanentGoldInput($event)"
type="number"
>
</el-input>
<p></p>
</el-form-item>
<el-form-item
prop="freeGold"
label="免费金币"
style="margin-left: -20px; float: left"
>
<el-input
v-model="addRefund.freeGold"
style="float: left; width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
@input="handleFreeGoldInput($event)"
type="number"
/>
<p></p>
</el-form-item>
<el-form-item prop="taskGold" label="任务金币" style="margin-left: -20px">
<el-input
v-model="addRefund.taskGold"
style="float: left; width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
@input="handleTaskGoldInput($event)"
type="number"
/>
<p></p>
</el-form-item>
</div>
<el-form-item prop="sumGold" label="退款金币总数">
<el-input disabled v-model="addRefund.sumGold" style="width: 100px">
</el-input> </el-input>
<p></p>
</el-form-item> </el-form-item>
<el-form-item
prop="freeGold"
label="免费金币"
style="margin-left: -20px; float: left"
>
<el-form-item prop="remark" label="备注">
<el-input <el-input
v-model="addRefund.freeGold"
style="float: left; width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
@input="handleFreeGoldInput($event)"
type="number"
v-model="addRefund.remark"
style="width: 300px"
:rows="2"
maxlength="100"
show-word-limit
type="textarea"
/> />
<p></p>
</el-form-item> </el-form-item>
<el-form-item prop="taskGold" label="任务金币" style="margin-left: -20px">
<el-form-item prop="adminName" label="提交人">
<el-input <el-input
v-model="addRefund.taskGold"
style="float: left; width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
@input="handleTaskGoldInput($event)"
type="number"
style="width: 300px"
:value="adminData.adminName"
disabled
placeholder="提交人姓名"
/> />
<p></p>
</el-form-item> </el-form-item>
</div>
<el-form-item prop="sumGold" label="退款金币总数">
<el-input disabled v-model="addRefund.sumGold" style="width: 100px">
</el-input>
</el-form-item>
<el-form-item prop="remark" label="备注">
<el-input
v-model="addRefund.remark"
style="width: 300px"
:rows="2"
maxlength="100"
show-word-limit
type="textarea"
/>
</el-form-item>
<el-form-item prop="adminName" label="提交人">
<el-input
style="width: 300px"
:value="adminData.adminName"
disabled
placeholder="提交人姓名"
/>
</el-form-item>
<el-button type="success" @click="cancel()" style="margin-left: 280px">重置</el-button>
<el-button type="primary" @click="addBefore"> 提交 </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="历史金币总数">
<p v-if="!isNaN(Number(user.historySumGold))">
{{ Number(user.historySumGold) }}
</p>
</el-form-item>
</el-col>
</el-row>
<!-- 第二行精网号 + 当前金币独立行 -->
<el-row>
<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">
<el-button type="success" @click="cancel()" style="margin-left: 280px">重置</el-button>
<el-button type="primary" @click="addBefore"> 提交</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="历史金币总数">
<p v-if="!isNaN(Number(user.historySumGold))">
{{ Number(user.historySumGold) }}
</p>
</el-form-item>
</el-col>
</el-row>
<!-- 第二行精网号 + 当前金币独立行 -->
<el-row>
<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 <span
style="color: #2fa1ff; margin-right: 5px"
v-if="user.nowSumGold !== undefined"
style="color: #2fa1ff; margin-right: 5px"
v-if="user.nowSumGold !== undefined"
>{{ user.nowSumGold }}</span> >{{ user.nowSumGold }}</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 }};
</el-form-item>
<!-- 金币详情独立显示 -->
<el-form-item style="margin-top: -23px"> <!-- 负边距减少间距 -->
<span
style="color: #b1b1b1; margin-left: 0px"
v-if="user.nowPermanentGold !== undefined"
>(永久金币:{{ user.nowPermanentGold }};
免费金币:{{ user.nowFreeGold }}; 免费金币:{{ user.nowFreeGold }};
任务金币:{{ user.nowTaskGold }})</span> 任务金币:{{ user.nowTaskGold }})</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>
</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> </div>
</template> </template>

4
src/views/refund/coinRefundDetail.vue

@ -512,7 +512,7 @@ const handleCurrentChange = function (val) {
<el-table-column <el-table-column
type="index" type="index"
label="序号" label="序号"
width="100px"
width="80px"
fixed="left" fixed="left"
> >
<template #default="scope"> <template #default="scope">
@ -526,7 +526,7 @@ const handleCurrentChange = function (val) {
prop="name" prop="name"
label="姓名" label="姓名"
fixed="left" fixed="left"
width="100px"
width="130px"
/> />
<el-table-column <el-table-column
prop="jwcode" prop="jwcode"

77
src/views/usergold/clientCountBalance.vue

@ -1,11 +1,11 @@
<script setup> <script setup>
// //
import { ref, onMounted, reactive, computed } from 'vue'
import {ref, onMounted, reactive, computed} from 'vue'
import ElementPlus from 'element-plus' import ElementPlus from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import {ElMessage, ElMessageBox} from 'element-plus'
import axios from 'axios' import axios from 'axios'
import moment from 'moment' import moment from 'moment'
import { ta } from 'element-plus/es/locales.mjs'
import {ta} from 'element-plus/es/locales.mjs'
import API from '@/util/http' import API from '@/util/http'
// //
@ -14,7 +14,7 @@ const adminData = ref({})
const dialogVisible = ref(false) const dialogVisible = ref(false)
const getAdminData = async function () { const getAdminData = async function () {
try { try {
const result = await API({ url: '/admin/userinfo', data: {} })
const result = await API({url: '/admin/userinfo', data: {}})
adminData.value = result adminData.value = result
// console.log('', result) // console.log('', result)
console.log('管理员用户信息', adminData.value) console.log('管理员用户信息', adminData.value)
@ -35,7 +35,7 @@ const getmarket = async () => {
console.log('获取地区数据成功', result) console.log('获取地区数据成功', result)
// { value, label } // { value, label }
if (Array.isArray(result.data) && typeof result.data[0] === 'string') { if (Array.isArray(result.data) && typeof result.data[0] === 'string') {
market.value = result.data.map(item => ({ value: item, label: item }));
market.value = result.data.map(item => ({value: item, label: item}));
} else { } else {
market.value = result.data; market.value = result.data;
} }
@ -104,7 +104,7 @@ const get = async function (val) {
// POST // POST
const requestData = { ...getObj.value, user: { ...user.value } };//
const requestData = {...getObj.value, user: {...user.value}};//
console.log('最终请求参数', JSON.stringify(requestData, null, 2)); // console.log('最终请求参数', JSON.stringify(requestData, null, 2)); //
//console.log('', requestData); //console.log('', requestData);
@ -112,7 +112,7 @@ const get = async function (val) {
const result = await API({ const result = await API({
url: '/goldDetail/getGold', url: '/goldDetail/getGold',
method: 'post', method: 'post',
data: { ...getObj.value, user: { ...user.value } }
data: {...getObj.value, user: {...user.value}}
}) })
console.log('响应数据', result) console.log('响应数据', result)
tableData.value = result.data.list tableData.value = result.data.list
@ -124,7 +124,7 @@ const get = async function (val) {
url: '/goldDetail/goldTotal', url: '/goldDetail/goldTotal',
data: { data: {
...getAllObj.value, ...getAllObj.value,
user: { ...user.value }
user: {...user.value}
} }
}) })
// result.data.list // result.data.list
@ -238,7 +238,7 @@ const exportExcel = async function () {
page:getObj.pageNum, page:getObj.pageNum,
size:total.value size:total.value
} }
const res = await API({ url: '/goldDetail/exportGold', data: params })
const res = await API({url: '/goldDetail/exportGold', data: params})
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('导出成功') ElMessage.success('导出成功')
} }
@ -326,12 +326,12 @@ const getTagText = (state) => {
<div class="head-card"> <div class="head-card">
<div class="head-card-element"> <div class="head-card-element">
<el-text class="mx-1" size="large">精网号</el-text> <el-text class="mx-1" size="large">精网号</el-text>
<el-input v-model="user.jwcode" style="width: 160px" placeholder="请输入精网号" clearable />
<el-input v-model="user.jwcode" style="width: 160px" placeholder="请输入精网号" clearable/>
</div> </div>
<div class="head-card-element"> <div class="head-card-element">
<el-text class="mx-1" size="large">所属地区</el-text> <el-text class="mx-1" size="large">所属地区</el-text>
<el-select v-model="user.market" placeholder="请选择所属地区" style="width: 180px" clearable> <el-select v-model="user.market" placeholder="请选择所属地区" style="width: 180px" clearable>
<el-option v-for="item in market" :key="item.value" :label="item.label" :value="item.value" />
<el-option v-for="item in market" :key="item.value" :label="item.label" :value="item.value"/>
</el-select> </el-select>
</div> </div>
<el-button type="primary" @click="search()">查询</el-button> <el-button type="primary" @click="search()">查询</el-button>
@ -354,25 +354,25 @@ const getTagText = (state) => {
<!-- 设置表格容器的高度和滚动样式 --> <!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 626px; overflow-y: auto"> <div style="height: 626px; overflow-y: auto">
<el-table :data="tableData" @cellClick="cellClick" style="width: 100%" height="626px" <el-table :data="tableData" @cellClick="cellClick" style="width: 100%" height="626px"
@sort-change="handleSortChange">
@sort-change="handleSortChange">
<el-table-column type="index" label="序号" width="100px" fixed="left"> <el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope"> <template #default="scope">
<span>{{ <span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="jwcode" label="精网号" width="120" />
<el-table-column prop="market" label="所属地区" width="120" />
<el-table-column prop="name" label="姓名" width="120"/>
<el-table-column prop="jwcode" label="精网号" width="120"/>
<el-table-column prop="market" label="所属地区" width="120"/>
<el-table-column prop="allJb" label="金币总数" width="120" aligh="center"> <el-table-column prop="allJb" label="金币总数" width="120" aligh="center">
<template #default="scope"> <template #default="scope">
<span>{{ <span>{{
(scope.row.currentPermanentGold +
scope.row.currentFreeJune +
scope.row.currentFreeDecember +
scope.row.currentTaskGold) / 100
}}</span>
(scope.row.currentPermanentGold +
scope.row.currentFreeJune +
scope.row.currentFreeDecember +
scope.row.currentTaskGold) / 100
}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="currentPermanentGold" label="永久金币" sortable="custom" width="110"> <el-table-column prop="currentPermanentGold" label="永久金币" sortable="custom" width="110">
@ -395,15 +395,27 @@ const getTagText = (state) => {
<span>{{ Math.abs(scope.row.currentTaskGold) / 100 }}</span> <span>{{ Math.abs(scope.row.currentTaskGold) / 100 }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="rcoin" label="历史金币" width="150">
<el-table-column prop="rcoin" label="历史金币总额" width="150">
<template #default="scope"> <template #default="scope">
<!-- 计算四个字段的和并显示 -->
<span>{{
(scope.row.sumPermanentGold || 0) /100 +
(scope.row.sumFreeJune || 0) /100 +
(scope.row.sumFreeDecember || 0) /100 +
(scope.row.sumTaskGold || 0) / 100
}}</span>
<el-popover trigger="hover" placement="left" width="150">
<template #default>
<div>
<div>永久金币{{ (scope.row.sumPermanentGold || 0) / 100 }}</div>
<div>免费金币{{ (scope.row.sumFreeJune || 0) + (scope.row.sumFreeDecember || 0) / 100 }}</div>
<div>任务金币{{ (scope.row.sumTaskGold || 0) / 100 }}</div>
</div>
</template>
<template #reference>
<span>
{{
(scope.row.sumPermanentGold || 0) / 100 +
(scope.row.sumFreeJune || 0) / 100 +
(scope.row.sumFreeDecember || 0) / 100 +
(scope.row.sumTaskGold || 0) / 100
}}</span>
</template>
</el-popover>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="sumConsume" label="历史消费" width="150"> <el-table-column prop="sumConsume" label="历史消费" width="150">
@ -417,8 +429,9 @@ const getTagText = (state) => {
<!-- 分页 --> <!-- 分页 -->
<div class="pagination" style="margin-top: 20px"> <div class="pagination" style="margin-top: 20px">
<el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]" <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>
layout="total, sizes, prev, pager, next, jumper" :total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>

24
src/views/usergold/clientCountDetail.vue

@ -6,6 +6,7 @@ import axios from 'axios'
import moment from 'moment' import moment from 'moment'
import API from '@/util/http' import API from '@/util/http'
import { writeFile, utils } from 'xlsx' import { writeFile, utils } from 'xlsx'
import request from "@/util/request.js";
// ref // ref
@ -99,8 +100,8 @@ const type = [
label: '退款' label: '退款'
} }
] ]
const market = ref([])
/*
// //
const isLoadingArea = ref(false); const isLoadingArea = ref(false);
const market = ref([]) const market = ref([])
@ -124,7 +125,21 @@ const getArea = async () => {
} finally { } finally {
isLoadingArea.value = false; isLoadingArea.value = false;
} }
};
};*/
//
const getMarket = async function () {
try {
const result = await API({
url: '/general/market',
data: {}
})
market.value = result.data
console.log('地区', market.value)
} catch (error) {
console.log('请求失败', error)
}
}
// //
const tableData = ref([]) const tableData = ref([])
@ -332,7 +347,7 @@ const handleCurrentChange = function (val) {
// //
onMounted(async function () { onMounted(async function () {
await get() await get()
await getArea()
await getMarket()
await getAdminData() await getAdminData()
await getPlatform() // await getPlatform() //
}) })
@ -424,6 +439,7 @@ onMounted(async function () {
<span v-if="scope.row.type === 0">充值</span> <span v-if="scope.row.type === 0">充值</span>
<span v-if="scope.row.type === 1">消耗</span> <span v-if="scope.row.type === 1">消耗</span>
<span v-if="scope.row.type === 2">退款</span> <span v-if="scope.row.type === 2">退款</span>
<span v-if="scope.row.type === 3">其他</span>
</template> </template>
</el-table-column> </el-table-column>

163
src/views/workspace/index.vue

@ -1,7 +1,19 @@
<template> <template>
<el-col :span="4">
<el-card class="center-card margin-bottom">数据总览</el-card>
</el-col>
<el-row>
<!-- 数据总览卡片 -->
<el-col :span="4" style="padding-right: 10px;"> <!-- 适当留白避免拥挤 -->
<el-card class="center-card margin-bottom">数据总览</el-card>
</el-col>
<!-- 最后更新时间 -->
<el-col :span="18" style="display: flex; align-items: center; font-size: 18px">
最后更新时间{{workDataUpdateTime}}
</el-col>
<!-- 剩余栅格空间可选用于占满一行 -->
<el-col :span="18"></el-col>
</el-row>
<el-row :gutter="10"> <el-row :gutter="10">
<!-- 第一个卡片 --> <!-- 第一个卡片 -->
<el-col :span="6"> <el-col :span="6">
@ -9,21 +21,23 @@
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<div class="card-title">当前金币余量</div> <div class="card-title">当前金币余量</div>
<div>{{ currentGold / 100 }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;较前一日 {{
dailyChange / 100 }}
<div>{{ currentGold / 100 }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;较前一日
{{
dailyChange / 100
}}
<template v-if="dailyChange > 0"> <template v-if="dailyChange > 0">
<el-icon style="color:red"> <el-icon style="color:red">
<ArrowUpBold />
<ArrowUpBold/>
</el-icon> </el-icon>
</template> </template>
<template v-else-if="dailyChange < 0"> <template v-else-if="dailyChange < 0">
<el-icon style="color:forestgreen"> <el-icon style="color:forestgreen">
<ArrowDownBold />
<ArrowDownBold/>
</el-icon> </el-icon>
</template> </template>
<template v-else> <template v-else>
<el-icon style="color:grey"> <el-icon style="color:grey">
<SemiSelect />
<SemiSelect/>
</el-icon> </el-icon>
</template> </template>
</div> </div>
@ -33,8 +47,10 @@
<div class="margin-bottom">永久金币{{ currentPermanent / 100 }}</div> <div class="margin-bottom">永久金币{{ currentPermanent / 100 }}</div>
<div class="margin-bottom">免费金币{{ currentFree / 100 }}</div> <div class="margin-bottom">免费金币{{ currentFree / 100 }}</div>
<div class="margin-bottom">[六月到期|{{ currentFreeJune / 100 }}]&nbsp;&nbsp;&nbsp;&nbsp;[12月到期|{{ <div class="margin-bottom">[六月到期|{{ currentFreeJune / 100 }}]&nbsp;&nbsp;&nbsp;&nbsp;[12月到期|{{
currentFreeDecember /
100 }}]</div>
currentFreeDecember /
100
}}]
</div>
<div>任务金币{{ currentTask / 100 }}</div> <div>任务金币{{ currentTask / 100 }}</div>
</div> </div>
</el-card> </el-card>
@ -57,14 +73,14 @@
<!-- 第三个卡片 --> <!-- 第三个卡片 -->
<el-col :span="6"> <el-col :span="6">
<el-card class="card-item"> <el-card class="card-item">
<div class="card-title">全年累计消金币数</div>
<div class="card-title">全年累计消金币数</div>
<div class="card-title">{{ yearlyReduce / 100 }}</div> <div class="card-title">{{ yearlyReduce / 100 }}</div>
<div class="center-card">消费{{ yearlyConsume / 100 }}</div> <div class="center-card">消费{{ yearlyConsume / 100 }}</div>
<div class="center-card">退款{{ yearlyRefund / 100 }}</div> <div class="center-card">退款{{ yearlyRefund / 100 }}</div>
<template #footer> <template #footer>
<div></div> <div></div>
<div class="margin-bottom center-card">昨日新增消耗{{ dailyReduce / 100 }}</div>
<div class="margin-bottom center-card">昨日新增消费{{ dailyConsume / 100 }}</div> <div class="margin-bottom center-card">昨日新增消费{{ dailyConsume / 100 }}</div>
<div class="margin-bottom center-card">昨日新增消耗{{ dailyReduce / 100 }}</div>
<div class="margin-bottom center-card">昨日新增退款{{ dailyRefund / 100 }}</div> <div class="margin-bottom center-card">昨日新增退款{{ dailyRefund / 100 }}</div>
</template> </template>
</el-card> </el-card>
@ -78,34 +94,34 @@
<el-col class="center-card">周同比:{{ sumWow }}%&nbsp;&nbsp;&nbsp;&nbsp; <el-col class="center-card">周同比:{{ sumWow }}%&nbsp;&nbsp;&nbsp;&nbsp;
<template v-if="sumWow > 0"> <template v-if="sumWow > 0">
<el-icon style="color:red"> <el-icon style="color:red">
<ArrowUpBold />
<ArrowUpBold/>
</el-icon> </el-icon>
</template> </template>
<template v-else-if="sumWow < 0"> <template v-else-if="sumWow < 0">
<el-icon style="color:forestgreen"> <el-icon style="color:forestgreen">
<ArrowDownBold />
<ArrowDownBold/>
</el-icon> </el-icon>
</template> </template>
<template v-else> <template v-else>
<el-icon style="color:grey"> <el-icon style="color:grey">
<SemiSelect />
<SemiSelect/>
</el-icon> </el-icon>
</template> </template>
</el-col> </el-col>
<el-col class="center-card">日环比:{{ sumDaily }}%&nbsp;&nbsp;&nbsp;&nbsp;
<el-col class="center-card">日环比:{{ sumDaily.toFixed(2) }}%&nbsp;&nbsp;&nbsp;&nbsp;
<template v-if="sumDaily > 0"> <template v-if="sumDaily > 0">
<el-icon style="color:red"> <el-icon style="color:red">
<ArrowUpBold />
<ArrowUpBold/>
</el-icon> </el-icon>
</template> </template>
<template v-else-if="sumDaily < 0"> <template v-else-if="sumDaily < 0">
<el-icon style="color:forestgreen"> <el-icon style="color:forestgreen">
<ArrowDownBold />
<ArrowDownBold/>
</el-icon> </el-icon>
</template> </template>
<template v-else> <template v-else>
<el-icon style="color:grey"> <el-icon style="color:grey">
<SemiSelect />
<SemiSelect/>
</el-icon> </el-icon>
</template> </template>
</el-col> </el-col>
@ -130,11 +146,14 @@
<el-col :span="24"> <el-col :span="24">
<el-row> <el-row>
<div style="margin-top:5px">合计&nbsp;&nbsp;&nbsp;&nbsp; <div style="margin-top:5px">合计&nbsp;&nbsp;&nbsp;&nbsp;
永久金币 {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100
永久金币 {{
activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100
}}&nbsp;&nbsp;&nbsp;&nbsp; }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金币 {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100
免费金币 {{
activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100
}}&nbsp;&nbsp;&nbsp;&nbsp; }}&nbsp;&nbsp;&nbsp;&nbsp;
任务金币 {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100
任务金币 {{
activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100
}}&nbsp;&nbsp;&nbsp;&nbsp; }}&nbsp;&nbsp;&nbsp;&nbsp;
</div> </div>
<div> <div>
@ -189,13 +208,14 @@
<script setup> <script setup>
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { ref, onMounted, nextTick, watch, onUnmounted } from 'vue'
import {onMounted, ref, watch} from 'vue'
import API from '@/util/http' import API from '@/util/http'
import { ElMessage } from 'element-plus'
import {ElMessage} from 'element-plus'
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import utc from 'dayjs-plugin-utc' import utc from 'dayjs-plugin-utc'
import {ArrowDownBold, ArrowUpBold, SemiSelect} from '@element-plus/icons-vue'
dayjs.extend(utc) dayjs.extend(utc)
import { ArrowUpBold, ArrowDownBold, SemiSelect } from '@element-plus/icons-vue'
// //
const markets = ref([]) const markets = ref([])
// //
@ -238,52 +258,21 @@ const sumDaily = ref(0)
const rechargeNum = ref(0) const rechargeNum = ref(0)
const firstRecharge = ref(0) const firstRecharge = ref(0)
const length = ref(0) const length = ref(0)
//
const chartLoading = ref(true)
const handleResize = () => {
if (chartInstance.value) {
try {
chartInstance.value.resize()
console.log('resize一下')
} catch (error) {
console.error('图表resize失败:', error)
}
}
const isLoading = ref(false)
const formatDate = function (date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
} }
//
const initChart = () => {
if (!chartInstance && chartRef.value) {
chartInstance = echarts.init(chartRef.value)
window.addEventListener('resize', handleResize)
}
}
//
const destroyChart = () => {
if (chartInstance.value) {
try {
chartInstance.value.dispose()
} catch (error) {
console.error('图表销毁失败:', error)
}
chartInstance.value = null
}
window.removeEventListener('resize', handleResize)
}
const formatDate = function(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// //
const getToday = function () { const getToday = function () {
const today = dayjs() const today = dayjs()
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss') const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.add(1,'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.add(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime] dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value) console.log('看看dateRange', dateRange.value)
getChartData() getChartData()
@ -291,8 +280,8 @@ const getToday = function () {
// //
const getWeek = function () { const getWeek = function () {
const today = dayjs() const today = dayjs()
const startTime = (today.startOf('week').add(1,'day')).format('YYYY-MM-DD HH:mm:ss')
const endTime = today.add(1,'week').startOf('week').add(1,'day').format('YYYY-MM-DD HH:mm:ss')
const startTime = (today.startOf('week').add(1, 'day')).format('YYYY-MM-DD HH:mm:ss')
const endTime = today.add(1, 'week').startOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime] dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value) console.log('看看dateRange', dateRange.value)
getChartData() getChartData()
@ -301,7 +290,7 @@ const getWeek = function () {
const getMonth = function () { const getMonth = function () {
const today = dayjs() const today = dayjs()
const startTime = today.startOf('month').format('YYYY-MM-DD HH:mm:ss') const startTime = today.startOf('month').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.add(1,'month').startOf('month').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.add(1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime] dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value) console.log('看看dateRange', dateRange.value)
getChartData() getChartData()
@ -310,7 +299,7 @@ const getMonth = function () {
const getYear = function () { const getYear = function () {
const today = dayjs() const today = dayjs()
const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss') const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.add(1,'year').startOf('year').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.add(1, 'year').startOf('year').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime] dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value) console.log('看看dateRange', dateRange.value)
getChartData() getChartData()
@ -397,7 +386,7 @@ const processData = (data) => {
// //
const getMarkets = async () => { const getMarkets = async () => {
try { try {
const response = await API({ url: '/general/market', data: {} })
const response = await API({url: '/general/market', data: {}})
if (Array.isArray(response.data)) { if (Array.isArray(response.data)) {
markets.value = response.data markets.value = response.data
console.log('市场列表获取成功:', markets.value) console.log('市场列表获取成功:', markets.value)
@ -420,7 +409,7 @@ const getChartData = async () => {
} }
// //
if(!dateRange.value || dateRange.value.length === 0){
if (!dateRange.value || dateRange.value.length === 0) {
getYear() getYear()
} }
@ -567,7 +556,7 @@ try{
type: 'bar', type: 'bar',
stack: 'recharge', stack: 'recharge',
data: chartData.rechargePermanent, data: chartData.rechargePermanent,
itemStyle: { color: '#5470c6' },
itemStyle: {color: '#5470c6'},
barWidth: 30 barWidth: 30
}, },
{ {
@ -575,7 +564,7 @@ try{
type: 'bar', type: 'bar',
stack: 'recharge', stack: 'recharge',
data: chartData.rechargeFree, data: chartData.rechargeFree,
itemStyle: { color: '#91cc75' },
itemStyle: {color: '#91cc75'},
barWidth: 30 barWidth: 30
}, },
{ {
@ -583,7 +572,7 @@ try{
type: 'bar', type: 'bar',
stack: 'recharge', stack: 'recharge',
data: chartData.rechargeTask, data: chartData.rechargeTask,
itemStyle: { color: '#fac858' },
itemStyle: {color: '#fac858'},
barWidth: 30 barWidth: 30
} }
] ]
@ -595,7 +584,7 @@ try{
type: 'bar', type: 'bar',
stack: 'consume', stack: 'consume',
data: chartData.consumePermanent, data: chartData.consumePermanent,
itemStyle: { color: '#5470c6' },
itemStyle: {color: '#5470c6'},
barWidth: 30 barWidth: 30
}, },
{ {
@ -603,7 +592,7 @@ try{
type: 'bar', type: 'bar',
stack: 'consume', stack: 'consume',
data: chartData.consumeFree, data: chartData.consumeFree,
itemStyle: { color: '#91cc75' },
itemStyle: {color: '#91cc75'},
barWidth: 30 barWidth: 30
}, },
{ {
@ -611,7 +600,7 @@ try{
type: 'bar', type: 'bar',
stack: 'consume', stack: 'consume',
data: chartData.consumeTask, data: chartData.consumeTask,
itemStyle: { color: '#fac858' },
itemStyle: {color: '#fac858'},
barWidth: 30 barWidth: 30
} }
] ]
@ -680,19 +669,25 @@ const handleTabChange = () => {
const getAdminData = async function () { const getAdminData = async function () {
try { try {
const result = await API({ url: '/admin/userinfo', data: {} })
const result = await API({url: '/admin/userinfo', data: {}})
adminData.value = result adminData.value = result
console.log('用户信息', adminData.value) console.log('用户信息', adminData.value)
} catch (error) { } catch (error) {
console.log('请求失败', error) console.log('请求失败', error)
} }
} }
const workDataUpdateTime = ref(null)
// //
const getCardData = async () => { const getCardData = async () => {
try { try {
const response = await API({ url: '/workbench/getCard', data: {} })
const response = await API({url: '/workbench/getCard', data: {}})
console.log('卡片数据', response.startDate)
workDataUpdateTime.value = response.updateTime
if (response && response.data) { if (response && response.data) {
processData(response.data) processData(response.data)
} else if (Array.isArray(response?.marketCards)) { } else if (Array.isArray(response?.marketCards)) {
processData(response) processData(response)
} else { } else {
@ -709,12 +704,8 @@ onMounted(async () => {
await getCardData() await getCardData()
await getMarkets() await getMarkets()
getYear() getYear()
window.addEventListener('resize', () => {
chartInstance.resize()
})
})
onUnmounted(() => {
destroyChart()
await getChartData()
console.log('挂载后调用')
}) })
</script> </script>

Loading…
Cancel
Save