This commit is contained in:
ping 2025-11-19 16:16:05 +08:00
commit 9e9dfae6d0
2 changed files with 480 additions and 238 deletions

View File

@ -7,6 +7,12 @@ import store from "@/store";
import {myBalanceAPI} from "@/api/finance/customerRechargeManagement";
import {testData} from "@/views/homePage/components/topBox/testData";
// 安全转换为字符串的辅助函数
const safeToString = (value, defaultValue = '') => {
if (value == null) return defaultValue;
return value.toString();
};
// 从sessionStorage恢复状态
const getStoredState = () => {
return {
@ -75,9 +81,18 @@ const mutations = {
state.userType = userType;
sessionStorage.setItem("userType", userType);
},
// 新增:设置组织类型
// 修复:设置组织类型 - 添加防御性检查
SET_ORG_TYPE: (state, orgType) => {
state.orgType = orgType;
// 防御性检查,确保 orgType 不为 null 或 undefined
if (orgType == null) {
console.warn('SET_ORG_TYPE: orgType is null or undefined, setting to empty string');
sessionStorage.setItem("orgType", '');
return;
}
// 安全地调用 toString()
sessionStorage.setItem("orgType", orgType.toString());
},
// 新增:设置用户角色
@ -120,7 +135,8 @@ const actions = {
const userRoles = org_type == 2 ? ['客户'] : ['管理员'];
commit("SET_USER_TYPE", userType);
commit("SET_ORG_TYPE", org_type);
// 确保 org_type 不为 undefined
commit("SET_ORG_TYPE", org_type || '');
commit("SET_ROLES", userRoles); // 新增:设置用户角色
console.log("登录用户类型:", userType, "org_type:", org_type, "用户角色:", userRoles);
@ -171,7 +187,9 @@ const actions = {
commit("SET_USER_TYPE", userType);
}
if (orgType) {
commit("SET_ORG_TYPE", parseInt(orgType));
// 确保 orgType 不为 null 或 undefined
const safeOrgType = orgType ? parseInt(orgType) : '';
commit("SET_ORG_TYPE", safeOrgType);
}
if (roles) {
commit("SET_ROLES", JSON.parse(roles));
@ -190,8 +208,6 @@ const actions = {
// user logout
logout({commit, state, dispatch}) {
return new Promise((resolve, reject) => {
// logout(state.token)
// .then(() => {
commit("SET_TOKEN", "");
commit("SET_ROLES", []);
commit("SET_USER_TYPE", ""); // 新增:清除用户类型
@ -214,10 +230,6 @@ const actions = {
dispatch("tagsView/delAllViews", null, {root: true});
resolve();
// })
// .catch((error) => {
// reject(error);
// });
});
},
@ -272,3 +284,4 @@ export default {
mutations,
actions,
};

View File

@ -1,110 +1,181 @@
<template>
<div id="box">
<div>
<el-table :data="userList" style="width: 100%; box-sizing: border-box;" height="calc(100vh - 98px)"
:row-key="getRowKeys" :expand-row-keys="expands" @expand-change="expandChangeHandler"
v-loading="loading">
<div class="customer-management-container">
<div class="table-container">
<el-table
:data="userList"
style="width: 100%;"
height="calc(100vh - 120px)"
:row-key="getRowKeys"
:expand-row-keys="expands"
@expand-change="expandChangeHandler"
v-loading="loading"
class="customer-table"
:default-sort="{prop: 'transfer_time', order: 'descending'}">
<!-- 展开行 - 客户详细信息 -->
<el-table-column type="expand" align="center" header-align="center">
<template>
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="客户名称:">
<span>{{ tableData.name }}</span>
</el-form-item>
<el-form-item label="客户地址:">
<span>{{ tableData.address }}</span>
</el-form-item>
<el-form-item label="统一社会信用代码:">
<span>{{ tableData.identityCode }}</span>
</el-form-item>
<el-form-item label="联系人:">
<span>{{ tableData.contact }}</span>
</el-form-item>
<el-form-item label="电话:">
<span>{{ tableData.tel }}</span>
</el-form-item>
<el-form-item label="邮箱:">
<span>{{ tableData.email }}</span>
</el-form-item>
<el-form-item label="开户行:">
<span>{{ tableData.bankName }}</span>
</el-form-item>
<el-form-item label="银行账号:">
<span>{{ tableData.bankAcc }}</span>
</el-form-item>
<el-form-item label="发票抬头:">
<span>{{ tableData.identityName }}</span>
</el-form-item>
<el-form-item label="发票联系电话:">
<span>{{ tableData.taxTel }}</span>
</el-form-item>
<el-form-item label="发票地址:">
<span>{{ tableData.taxAddress }}</span>
</el-form-item>
<el-form-item label="纳税人识别号:">
<span>{{ tableData.taxpayerIdentity }}</span>
</el-form-item>
</el-form>
<template slot-scope="scope">
<div class="customer-detail-panel">
<h3 class="detail-title">客户详细信息</h3>
<el-row :gutter="20" class="detail-grid">
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">客户名称</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.name) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">客户地址</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.address) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">统一社会信用代码</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.identityCode) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">联系人</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.contact) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">电话</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.tel) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">邮箱</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.email) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">开户行</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.bankName) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">银行账号</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.bankAcc) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">发票抬头</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.identityName) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">发票联系电话</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.taxTel) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">发票地址</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.taxAddress) || '--' }}</div>
</el-col>
<el-col :xs="24" :sm="12" :md="8" class="detail-item">
<div class="detail-label">纳税人识别号</div>
<div class="detail-value">{{ (scope.row.detailData && scope.row.detailData.taxpayerIdentity) || '--' }}</div>
</el-col>
</el-row>
</div>
</template>
</el-table-column>
<el-table-column label="客户名称" prop="orgname" align="center" header-align="center"></el-table-column>
<el-table-column label="联系电话" prop="contactor_phone" align="center" header-align="center">
</el-table-column>
<el-table-column label="邮箱" prop="emailaddress" align="center" header-align="center"></el-table-column>
<el-table-column label="客户地址" prop="address" align="center" header-align="center"></el-table-column>
<el-table-column label="客户类型" prop="type" align="center" header-align="center"></el-table-column>
<el-table-column label="交接人" prop="previous_sales" align="center" header-align="center"></el-table-column>
<el-table-column label="交接时间" prop="transfer_time" align="center" header-align="center"></el-table-column>
<el-table-column label="操作" prop="" align="center" header-align="center">
<!-- 客户列表列 -->
<el-table-column label="客户名称" prop="orgname" align="center" header-align="center" min-width="160" show-overflow-tooltip></el-table-column>
<el-table-column label="联系电话" prop="contactor_phone" align="center" header-align="center" min-width="130"></el-table-column>
<el-table-column label="邮箱" prop="emailaddress" align="center" header-align="center" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="客户地址" prop="address" align="center" header-align="center" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="客户类型" prop="type" align="center" header-align="center" min-width="100"></el-table-column>
<el-table-column label="交接人" prop="previous_sales" align="center" header-align="center" min-width="100"></el-table-column>
<el-table-column label="交接时间" prop="transfer_time" align="center" header-align="center" min-width="120" sortable></el-table-column>
<el-table-column label="操作" align="center" header-align="center" min-width="120" fixed="right">
<template slot-scope="scope">
<el-button size="small" type="primary" @click="lookBill(scope.row)">查看账单</el-button>
<el-button size="small" type="primary" @click="lookBill(scope.row)" class="action-btn">查看账单</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 查看账单弹窗 -->
<el-dialog title="查看账单" :visible.sync="lookBillVisible" width="70%"
style="height: calc(100vh - 0px);" fullscreen center
class="dialog">
<div class="pagination">
<div class="two">
<div class="data">
<el-date-picker :picker-options="endPickerOpts" v-model="dataOne" type="date" placeholder="选择日期">
<el-dialog
title="查看账单"
:visible.sync="lookBillVisible"
width="85%"
top="10px"
class="bill-dialog"
:close-on-click-modal="false">
<div class="bill-content">
<div class="filter-section">
<div class="date-filter">
<div class="filter-label">账单日期</div>
<el-date-picker
v-model="dataOne"
type="date"
placeholder="开始日期"
:picker-options="startPickerOpts"
class="date-input">
</el-date-picker>
<span class="line"></span>
<el-date-picker :picker-options="endPickerOpts" type="date" placeholder="选择日期"
v-model="dataTwo"></el-date-picker>
</div>
<div class="button">
<el-button size="small" type="primary" @click="onsubmit()">查询</el-button>
<span class="date-separator"></span>
<el-date-picker
v-model="dataTwo"
type="date"
placeholder="结束日期"
:picker-options="endPickerOpts"
class="date-input">
</el-date-picker>
<el-button
type="primary"
size="small"
@click="onsubmit()"
class="query-btn"
icon="el-icon-search">
查询
</el-button>
</div>
</div>
<el-table :data="billList" height="calc(100vh - 230px)">
<el-table-column label="产品名称" prop="productname" align="center" header-align="center">
<div class="bill-table-container">
<el-table
:data="billList"
height="calc(100vh - 280px)"
class="bill-table"
empty-text="暂无账单数据">
<el-table-column label="产品名称" prop="productname" align="center" header-align="center" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="账单号" prop="id" align="center" header-align="center" min-width="120"></el-table-column>
<el-table-column label="账单金额" prop="amount" align="center" header-align="center" min-width="120">
<template slot-scope="scope">
<span class="amount">¥{{ scope.row.amount || 0 }}</span>
</template>
</el-table-column>
<el-table-column label="账单号" prop="id" align="center" header-align="center"></el-table-column>
<el-table-column label="账单金额" prop="amount" align="center" header-align="center"></el-table-column>
<el-table-column label="账单日期" prop="bill_date" align="center" header-align="center"></el-table-column>
<el-table-column label="账单状态" prop="contactor_phone" align="center" header-align="center">
<el-table-column label="账单日期" prop="bill_date" align="center" header-align="center" min-width="120"></el-table-column>
<el-table-column label="账单状态" align="center" header-align="center" min-width="120">
<template slot-scope="scope">
<el-tag
:type="getBillstate(scope.row.bill_state * 1).type"
effect="dark">
:effect="getBillstate(scope.row.bill_state * 1).effect || 'light'"
class="status-tag">
{{ getBillstate(scope.row.bill_state * 1).message }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="购买状态" prop="productname" align="center" header-align="center">
<!-- <template slot-scope="scope">-->
<!-- {{ getBusinessOp(scope.row.business_op) }}-->
<!-- </template>-->
<el-table-column label="购买状态" align="center" header-align="center" min-width="120">
<template slot-scope="scope">
<el-tag
:type="getBusinessOpType(scope.row.business_op)"
effect="light"
class="business-op-tag">
{{ getBusinessOpText(scope.row.business_op) }}
</el-tag>
</template>
</el-table-column>
</el-table>
<el-pagination style="margin-top:20px;margin-left:30%" background @current-change="handleCurrentChange"
:page-size="10" :pager-count="11" layout="prev, pager, next" :total='total'>
</div>
<div class="pagination-section">
<el-pagination
background
@current-change="handleCurrentChange"
:page-size="10"
:pager-count="7"
layout="total, prev, pager, next, jumper"
:total="total"
class="bill-pagination">
</el-pagination>
</div>
</el-dialog>
</div>
</el-dialog>
</div>
</template>
@ -124,232 +195,390 @@ export default {
currentRow: {},
expands: [],
lookBillVisible: false,
getRowKeys(row) {
return row.id;
},
tableData: {
address: "",
ak: "",
appId: "",
bankAcc: "",
bankName: "",
contact: "",
email: "",
fullName: "",
identityCode: "",
identityName: "",
name: "",
remark: "",
saleMgrEmail: "",
saleMgrName: "",
saleMgrTel: "",
saleorgname: "",
sk: "",
supId: 1,
taxAddress: "",
taxTel: "",
taxpayerIdentity: "",
tel: "",
thirdId: "",
userAc: "",
userPhone: "",
userid: "",
},
current_page: 1,
total: null,
dataOne: null,
dataTwo: null,
startPickerOpts: {
disabledDate: (time) => {
if (this.dataTwo) {
return time.getTime() > new Date(this.dataTwo).getTime();
}
return time.getTime() > Date.now();
}
},
endPickerOpts: {
disabledDate(time) {
disabledDate: (time) => {
if (this.dataOne) {
return time.getTime() < new Date(this.dataOne).getTime() || time.getTime() > Date.now();
}
return time.getTime() > Date.now();
}
},
};
},
mounted() {
this.loading = true
this.loading = true;
this.getuserList();
//
const end = new Date();
const start = new Date();
start.setMonth(start.getMonth() - 1);
this.dataOne = start;
this.dataTwo = end;
},
methods: {
getRowKeys(row) {
return row.id;
},
handleCurrentChange(index) {
this.current_page = index
this.lookUp()
this.current_page = index;
this.lookUp();
},
lookBill(row) {
this.currentRow = row
this.lookBillVisible = true
this.lookUp()
this.currentRow = row;
this.lookBillVisible = true;
this.lookUp();
},
lookUp(dataOne, dataTwo) {
let params = {
user_orgid: this.currentRow.id,
start_time: dataOne,
end_time: dataTwo,
start_time: dataOne || this.dataOne,
end_time: dataTwo || this.dataTwo,
page_size: 10,
current_page: this.current_page
}
};
userGetbillAPI(params).then(res => {
console.log(res);
if (res.status) {
if (res.data.total_page != 0) {
this.billList = res.data.bill_list
this.total = res.data.total_num
this.billList = res.data.bill_list;
this.total = res.data.total_num;
} else {
this.billList = []
this.total = 0
this.billList = [];
this.total = 0;
this.$message({
message: "暂无数据",
type: 'warning'
})
});
}
} else {
this.$message({
message: res.msg,
type: 'error'
})
});
}
})
}).catch(error => {
this.$message({
message: "请求失败,请稍后重试",
type: 'error'
});
console.error(error);
});
},
onsubmit() {
if (!this.dataOne || !this.dataTwo) {
this.$message({
message: "请选择时间",
message: "请选择完整的时间范围",
type: 'warning'
})
} else {
this.lookUp(this.dataOne, this.dataTwo)
}
},
expandChangeHandler(row, expandedRows) {//
var orgid = {
orgid: row.id,
};
getZJUserInfoAPI(orgid).then((res) => {
this.tableData = res.data;
});
return;
}
if (this.dataOne > this.dataTwo) {
this.$message({
message: "开始日期不能大于结束日期",
type: 'warning'
});
return;
}
this.current_page = 1;
this.lookUp();
},
expandChangeHandler(row, expandedRows) {
if (expandedRows.length) {
this.expands = [];
if (row) {
this.expands.push(row.id);
//
if (!row.detailData) {
var orgid = {
orgid: row.id,
};
getZJUserInfoAPI(orgid).then((res) => {
// 使 $set
this.$set(row, 'detailData', res.data);
}).catch(error => {
console.error("获取客户详情失败:", error);
// 使
this.$set(row, 'detailData', {});
});
}
}
} else {
this.expands = [];
}
},
getuserList() {//
getuserList() {
var userid = {
userid: sessionStorage.getItem("userId"),
// kv: "zj",
};
getZJsaleGetUsersAPI(userid).then((res) => {
this.loading = false
this.loading = false;
this.userList = res.data;
}).catch(error => {
this.loading = false;
console.error("获取客户列表失败:", error);
this.$message({
message: "获取客户列表失败",
type: 'error'
});
});
},
open4(str) { //
this.$message.error(str);
},
getBusinessOp(data) {
switch (data) {
case 'BUY':
return "购买";
case 'RECHARGE':
return "充值";
case 'RECHARGE_ALIPAY':
return "支付宝充值";
case 'REFUND':
return "退款";
}
},
getBillstate(data) {
switch (data) {
case 0:
return {
message: '未支付',
type: 'info'
type: 'warning'
};
case 1:
return {
message: '已支付',
type: 'success'
}
};
case 2:
return {
message: '已取消',
type: 'info'
}
};
case null:
return {
message: '已取消',
type: 'info'
}
};
default:
return {
message: '未知',
type: 'info'
}
};
}
},
//
getBusinessOpText(businessOp) {
switch (businessOp) {
case 'BUY':
return '购买';
case 'BUY_REVERSE':
return '退费';
case 'RECHARGE ':
return '续费';
default:
return businessOp || '--';
}
},
//
getBusinessOpType(businessOp) {
switch (businessOp) {
case 'BUY':
return 'success';
case 'BUY_REVERSE':
return 'danger';
case 'RENEW':
return 'primary';
default:
return 'info';
}
}
},
};
</script>
<style lang="scss" scoped>
#box {
min-width: 800px;
<style lang="less" scoped>
.customer-management-container {
padding: 20px;
background-color: #f5f7fa;
min-height: calc(100vh - 40px);
box-sizing: border-box;
/* overflow: scroll; */
.dialog {
height: 100%;
// position: relative;
.pagination {
.two {
.table-container {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
overflow: hidden;
.customer-table {
::v-deep .el-table__expanded-cell {
padding: 0;
}
.action-btn {
border-radius: 4px;
}
}
}
.customer-detail-panel {
padding: 20px;
background: #f9fafc;
.detail-title {
margin: 0 0 16px 0;
font-size: 16px;
color: #303133;
font-weight: 600;
border-bottom: 1px solid #e6e8eb;
padding-bottom: 10px;
}
.detail-grid {
.detail-item {
margin-bottom: 16px;
display: flex;
flex-direction: row;
flex-direction: column;
.data {
line-height: 50px;
height: 50px;
.detail-label {
font-size: 13px;
color: #909399;
margin-bottom: 4px;
font-weight: 500;
}
.detail-value {
font-size: 14px;
color: #606266;
word-break: break-all;
}
}
}
}
.bill-dialog {
::v-deep .el-dialog {
border-radius: 8px;
overflow: hidden;
.el-dialog__header {
background: #f5f7fa;
padding: 15px 20px;
border-bottom: 1px solid #e6e8eb;
.el-dialog__title {
font-weight: 600;
color: #303133;
}
}
.el-dialog__body {
padding: 0;
}
}
.bill-content {
padding: 20px;
.filter-section {
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #e6e8eb;
.date-filter {
display: flex;
flex-direction: row;
align-items: center;
.line {
margin-left: 5px;
margin-right: 5px;
.filter-label {
margin-right: 10px;
font-weight: 500;
color: #606266;
}
.date-input {
width: 160px;
}
.date-separator {
margin: 0 10px;
color: #909399;
}
.query-btn {
margin-left: 15px;
border-radius: 4px;
}
}
}
.button {
margin-top: 10px;
margin-left: 15px
.bill-table-container {
.bill-table {
.amount {
font-weight: 600;
color: #f56c6c;
}
.status-tag {
border-radius: 12px;
padding: 0 10px;
height: 24px;
line-height: 24px;
}
.business-op-tag {
border-radius: 12px;
padding: 0 10px;
height: 24px;
line-height: 24px;
}
}
}
.pagination-section {
margin-top: 20px;
display: flex;
justify-content: center;
.bill-pagination {
::v-deep .el-pagination.is-background .el-pager li:not(.disabled).active {
background-color: #409eff;
}
}
}
}
}
}
.demo-table-expand {
font-size: 0;
}
//
@media (max-width: 768px) {
.customer-management-container {
padding: 10px;
.demo-table-expand label {
width: 90px;
color: #99a9bf;
}
.bill-dialog {
width: 95% !important;
.demo-table-expand .el-form-item {
margin-right: 0;
margin-bottom: 0;
width: 40%;
}
.bill-content {
.filter-section {
.date-filter {
flex-wrap: wrap;
.el-form-item__label {
width: 140px !important;
.filter-label {
width: 100%;
margin-bottom: 10px;
}
.date-input {
width: calc(50% - 25px);
}
.query-btn {
width: 100%;
margin: 15px 0 0 0;
}
}
}
}
}
}
}
</style>