Files
cashier-web/src/views/user/list/index.vue
2026-02-04 16:32:55 +08:00

442 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<!-- 列表 -->
<!-- 搜索 -->
<page-search ref="searchRef" :search-config="searchConfig" @query-click="searchQueryClick"
@reset-click="handleResetClick" />
<div class="head-container">
<div class="card">
<!-- <div class="title">统计数据</div> -->
<div class="row">
<div class="item">
<div class="t">用户数量</div>
<div class="n">{{ summary.userTotal || 0 }}</div>
</div>
<div class="item">
<div class="t">用户总余额</div>
<div class="n">{{ summary.balanceTotal || 0 }}</div>
</div>
<div class="item">
<div class="t">充值金额</div>
<div class="n">{{ summary.chargeTotal || 0 }}</div>
</div>
<div class="item u-flex u-col-center">
<el-button type="success" @click="toCharge()">充值记录</el-button>
<!-- <el-button type="danger" @click="toCharge('cost')">消费记录</el-button> -->
</div>
</div>
</div>
</div>
<!-- 列表 -->
<page-content ref="contentRef" :content-config="contentConfig" @add-click="handleAddClick"
@edit-click="handleEditClick" @export-click="handleExportClick" @upload-click="" @search-click="handleSearchClick"
@toolbar-click="handleToolbarClick" @operat-click="handleOperatClick" @filter-change="handleFilterChange">
<template #custom>
<importData ref="importDataRef" :type="6" @close="searchQueryClick" />
</template>
<template #status="scope">
<el-link :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
</el-link>
</template>
<template #options="scope">
{{ returnOptionsLabel(scope.prop, scope.row[scope.prop]) }}
</template>
<template #bol="scope">
<el-tag disable-transitions type="primary" v-if="scope.row.isVip" @click="showVipInfoHandle(scope.row)"
style="cursor: pointer;">
{{ scope.row.memberLevelName }}
</el-tag>
<span v-else></span>
</template>
<template #gender="scope">
<el-tag :type="scope.row[scope.prop] == null
? 'info'
: scope.row[scope.prop] == 1
? 'success'
: 'warning'
">
{{
scope.row[scope.prop] === null
? "未知"
: scope.row[scope.prop] == 1
? "男"
: "女"
}}
</el-tag>
</template>
<template #user="scope">
<div class="flex align-center">
<el-avatar :src="scope.row.headImg" />
<span class="u-line-1 u-m-l-6" style="max-width: 90px">
{{ scope.row.nickName }}
</span>
</div>
</template>
<template #link="scope">
<el-link>{{ scope.row[scope.prop] }}</el-link>
</template>
<template #mobile="scope">
<el-text>{{ scope.row[scope.prop] }}</el-text>
<copy-button v-if="scope.row[scope.prop]" :text="scope.row[scope.prop]" style="margin-left: 2px" />
</template>
<template #coupon="scope">
<div>
{{ scope.row.couponNum }}
<el-link :underline="false" type="primary" @click="handleViewCoupon(scope.row)">
查看详情
</el-link>
</div>
</template>
</page-content>
<!-- 新增 -->
<page-modal ref="addModalRef" :modal-config="addModalConfig" @submit-click="handleSubmitClick"></page-modal>
<!-- 编辑 -->
<page-modal ref="editModalRef" :modal-config="editModalConfig" @submit-click="handleSubmitClick"></page-modal>
<!-- 用户余额修改 -->
<page-modal ref="editMoneyModalRef" :modal-config="editMoneyModalConfig" @formDataChange="formDataChange"
@submit-click="handleSubmitClick"></page-modal>
<!-- 用户优惠券详情 -->
<UserCouponDialog ref="userCouponDialogRef"></UserCouponDialog>
<!-- 赠送券 -->
<GiveCoupon ref="GiveCouponRef"></GiveCoupon>
<el-dialog :title="`账号${userRow.status == 0 ? '开启' : '禁用'}`" width="600px" v-model="visible">
<span>确定要{{ userRow.status == 0 ? '开启' : '禁用' }}{{ userRow.nickName }} / {{ userRow.phone }}账号吗</span>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="handleOk" :loading="confirmLoading"> </el-button>
</div>
</template>
</el-dialog>
<!-- 会员详情 -->
<el-dialog title="会员详情" width="600px" v-model="vipDialogVisable">
<div class="vip_info">
<div class="top">
<el-avatar :src="currentVipInfo.headImg" :size="60" shape="square"></el-avatar>
<div class="info">
<div class="name">{{ currentVipInfo.nickName }}</div>
<div class="id">ID{{ currentVipInfo.id }}</div>
</div>
</div>
<div class="btm">
<div class="row">
<span class="row_t">会员等级</span>
<span class="row_b">{{ currentVipInfo.memberLevelName }}</span>
</div>
<div class="row">
<span class="row_t">开通时间</span>
<span class="row_b">{{ currentVipInfo.startTime }}</span>
</div>
<div class="row">
<span class="row_t">到期时间</span>
<span class="row_b" style="color: #FF2F2F;">{{ currentVipInfo.endTime }}</span>
</div>
<div class="row">
<span class="row_t">成长值</span>
<span class="row_b" style="margin-left: 6px;">{{ currentVipInfo.experience }}</span>
<span class="tips" v-if="currentVipInfo.nextMemberLevelName">距离{{ currentVipInfo.nextMemberLevelName }}还差{{
currentVipInfo.nextExperience }}</span>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import importData from "@/components/importData/index.vue";
import UserCouponDialog from "./components/user-coupon-dialog.vue";
import GiveCoupon from "./components/give-coupon.vue";
import usePage from "@/components/CURD/usePage";
import addModalConfig from "./config/add";
import contentConfig from "./config/content";
import editModalConfig from "./config/edit";
import editMoneyModalConfig, { addOptions, reduceOptions } from "./config/edit-money";
import searchConfig from "./config/search";
import { returnOptionsLabel } from "./config/config";
import shopUserApi from "@/api/account/shopUser";
import { useRoute } from 'vue-router'
import { ElNotification } from 'element-plus'
import { downloadFile } from "@/utils/index";
const editMoneyModalRef = ref(null);
const userCouponDialogRef = ref(null);
const GiveCouponRef = ref(null);
//查看用户优惠券
function handleViewCoupon(row) {
userCouponDialogRef.value.open(row);
}
const {
searchRef,
contentRef,
addModalRef,
editModalRef,
handleQueryClick,
handleResetClick,
// handleAddClick,
// handleEditClick,
handleSubmitClick,
// handleExportClick,
handleSearchClick,
handleFilterChange,
} = usePage();
function searchQueryClick(e) {
console.log(e);
handleQueryClick(e);
// 获取统计数据
getSummary();
}
const summary = reactive({
userTotal: 0,
chargeTotal: 0,
balanceTotal: 0.0,
});
const router = useRouter();
// 跳转页面
function toCharge(params) {
console.log(params);
router.push({ path: "/user/charge-list", query: { ...params } });
}
async function getSummary(e) {
// 获取统计数据
const res = await shopUserApi.getSummary(e);
console.log(res);
Object.assign(summary, res);
}
// 修改金额表单类型
function formDataChange(type, val) {
if (type == "type") {
if (val == 1) {
editMoneyModalConfig.formItems[4].options = addOptions;
} else {
editMoneyModalConfig.formItems[4].options = reduceOptions;
}
}
}
// 导出
async function handleExportClick() {
try {
const file = await shopUserApi.export(searchRef.value.getQueryParams());
downloadFile(file, "用户列表", "xlsx");
} catch (error) {
console.log(error);
}
}
// 新增
async function handleAddClick() {
addModalRef.value?.setModalVisible();
// 加载部门下拉数据源
// addModalConfig.formItems[2]!.attrs!.data = await DeptAPI.getOptions();
// 加载角色下拉数据源
// addModalConfig.formItems[4]!.options = await RoleAPI.getOptions();
}
// 编辑
async function handleEditClick(row) {
editModalRef.value?.handleDisabled(false);
editModalRef.value?.setModalVisible();
// 根据id获取数据进行填充
// const data = await VersionApi.getFormData(row.id);
editModalRef.value?.setFormData({ ...row, headImg: row.headImg ? [row.headImg] : "" });
}
// 其他工具栏
function handleToolbarClick(name) {
console.log(name);
if (name === "custom1") {
ElMessage.success("点击了自定义1按钮");
} else if (name === "upload") {
importDataRef.value.show()
}
}
// 账号禁用 start
const userRow = ref('')
const visible = ref(false)
const confirmLoading = ref(false)
async function handleOk() {
try {
confirmLoading.value = true
const shopId = localStorage.getItem('shopId')
let state = 0
if (userRow.value.status == 0) {
state = 1
} else {
state = 0
}
await shopUserApi.edit(shopId, { id: userRow.value.id, status: state })
searchQueryClick()
ElNotification({
title: '注意',
message: `${userRow.value.status == 0 ? '开启' : '禁用'}成功`,
type: 'success'
})
} catch (error) {
console.log(error);
}
setTimeout(() => {
confirmLoading.value = false
visible.value = false
}, 300);
}
// 账号禁用 end
// 会员详情 start
const vipDialogVisable = ref(false)
const currentVipInfo = ref('')
const currentVipUser = ref('')
function showVipInfoHandle(row) {
currentVipUser.value = { ...row }
vipDialogVisable.value = true
getUserVipInfo()
}
// 获取会员详情
async function getUserVipInfo() {
try {
const res = await shopUserApi.vipInfo({ id: currentVipUser.value.id })
currentVipInfo.value = res
console.log('getUserVipInfo===', res);
} catch (error) {
console.log(error);
}
}
// 会员详情 end
// 赠送券
function toGiveCoupon() { }
// 其他操作列
async function handleOperatClick(data) {
const row = data.row;
if (data.name == "more") {
if (data.command === "change-money") {
editMoneyModalRef.value.setModalVisible();
editMoneyModalRef.value.setFormData({
...row,
headImg: row.headImg ? [row.headImg] : "",
});
return;
}
if (data.command === "charge-list") {
console.log(data);
toCharge({ userId: data.row.userId });
return;
}
if (data.command === "give-coupon") {
GiveCouponRef.value.open(row);
return;
}
if (data.command === 'user-disabld') {
userRow.value = { ...row }
visible.value = true
return
}
return;
}
}
const route = useRoute()
onMounted(() => {
if (route.query.phone) {
searchQueryClick({
key: route.query.phone
})
}
getSummary(searchRef.value.getQueryParams());
});
</script>
<style scoped lang="scss">
.align-center {
align-items: center;
}
.card {
background-color: #f5f5f5;
padding: 0 14px;
.title {
font-size: 22px;
padding-top: 14px;
}
.row {
display: flex;
padding: 20px 0;
.item {
flex: 1;
.t {
text-align: center;
color: #555;
}
.n {
color: #000;
font-size: 20px;
font-weight: bold;
padding-top: 6px;
text-align: center;
}
}
}
}
.vip_info {
.top {
padding: 14px;
background-color: #f5f5f5;
display: flex;
align-items: center;
.info {
padding-left: 10px;
display: flex;
flex-direction: column;
.name {
font-size: 16px;
color: #333;
}
.id {
font-size: 14px;
color: #666;
}
}
}
.btm {
margin-top: 14px;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(auto, 1fr);
grid-column-gap: 14px;
grid-row-gap: 14px;
.row {
.row_t {
color: #666;
}
.row_b {
color: #333;
}
}
}
}
</style>