This commit is contained in:
qsh
2026-01-29 17:39:43 +08:00
parent 737f37afdc
commit db42252b6c
14 changed files with 7320 additions and 338 deletions

View File

@@ -3,109 +3,169 @@
{
"path": "pages/login",
"style": {
"navigationBarTitleText": "登录"
"navigationStyle": "custom"
}
},
{
"path": "pages/register",
"style": {
"navigationBarTitleText": "注册"
"navigationStyle": "custom"
}
},
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "小程序管理后台"
"navigationStyle": "custom"
}
},
{
"path": "pages/work/index",
"style": {
"navigationBarTitleText": "工作台"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/index",
"style": {
"navigationBarTitleText": "我的"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/avatar/index",
"style": {
"navigationBarTitleText": "修改头像"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/info/index",
"style": {
"navigationBarTitleText": "个人信息"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/info/edit",
"style": {
"navigationBarTitleText": "编辑资料"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/pwd/index",
"style": {
"navigationBarTitleText": "修改密码"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/setting/index",
"style": {
"navigationBarTitleText": "应用设置"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/help/index",
"style": {
"navigationBarTitleText": "常见问题"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/about/index",
"style": {
"navigationBarTitleText": "关于我们"
"navigationStyle": "custom"
}
},
{
"path": "pages/common/webview/index",
"style": {
"navigationBarTitleText": "浏览网页"
"navigationStyle": "custom"
}
},
{
"path": "pages/common/textview/index",
"style": {
"navigationBarTitleText": "浏览文本"
"navigationStyle": "custom"
}
},
{
"path": "pages/distributor/index",
"style": {
"navigationBarTitleText": "分销员管理"
"navigationStyle": "custom"
}
},
{
"path": "pages/distributor/add",
"style": {
"navigationBarTitleText": "新增分销员"
"navigationStyle": "custom"
}
},
{
"path": "pages/distributor/edit",
"style": {
"navigationBarTitleText": "修改分销员"
"navigationStyle": "custom"
}
},
{
"path": "pages/distributor/rule",
"style": {
"navigationBarTitleText": "分润规则配置"
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/school-info",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/custom-fields",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/data-logs",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/personal-info",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/password-change",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/help-center",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/about-us",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/exception/profit",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/exception/ai-recharge",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/exception/member-order",
"style": {
"navigationStyle": "custom"
}
}
],

View File

@@ -0,0 +1,609 @@
<template>
<view class="ai-recharge-exception-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">AI充值订单异常</view>
<view class="header-right" @click="refreshData">
<view class="refresh-btn">刷新</view>
</view>
</view>
<!-- 异常统计 -->
<view class="stats-section">
<view class="stats-grid">
<view class="stat-card">
<view class="stat-icon">🤖</view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.total }}</view>
<view class="stat-label">总异常数</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.pending }}</view>
<view class="stat-label">待处理</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.resolved }}</view>
<view class="stat-label">已解决</view>
</view>
</view>
</view>
</view>
<!-- 异常列表 -->
<view class="exception-section">
<view class="section-header">
<view class="section-title">异常列表</view>
<view class="filter-box">
<view class="filter-tabs">
<view
v-for="tab in filterTabs"
:key="tab.value"
class="filter-tab"
:class="{ active: currentFilter === tab.value }"
@click="currentFilter = tab.value"
>
{{ tab.label }}
</view>
</view>
</view>
</view>
<view class="exception-list">
<view
v-for="exception in filteredExceptions"
:key="exception.id"
class="exception-item"
:class="{ 'pending': exception.status === 'pending', 'resolved': exception.status === 'resolved' }"
@click="viewExceptionDetail(exception.id)"
>
<view class="exception-header">
<view class="exception-title">{{ exception.title }}</view>
<view class="exception-status">{{ getStatusText(exception.status) }}</view>
</view>
<view class="exception-content">
<view class="exception-desc">{{ exception.description }}</view>
<view class="exception-info">
<view class="info-item">
<view class="info-label">订单号</view>
<view class="info-value">{{ exception.orderNo }}</view>
</view>
<view class="info-item">
<view class="info-label">学员信息</view>
<view class="info-value">{{ getMaskedStudentInfo(exception.studentInfo) }}</view>
</view>
<view class="info-item">
<view class="info-label">充值金额</view>
<view class="info-value">{{ exception.amount }}</view>
</view>
<view class="info-item">
<view class="info-label">异常时间</view>
<view class="info-value">{{ exception.createTime }}</view>
</view>
</view>
</view>
<view class="exception-actions">
<view
v-if="exception.status === 'pending'"
class="action-btn primary"
@click.stop="resolveException(exception.id)"
>
处理
</view>
<view
class="action-btn secondary"
@click.stop="viewExceptionDetail(exception.id)"
>
详情
</view>
</view>
</view>
<view v-if="filteredExceptions.length === 0" class="empty-state">
<view class="empty-icon">🤖</view>
<view class="empty-text">暂无相关异常</view>
</view>
</view>
</view>
<!-- 操作提示 -->
<view class="tips-section">
<view class="tips-title">操作提示</view>
<view class="tips-content">
<view class="tip-item"> AI充值订单异常可能包括支付失败系统错误等情况</view>
<view class="tip-item"> 处理异常后系统会自动重试订单处理</view>
<view class="tip-item"> 如遇持续异常请联系平台客服</view>
<view class="tip-item"> 学员信息已脱敏处理保护隐私安全</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
// 异常统计
const exceptionStats = ref({
total: 3,
pending: 1,
resolved: 2
})
// 异常列表
const exceptions = ref([
{
id: 1,
title: '支付失败',
description: 'AI充值订单支付失败请检查支付状态',
orderNo: 'AI202601290001',
studentInfo: {
name: '张**',
phone: '138****1234'
},
amount: 99.00,
status: 'pending',
createTime: '2026-01-29 10:30:45'
},
{
id: 2,
title: '系统错误',
description: 'AI充值订单处理时系统错误请重试',
orderNo: 'AI202601290002',
studentInfo: {
name: '李**',
phone: '139****5678'
},
amount: 199.00,
status: 'resolved',
createTime: '2026-01-29 09:15:30'
},
{
id: 3,
title: '支付超时',
description: 'AI充值订单支付超时请重新发起支付',
orderNo: 'AI202601290003',
studentInfo: {
name: '王**',
phone: '137****9012'
},
amount: 49.00,
status: 'resolved',
createTime: '2026-01-29 08:45:12'
}
])
// 过滤标签
const filterTabs = ref([
{ label: '全部', value: 'all' },
{ label: '待处理', value: 'pending' },
{ label: '已解决', value: 'resolved' }
])
const currentFilter = ref('all')
// 过滤后的异常列表
const filteredExceptions = computed(() => {
if (currentFilter.value === 'all') {
return exceptions.value
}
return exceptions.value.filter(exception => exception.status === currentFilter.value)
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 刷新数据
function refreshData() {
uni.showLoading({ title: '刷新中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '刷新成功', icon: 'success' })
}, 1000)
}
// 获取状态文本
function getStatusText(status) {
switch (status) {
case 'pending':
return '待处理'
case 'resolved':
return '已解决'
default:
return '未知'
}
}
// 获取脱敏学员信息
function getMaskedStudentInfo(studentInfo) {
return `${studentInfo.name} ${studentInfo.phone}`
}
// 查看异常详情
function viewExceptionDetail(exceptionId) {
uni.navigateTo({
url: `/pages/exception/ai-recharge-detail?id=${exceptionId}`
})
}
// 处理异常
function resolveException(exceptionId) {
uni.showModal({
title: '处理异常',
content: '是否确认处理该异常?\n\n处理后系统会自动重试订单处理',
success: function(res) {
if (res.confirm) {
uni.showLoading({ title: '处理中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '处理成功', icon: 'success' })
// 更新异常状态
const exception = exceptions.value.find(e => e.id === exceptionId)
if (exception) {
exception.status = 'resolved'
// 更新统计数据
exceptionStats.value.pending--
exceptionStats.value.resolved++
}
}, 1500)
}
}
})
}
onMounted(() => {
// 实际项目中应从接口获取异常数据
// fetchExceptionData()
})
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.ai-recharge-exception-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.refresh-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 异常统计 */
.stats-section {
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.stats-grid {
display: flex;
justify-content: space-between;
gap: 16rpx;
}
.stat-card {
flex: 1;
display: flex;
align-items: center;
padding: 24rpx;
background-color: #f9f9f9;
border-radius: 12rpx;
}
.stat-icon {
font-size: 48rpx;
margin-right: 24rpx;
}
.stat-content {
flex: 1;
}
.stat-value {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 24rpx;
color: #606266;
}
/* 异常列表 */
.exception-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
line-height: 1.2;
}
.filter-tabs {
display: flex;
gap: 16rpx;
}
.filter-tab {
padding: 12rpx 24rpx;
background-color: #f9f9f9;
border-radius: 8rpx;
font-size: 24rpx;
color: #606266;
cursor: pointer;
}
.filter-tab.active {
background-color: #409eff;
color: #fff;
}
.exception-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.exception-item {
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
transition: all 0.3s ease;
}
.exception-item.pending {
border-left: 8rpx solid #f56c6c;
}
.exception-item.resolved {
border-left: 8rpx solid #67c23a;
}
.exception-item:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.exception-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.exception-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
.exception-status {
padding: 8rpx 16rpx;
border-radius: 8rpx;
font-size: 20rpx;
font-weight: 600;
}
.exception-item.pending .exception-status {
background-color: #fef0f0;
color: #f56c6c;
}
.exception-item.resolved .exception-status {
background-color: #f0f9eb;
color: #67c23a;
}
.exception-content {
margin-bottom: 20rpx;
}
.exception-desc {
font-size: 24rpx;
color: #606266;
margin-bottom: 16rpx;
line-height: 1.4;
}
.exception-info {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.info-item {
display: flex;
align-items: center;
}
.info-label {
font-size: 22rpx;
color: #909399;
margin-right: 8rpx;
}
.info-value {
font-size: 22rpx;
font-weight: 600;
color: #303133;
}
.exception-actions {
display: flex;
gap: 16rpx;
justify-content: flex-end;
}
.action-btn {
padding: 12rpx 24rpx;
border-radius: 8rpx;
font-size: 24rpx;
font-weight: 600;
cursor: pointer;
}
.action-btn.primary {
background-color: #409eff;
color: #fff;
}
.action-btn.secondary {
background-color: #f9f9f9;
color: #606266;
border: 1rpx solid #e4e7ed;
}
/* 操作提示 */
.tips-section {
padding: 32rpx;
background-color: #ecf5ff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
.tip-item {
margin-bottom: 8rpx;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
text-align: center;
}
.empty-icon {
font-size: 100rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 28rpx;
color: #909399;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.ai-recharge-exception-container {
max-width: 900px;
margin: 0 auto;
}
.stats-section,
.exception-section {
padding: 40rpx;
}
.exception-title {
font-size: 32rpx;
}
.exception-desc {
font-size: 28rpx;
}
.info-item {
font-size: 24rpx;
}
}
</style>

View File

@@ -0,0 +1,644 @@
<template>
<view class="member-order-exception-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">会员订单异常</view>
<view class="header-right" @click="refreshData">
<view class="refresh-btn">刷新</view>
</view>
</view>
<!-- 异常统计 -->
<view class="stats-section">
<view class="stats-grid">
<view class="stat-card">
<view class="stat-icon">🛒</view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.total }}</view>
<view class="stat-label">总异常数</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.pending }}</view>
<view class="stat-label">待处理</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.resolved }}</view>
<view class="stat-label">已解决</view>
</view>
</view>
</view>
</view>
<!-- 异常列表 -->
<view class="exception-section">
<view class="section-header">
<view class="section-title">异常列表</view>
<view class="filter-box">
<view class="filter-tabs">
<view
v-for="tab in filterTabs"
:key="tab.value"
class="filter-tab"
:class="{ active: currentFilter === tab.value }"
@click="currentFilter = tab.value"
>
{{ tab.label }}
</view>
</view>
</view>
</view>
<view class="exception-list">
<view
v-for="exception in filteredExceptions"
:key="exception.id"
class="exception-item"
:class="{ 'pending': exception.status === 'pending', 'resolved': exception.status === 'resolved' }"
@click="viewExceptionDetail(exception.id)"
>
<view class="exception-header">
<view class="exception-title">{{ exception.title }}</view>
<view class="exception-status">{{ getStatusText(exception.status) }}</view>
</view>
<view class="exception-content">
<view class="exception-desc">{{ exception.description }}</view>
<view class="exception-info">
<view class="info-item">
<view class="info-label">订单号</view>
<view class="info-value">{{ exception.orderNo }}</view>
</view>
<view class="info-item">
<view class="info-label">学员信息</view>
<view class="info-value">{{ getMaskedStudentInfo(exception.studentInfo) }}</view>
</view>
<view class="info-item">
<view class="info-label">会员类型</view>
<view class="info-value">{{ exception.memberType }}</view>
</view>
<view class="info-item">
<view class="info-label">订单金额</view>
<view class="info-value">{{ exception.amount }}</view>
</view>
<view class="info-item">
<view class="info-label">异常时间</view>
<view class="info-value">{{ exception.createTime }}</view>
</view>
</view>
</view>
<view class="exception-actions">
<view
v-if="exception.status === 'pending'"
class="action-btn primary"
@click.stop="resolveException(exception.id)"
>
处理
</view>
<view
class="action-btn secondary"
@click.stop="viewExceptionDetail(exception.id)"
>
详情
</view>
</view>
</view>
<view v-if="filteredExceptions.length === 0" class="empty-state">
<view class="empty-icon">🛒</view>
<view class="empty-text">暂无相关异常</view>
</view>
</view>
</view>
<!-- 操作提示 -->
<view class="tips-section">
<view class="tips-title">操作提示</view>
<view class="tips-content">
<view class="tip-item"> 会员订单异常可能包括支付失败系统错误等情况</view>
<view class="tip-item"> 处理异常后系统会自动重试订单处理</view>
<view class="tip-item"> 如遇持续异常请联系平台客服</view>
<view class="tip-item"> 学员信息已脱敏处理保护隐私安全</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
// 异常统计
const exceptionStats = ref({
total: 5,
pending: 3,
resolved: 2
})
// 异常列表
const exceptions = ref([
{
id: 1,
title: '支付失败',
description: '会员订单支付失败,请检查支付状态',
orderNo: 'M202601290001',
studentInfo: {
name: '张**',
phone: '138****1234'
},
memberType: '年度会员',
amount: 299.00,
status: 'pending',
createTime: '2026-01-29 10:45:30'
},
{
id: 2,
title: '系统错误',
description: '会员订单处理时系统错误,请重试',
orderNo: 'M202601290002',
studentInfo: {
name: '李**',
phone: '139****5678'
},
memberType: '季度会员',
amount: 99.00,
status: 'pending',
createTime: '2026-01-29 09:30:15'
},
{
id: 3,
title: '支付超时',
description: '会员订单支付超时,请重新发起支付',
orderNo: 'M202601290003',
studentInfo: {
name: '王**',
phone: '137****9012'
},
memberType: '月度会员',
amount: 39.00,
status: 'pending',
createTime: '2026-01-29 08:15:45'
},
{
id: 4,
title: '支付失败',
description: '会员订单支付失败,请检查支付状态',
orderNo: 'M202601280004',
studentInfo: {
name: '刘**',
phone: '136****3456'
},
memberType: '年度会员',
amount: 299.00,
status: 'resolved',
createTime: '2026-01-28 16:20:30'
},
{
id: 5,
title: '系统错误',
description: '会员订单处理时系统错误,请重试',
orderNo: 'M202601280005',
studentInfo: {
name: '陈**',
phone: '135****7890'
},
memberType: '季度会员',
amount: 99.00,
status: 'resolved',
createTime: '2026-01-28 14:10:15'
}
])
// 过滤标签
const filterTabs = ref([
{ label: '全部', value: 'all' },
{ label: '待处理', value: 'pending' },
{ label: '已解决', value: 'resolved' }
])
const currentFilter = ref('all')
// 过滤后的异常列表
const filteredExceptions = computed(() => {
if (currentFilter.value === 'all') {
return exceptions.value
}
return exceptions.value.filter(exception => exception.status === currentFilter.value)
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 刷新数据
function refreshData() {
uni.showLoading({ title: '刷新中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '刷新成功', icon: 'success' })
}, 1000)
}
// 获取状态文本
function getStatusText(status) {
switch (status) {
case 'pending':
return '待处理'
case 'resolved':
return '已解决'
default:
return '未知'
}
}
// 获取脱敏学员信息
function getMaskedStudentInfo(studentInfo) {
return `${studentInfo.name} ${studentInfo.phone}`
}
// 查看异常详情
function viewExceptionDetail(exceptionId) {
uni.navigateTo({
url: `/pages/exception/member-order-detail?id=${exceptionId}`
})
}
// 处理异常
function resolveException(exceptionId) {
uni.showModal({
title: '处理异常',
content: '是否确认处理该异常?\n\n处理后系统会自动重试订单处理',
success: function(res) {
if (res.confirm) {
uni.showLoading({ title: '处理中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '处理成功', icon: 'success' })
// 更新异常状态
const exception = exceptions.value.find(e => e.id === exceptionId)
if (exception) {
exception.status = 'resolved'
// 更新统计数据
exceptionStats.value.pending--
exceptionStats.value.resolved++
}
}, 1500)
}
}
})
}
onMounted(() => {
// 实际项目中应从接口获取异常数据
// fetchExceptionData()
})
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.member-order-exception-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.refresh-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 异常统计 */
.stats-section {
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.stats-grid {
display: flex;
justify-content: space-between;
gap: 16rpx;
}
.stat-card {
flex: 1;
display: flex;
align-items: center;
padding: 24rpx;
background-color: #f9f9f9;
border-radius: 12rpx;
}
.stat-icon {
font-size: 48rpx;
margin-right: 24rpx;
}
.stat-content {
flex: 1;
}
.stat-value {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 24rpx;
color: #606266;
}
/* 异常列表 */
.exception-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
line-height: 1.2;
}
.filter-tabs {
display: flex;
gap: 16rpx;
}
.filter-tab {
padding: 12rpx 24rpx;
background-color: #f9f9f9;
border-radius: 8rpx;
font-size: 24rpx;
color: #606266;
cursor: pointer;
}
.filter-tab.active {
background-color: #409eff;
color: #fff;
}
.exception-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.exception-item {
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
transition: all 0.3s ease;
}
.exception-item.pending {
border-left: 8rpx solid #f56c6c;
}
.exception-item.resolved {
border-left: 8rpx solid #67c23a;
}
.exception-item:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.exception-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.exception-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
.exception-status {
padding: 8rpx 16rpx;
border-radius: 8rpx;
font-size: 20rpx;
font-weight: 600;
}
.exception-item.pending .exception-status {
background-color: #fef0f0;
color: #f56c6c;
}
.exception-item.resolved .exception-status {
background-color: #f0f9eb;
color: #67c23a;
}
.exception-content {
margin-bottom: 20rpx;
}
.exception-desc {
font-size: 24rpx;
color: #606266;
margin-bottom: 16rpx;
line-height: 1.4;
}
.exception-info {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.info-item {
display: flex;
align-items: center;
}
.info-label {
font-size: 22rpx;
color: #909399;
margin-right: 8rpx;
}
.info-value {
font-size: 22rpx;
font-weight: 600;
color: #303133;
}
.exception-actions {
display: flex;
gap: 16rpx;
justify-content: flex-end;
}
.action-btn {
padding: 12rpx 24rpx;
border-radius: 8rpx;
font-size: 24rpx;
font-weight: 600;
cursor: pointer;
}
.action-btn.primary {
background-color: #409eff;
color: #fff;
}
.action-btn.secondary {
background-color: #f9f9f9;
color: #606266;
border: 1rpx solid #e4e7ed;
}
/* 操作提示 */
.tips-section {
padding: 32rpx;
background-color: #ecf5ff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
.tip-item {
margin-bottom: 8rpx;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
text-align: center;
}
.empty-icon {
font-size: 100rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 28rpx;
color: #909399;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.member-order-exception-container {
max-width: 900px;
margin: 0 auto;
}
.stats-section,
.exception-section {
padding: 40rpx;
}
.exception-title {
font-size: 32rpx;
}
.exception-desc {
font-size: 28rpx;
}
.info-item {
font-size: 24rpx;
}
}
</style>

View File

@@ -0,0 +1,606 @@
<template>
<view class="profit-exception-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">分润异常提醒</view>
<view class="header-right" @click="refreshData">
<view class="refresh-btn">刷新</view>
</view>
</view>
<!-- 异常统计 -->
<view class="stats-section">
<view class="stats-grid">
<view class="stat-card">
<view class="stat-icon">💰</view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.total }}</view>
<view class="stat-label">总异常数</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.pending }}</view>
<view class="stat-label">待处理</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<view class="stat-value">{{ exceptionStats.resolved }}</view>
<view class="stat-label">已解决</view>
</view>
</view>
</view>
</view>
<!-- 异常列表 -->
<view class="exception-section">
<view class="section-header">
<view class="section-title">异常列表</view>
<view class="filter-box">
<view class="filter-tabs">
<view
v-for="tab in filterTabs"
:key="tab.value"
class="filter-tab"
:class="{ active: currentFilter === tab.value }"
@click="currentFilter = tab.value"
>
{{ tab.label }}
</view>
</view>
</view>
</view>
<view class="exception-list">
<view
v-for="exception in filteredExceptions"
:key="exception.id"
class="exception-item"
:class="{ 'pending': exception.status === 'pending', 'resolved': exception.status === 'resolved' }"
@click="viewExceptionDetail(exception.id)"
>
<view class="exception-header">
<view class="exception-title">{{ exception.title }}</view>
<view class="exception-status">{{ getStatusText(exception.status) }}</view>
</view>
<view class="exception-content">
<view class="exception-desc">{{ exception.description }}</view>
<view class="exception-info">
<view class="info-item">
<view class="info-label">关联账户</view>
<view class="info-value">{{ exception.accountName }}</view>
</view>
<view class="info-item">
<view class="info-label">异常金额</view>
<view class="info-value">{{ exception.amount }}</view>
</view>
<view class="info-item">
<view class="info-label">异常时间</view>
<view class="info-value">{{ exception.createTime }}</view>
</view>
</view>
</view>
<view class="exception-actions">
<view
v-if="exception.status === 'pending'"
class="action-btn primary"
@click.stop="resolveException(exception.id)"
>
处理
</view>
<view
class="action-btn secondary"
@click.stop="viewExceptionDetail(exception.id)"
>
详情
</view>
</view>
</view>
<view v-if="filteredExceptions.length === 0" class="empty-state">
<view class="empty-icon">📭</view>
<view class="empty-text">暂无相关异常</view>
</view>
</view>
</view>
<!-- 操作提示 -->
<view class="tips-section">
<view class="tips-title">操作提示</view>
<view class="tips-content">
<view class="tip-item"> 账户余额不足时系统会暂停分润发放</view>
<view class="tip-item"> 请及时充值以确保分润正常发放</view>
<view class="tip-item"> 处理异常后系统会自动重试分润发放</view>
<view class="tip-item"> 如遇持续异常请联系平台客服</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
// 异常统计
const exceptionStats = ref({
total: 5,
pending: 2,
resolved: 3
})
// 异常列表
const exceptions = ref([
{
id: 1,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 1250.00,
status: 'pending',
createTime: '2026-01-29 10:15:30'
},
{
id: 2,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 890.50,
status: 'pending',
createTime: '2026-01-29 09:45:12'
},
{
id: 3,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 678.20,
status: 'resolved',
createTime: '2026-01-28 16:30:45'
},
{
id: 4,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 1560.80,
status: 'resolved',
createTime: '2026-01-28 14:20:18'
},
{
id: 5,
title: '账户余额不足',
description: '驾校账户余额不足,无法发放分销员分润',
accountName: '顺达驾校',
amount: 980.00,
status: 'resolved',
createTime: '2026-01-28 11:05:33'
}
])
// 过滤标签
const filterTabs = ref([
{ label: '全部', value: 'all' },
{ label: '待处理', value: 'pending' },
{ label: '已解决', value: 'resolved' }
])
const currentFilter = ref('all')
// 过滤后的异常列表
const filteredExceptions = computed(() => {
if (currentFilter.value === 'all') {
return exceptions.value
}
return exceptions.value.filter(exception => exception.status === currentFilter.value)
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 刷新数据
function refreshData() {
uni.showLoading({ title: '刷新中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '刷新成功', icon: 'success' })
}, 1000)
}
// 获取状态文本
function getStatusText(status) {
switch (status) {
case 'pending':
return '待处理'
case 'resolved':
return '已解决'
default:
return '未知'
}
}
// 查看异常详情
function viewExceptionDetail(exceptionId) {
uni.navigateTo({
url: `/pages/exception/profit-detail?id=${exceptionId}`
})
}
// 处理异常
function resolveException(exceptionId) {
uni.showModal({
title: '处理异常',
content: '是否确认处理该异常?\n\n处理后系统会自动重试分润发放',
success: function(res) {
if (res.confirm) {
uni.showLoading({ title: '处理中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '处理成功', icon: 'success' })
// 更新异常状态
const exception = exceptions.value.find(e => e.id === exceptionId)
if (exception) {
exception.status = 'resolved'
// 更新统计数据
exceptionStats.value.pending--
exceptionStats.value.resolved++
}
}, 1500)
}
}
})
}
onMounted(() => {
// 实际项目中应从接口获取异常数据
// fetchExceptionData()
})
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.profit-exception-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.refresh-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 异常统计 */
.stats-section {
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.stats-grid {
display: flex;
justify-content: space-between;
gap: 16rpx;
}
.stat-card {
flex: 1;
display: flex;
align-items: center;
padding: 24rpx;
background-color: #f9f9f9;
border-radius: 12rpx;
}
.stat-icon {
font-size: 48rpx;
margin-right: 24rpx;
}
.stat-content {
flex: 1;
}
.stat-value {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 24rpx;
color: #606266;
}
/* 异常列表 */
.exception-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
line-height: 1.2;
}
.filter-tabs {
display: flex;
gap: 16rpx;
}
.filter-tab {
padding: 12rpx 24rpx;
background-color: #f9f9f9;
border-radius: 8rpx;
font-size: 24rpx;
color: #606266;
cursor: pointer;
}
.filter-tab.active {
background-color: #409eff;
color: #fff;
}
.exception-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.exception-item {
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
transition: all 0.3s ease;
}
.exception-item.pending {
border-left: 8rpx solid #f56c6c;
}
.exception-item.resolved {
border-left: 8rpx solid #67c23a;
}
.exception-item:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.exception-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.exception-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
.exception-status {
padding: 8rpx 16rpx;
border-radius: 8rpx;
font-size: 20rpx;
font-weight: 600;
}
.exception-item.pending .exception-status {
background-color: #fef0f0;
color: #f56c6c;
}
.exception-item.resolved .exception-status {
background-color: #f0f9eb;
color: #67c23a;
}
.exception-content {
margin-bottom: 20rpx;
}
.exception-desc {
font-size: 24rpx;
color: #606266;
margin-bottom: 16rpx;
line-height: 1.4;
}
.exception-info {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.info-item {
display: flex;
align-items: center;
}
.info-label {
font-size: 22rpx;
color: #909399;
margin-right: 8rpx;
}
.info-value {
font-size: 22rpx;
font-weight: 600;
color: #303133;
}
.exception-actions {
display: flex;
gap: 16rpx;
justify-content: flex-end;
}
.action-btn {
padding: 12rpx 24rpx;
border-radius: 8rpx;
font-size: 24rpx;
font-weight: 600;
cursor: pointer;
}
.action-btn.primary {
background-color: #409eff;
color: #fff;
}
.action-btn.secondary {
background-color: #f9f9f9;
color: #606266;
border: 1rpx solid #e4e7ed;
}
/* 操作提示 */
.tips-section {
padding: 32rpx;
background-color: #ecf5ff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
.tip-item {
margin-bottom: 8rpx;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
text-align: center;
}
.empty-icon {
font-size: 100rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 28rpx;
color: #909399;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.profit-exception-container {
max-width: 900px;
margin: 0 auto;
}
.stats-section,
.exception-section {
padding: 40rpx;
}
.exception-title {
font-size: 32rpx;
}
.exception-desc {
font-size: 28rpx;
}
.info-item {
font-size: 24rpx;
}
}
</style>

View File

@@ -1,36 +1,575 @@
<template>
<view class="content">
<image class="logo" src="@/static/logo.png"></image>
<view class="text-area">
<text class="title">Hello RuoYi</text>
<view class="index-container">
<!-- 欢迎信息 -->
<view class="welcome-section">
<view class="welcome-title">欢迎使用小程序管理系统</view>
<view class="welcome-desc">
<text v-if="userRole === 'admin'">管理员视图</text>
<text v-else>分销员视图</text>
</view>
</view>
<!-- 管理员统计功能 -->
<view v-if="userRole === 'admin'" class="stats-section">
<!-- 核心数据概览 -->
<view class="section">
<view class="section-title">核心数据概览</view>
<view class="stats-grid">
<view class="stat-card" @click="goToDistributionStats">
<view class="stat-icon">📊</view>
<view class="stat-content">
<view class="stat-value">{{ distributionStats.totalProfit }}</view>
<view class="stat-label">分润总额</view>
</view>
</view>
<view class="stat-card" @click="goToMemberStats">
<view class="stat-icon">👥</view>
<view class="stat-content">
<view class="stat-value">{{ memberStats.totalOrders }}</view>
<view class="stat-label">会员订单</view>
</view>
</view>
<view class="stat-card" @click="goToStudentStats">
<view class="stat-icon">🎓</view>
<view class="stat-content">
<view class="stat-value">{{ studentStats.totalStudents }}</view>
<view class="stat-label">学员总数</view>
</view>
</view>
<view class="stat-card" @click="goToDistributionStats">
<view class="stat-icon">📈</view>
<view class="stat-content">
<view class="stat-value">{{ distributionStats.scanCount }}</view>
<view class="stat-label">扫码数</view>
</view>
</view>
</view>
</view>
<!-- 分销业绩统计 -->
<view class="section">
<view class="section-title">分销业绩统计</view>
<view class="feature-card" @click="goToDistributionStats">
<view class="feature-icon distributor-icon">
<view class="icon-text">📈</view>
</view>
<view class="feature-info">
<view class="feature-title">分销业绩统计</view>
<view class="feature-desc">查看业绩汇总排行多维度筛选</view>
</view>
</view>
</view>
<!-- 会员运营统计 -->
<view class="section">
<view class="section-title">会员运营统计</view>
<view class="feature-card" @click="goToMemberStats">
<view class="feature-icon user-icon">
<view class="icon-text">👥</view>
</view>
<view class="feature-info">
<view class="feature-title">会员运营统计</view>
<view class="feature-desc">查看订单总数金额各类型占比</view>
</view>
</view>
</view>
<!-- 学员学情统计 -->
<view class="section">
<view class="section-title">学员学情统计</view>
<view class="feature-card" @click="goToStudentStats">
<view class="feature-icon notice-icon">
<view class="icon-text">🎓</view>
</view>
<view class="feature-info">
<view class="feature-title">学员学情统计</view>
<view class="feature-desc">查看学员总数正确率模考平均分</view>
</view>
</view>
</view>
</view>
<!-- 分销员统计功能 -->
<view v-else-if="userRole === 'distributor'" class="stats-section">
<!-- 个人核心数据 -->
<view class="section">
<view class="section-title">个人核心数据</view>
<view class="stats-grid">
<view class="stat-card">
<view class="stat-icon">📱</view>
<view class="stat-content">
<view class="stat-value">{{ personalStats.scanCount }}</view>
<view class="stat-label">扫码数</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon">👥</view>
<view class="stat-content">
<view class="stat-value">{{ personalStats.paidCount }}</view>
<view class="stat-label">付费人数</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon">📈</view>
<view class="stat-content">
<view class="stat-value">{{ personalStats.conversionRate }}%</view>
<view class="stat-label">转化率</view>
</view>
</view>
<view class="stat-card">
<view class="stat-icon">💰</view>
<view class="stat-content">
<view class="stat-value">{{ personalStats.totalProfit }}</view>
<view class="stat-label">提成总额</view>
</view>
</view>
</view>
</view>
<!-- 个人业绩统计 -->
<view class="section">
<view class="section-title">个人业绩统计</view>
<view class="feature-card" @click="goToPersonalStats">
<view class="feature-icon distributor-icon">
<view class="icon-text">📊</view>
</view>
<view class="feature-info">
<view class="feature-title">个人业绩统计</view>
<view class="feature-desc">查看核心数据近7天趋势</view>
</view>
</view>
</view>
<!-- 数据分享 -->
<view class="section">
<view class="section-title">数据分享</view>
<view class="feature-card" @click="shareData">
<view class="feature-icon user-icon">
<view class="icon-text">📱</view>
</view>
<view class="feature-info">
<view class="feature-title">数据分享</view>
<view class="feature-desc">生成业绩数据图片一键分享</view>
</view>
</view>
</view>
</view>
</view>
</template>
<style scoped>
.content {
<script setup>
import { ref, getCurrentInstance, onMounted } from "vue"
const { proxy } = getCurrentInstance()
const userRole = ref('admin') // 模拟角色,实际应从登录状态获取
// 模拟统计数据
const distributionStats = ref({
totalProfit: '¥12,345.67',
scanCount: 1234,
paidCount: 456,
conversionRate: '36.9%'
})
const memberStats = ref({
totalOrders: 789,
totalAmount: '¥89,765.43',
refundRate: '2.1%'
})
const studentStats = ref({
totalStudents: 1234,
memberStudents: 890,
avgCorrectRate: '78.5%',
avgExamScore: '82.3'
})
const personalStats = ref({
scanCount: 123,
paidCount: 45,
conversionRate: 36.9,
totalProfit: '¥1,234.56'
})
onMounted(() => {
// 实际项目中应从登录状态或接口获取用户角色和数据
// userRole.value = getUserRole()
// loadStatsData()
})
// 管理员统计功能跳转
function goToDistributionStats() {
uni.navigateTo({
url: '/pages/stats/distribution'
})
}
function goToMemberStats() {
uni.navigateTo({
url: '/pages/stats/member'
})
}
function goToStudentStats() {
uni.navigateTo({
url: '/pages/stats/student'
})
}
// 分销员统计功能跳转
function goToPersonalStats() {
uni.navigateTo({
url: '/pages/stats/personal'
})
}
function shareData() {
// 生成并分享业绩数据图片
uni.showToast({
title: '生成分享图片中...',
duration: 1500
})
// 模拟生成图片并分享
setTimeout(() => {
uni.showActionSheet({
itemList: ['分享到微信', '分享到朋友圈', '保存图片'],
success: function(res) {
switch(res.tapIndex) {
case 0:
uni.showToast({ title: '分享到微信', duration: 1000 })
break
case 1:
uni.showToast({ title: '分享到朋友圈', duration: 1000 })
break
case 2:
uni.showToast({ title: '图片已保存', duration: 1000 })
break
}
}
})
}, 1500)
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.index-container {
padding: 20rpx;
min-height: 100vh;
}
/* 欢迎信息 */
.welcome-section {
background: linear-gradient(135deg, #409eff 0%, #667eea 100%);
border-radius: 20rpx;
padding: 40rpx;
margin-bottom: 30rpx;
color: #fff;
box-shadow: 0 8rpx 32rpx rgba(64, 158, 255, 0.3);
}
.welcome-title {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 12rpx;
line-height: 1.2;
}
.welcome-desc {
font-size: 24rpx;
opacity: 0.9;
line-height: 1.4;
}
/* 统计区域 */
.stats-section {
display: flex;
flex-direction: column;
gap: 30rpx;
}
.section {
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 24rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
/* 统计网格 */
.stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
}
.stat-card {
background-color: #f9f9f9;
border-radius: 12rpx;
padding: 24rpx;
display: flex;
align-items: center;
transition: all 0.3s ease;
cursor: pointer;
}
.stat-card:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.stat-icon {
font-size: 48rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
.stat-content {
flex: 1;
}
.stat-value {
font-size: 28rpx;
font-weight: bold;
color: #303133;
margin-bottom: 4rpx;
line-height: 1.2;
}
.stat-label {
font-size: 20rpx;
color: #909399;
line-height: 1.3;
}
/* 功能卡片样式 */
.feature-card {
display: flex;
align-items: center;
background-color: #f9f9f9;
border-radius: 12rpx;
padding: 24rpx;
transition: all 0.3s ease;
cursor: pointer;
}
.feature-card:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
/* 图标容器 */
.feature-icon {
width: 80rpx;
height: 80rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
flex-shrink: 0;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
/* 各模块颜色 */
.distributor-icon {
background-color: #ecf5ff;
}
.text-area {
display: flex;
justify-content: center;
.user-icon {
background-color: #f0f9eb;
}
.title {
.dept-icon {
background-color: #fdf6ec;
}
.notice-icon {
background-color: #fef0f0;
}
.log-icon {
background-color: #f4f4f5;
}
/* 图标文本样式 */
.icon-text {
font-size: 40rpx;
line-height: 1;
text-align: center;
}
/* 功能信息 */
.feature-info {
flex: 1;
min-width: 0;
}
.feature-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 8rpx;
line-height: 1.3;
}
.feature-desc {
font-size: 22rpx;
color: #909399;
line-height: 1.4;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.index-container {
max-width: 900px;
margin: 0 auto;
padding: 30rpx;
}
.welcome-section {
padding: 50rpx;
}
.welcome-title {
font-size: 44rpx;
}
.welcome-desc {
font-size: 28rpx;
}
.section {
padding: 30rpx;
}
.section-title {
font-size: 36rpx;
color: #8f8f94;
margin-bottom: 30rpx;
}
.stats-grid {
grid-template-columns: repeat(4, 1fr);
gap: 20rpx;
}
.stat-card {
padding: 30rpx;
}
.stat-icon {
font-size: 56rpx;
margin-right: 20rpx;
}
.stat-value {
font-size: 32rpx;
}
.stat-label {
font-size: 24rpx;
}
.feature-card {
padding: 30rpx;
}
.feature-icon {
width: 100rpx;
height: 100rpx;
margin-right: 24rpx;
}
.icon-text {
font-size: 48rpx;
}
.feature-title {
font-size: 32rpx;
}
.feature-desc {
font-size: 24rpx;
}
}
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.index-container {
max-width: 1000px;
}
.welcome-section {
padding: 60rpx;
}
.welcome-title {
font-size: 52rpx;
}
.section {
padding: 36rpx;
}
.stats-grid {
gap: 24rpx;
}
.stat-card {
padding: 36rpx;
}
.stat-icon {
font-size: 64rpx;
}
.stat-value {
font-size: 36rpx;
}
.feature-card {
padding: 36rpx;
}
.feature-icon {
width: 120rpx;
height: 120rpx;
}
.icon-text {
font-size: 56rpx;
}
.feature-title {
font-size: 36rpx;
}
.feature-desc {
font-size: 26rpx;
}
}
</style>

483
src/pages/mine/about-us.vue Normal file
View File

@@ -0,0 +1,483 @@
<template>
<view class="about-us-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">关于我们</view>
<view class="header-right"></view>
</view>
<!-- 公司信息 -->
<view class="company-section">
<view class="company-logo">
<view class="logo-icon">🏢</view>
</view>
<view class="company-info">
<view class="company-name">顺达驾校管理系统</view>
<view class="company-slogan">专业的驾校管理解决方案</view>
</view>
</view>
<!-- 版本信息 -->
<view class="version-section">
<view class="version-item">
<view class="version-label">当前版本</view>
<view class="version-value">{{ appVersion }}</view>
</view>
<view class="version-item">
<view class="version-label">更新时间</view>
<view class="version-value">{{ updateTime }}</view>
</view>
<view class="version-item">
<view class="version-label">系统状态</view>
<view class="version-value">
<view class="status-indicator"></view>
<view class="status-text">运行中</view>
</view>
</view>
</view>
<!-- 功能介绍 -->
<view class="features-section">
<view class="section-title">功能介绍</view>
<view class="features-list">
<view class="feature-item">
<view class="feature-icon">📊</view>
<view class="feature-info">
<view class="feature-title">统计分析</view>
<view class="feature-desc">实时查看驾校运营数据掌握业务动态</view>
</view>
</view>
<view class="feature-item">
<view class="feature-icon">👥</view>
<view class="feature-info">
<view class="feature-title">会员管理</view>
<view class="feature-desc">管理会员信息支持会员赠送和续费</view>
</view>
</view>
<view class="feature-item">
<view class="feature-icon">🎓</view>
<view class="feature-info">
<view class="feature-title">学员管理</view>
<view class="feature-desc">监控学员学习情况提供个性化学习建议</view>
</view>
</view>
<view class="feature-item">
<view class="feature-icon">📈</view>
<view class="feature-info">
<view class="feature-title">分销系统</view>
<view class="feature-desc">支持分销员管理提高驾校招生效率</view>
</view>
</view>
<view class="feature-item">
<view class="feature-icon">🏢</view>
<view class="feature-info">
<view class="feature-title">驾校管理</view>
<view class="feature-desc">管理驾校信息配置自定义字段</view>
</view>
</view>
</view>
</view>
<!-- 联系信息 -->
<view class="contact-section">
<view class="section-title">联系我们</view>
<view class="contact-list">
<view class="contact-item">
<view class="contact-icon">📞</view>
<view class="contact-info">
<view class="contact-label">客服电话</view>
<view class="contact-value">400-123-4567</view>
</view>
</view>
<view class="contact-item">
<view class="contact-icon">📧</view>
<view class="contact-info">
<view class="contact-label">客服邮箱</view>
<view class="contact-value">support@shunda.com</view>
</view>
</view>
<view class="contact-item">
<view class="contact-icon">🌐</view>
<view class="contact-info">
<view class="contact-label">官方网站</view>
<view class="contact-value">www.shunda.com</view>
</view>
</view>
<view class="contact-item">
<view class="contact-icon">📍</view>
<view class="contact-info">
<view class="contact-label">公司地址</view>
<view class="contact-value">北京市朝阳区建国路88号</view>
</view>
</view>
</view>
</view>
<!-- 版权信息 -->
<view class="copyright-section">
<view class="copyright-text">© 2026 顺达驾校管理系统</view>
<view class="copyright-desc">All Rights Reserved</view>
<view class="copyright-policy">
<view class="policy-item" @click="viewPrivacyPolicy">隐私政策</view>
<view class="policy-divider">|</view>
<view class="policy-item" @click="viewTermsOfService">服务条款</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from "vue"
// 应用信息
const appVersion = ref('v1.0.0')
const updateTime = ref('2026-01-29')
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 查看隐私政策
function viewPrivacyPolicy() {
uni.showModal({
title: '隐私政策',
content: '隐私政策详情页面正在开发中',
showCancel: false
})
}
// 查看服务条款
function viewTermsOfService() {
uni.showModal({
title: '服务条款',
content: '服务条款详情页面正在开发中',
showCancel: false
})
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.about-us-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
}
/* 公司信息 */
.company-section {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60rpx 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.company-logo {
width: 160rpx;
height: 160rpx;
border-radius: 80rpx;
background-color: #409eff;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 32rpx;
}
.logo-icon {
font-size: 80rpx;
}
.company-name {
font-size: 36rpx;
font-weight: bold;
color: #303133;
margin-bottom: 16rpx;
}
.company-slogan {
font-size: 24rpx;
color: #606266;
}
/* 版本信息 */
.version-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.version-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #e4e7ed;
}
.version-item:last-child {
border-bottom: none;
}
.version-label {
font-size: 28rpx;
color: #606266;
}
.version-value {
font-size: 28rpx;
font-weight: 600;
color: #303133;
display: flex;
align-items: center;
}
.status-indicator {
width: 12rpx;
height: 12rpx;
border-radius: 6rpx;
background-color: #67c23a;
margin-right: 8rpx;
}
.status-text {
color: #67c23a;
}
/* 功能介绍 */
.features-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 32rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
.features-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300rpx, 1fr));
gap: 24rpx;
}
.feature-item {
display: flex;
align-items: flex-start;
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
}
.feature-icon {
font-size: 40rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
.feature-info {
flex: 1;
}
.feature-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 8rpx;
line-height: 1.2;
}
.feature-desc {
font-size: 24rpx;
color: #606266;
line-height: 1.4;
}
/* 联系信息 */
.contact-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.contact-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.contact-item {
display: flex;
align-items: center;
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
}
.contact-icon {
font-size: 40rpx;
margin-right: 24rpx;
flex-shrink: 0;
}
.contact-info {
flex: 1;
}
.contact-label {
font-size: 24rpx;
color: #606266;
margin-bottom: 4rpx;
}
.contact-value {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
/* 版权信息 */
.copyright-section {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40rpx 32rpx;
background-color: #f0f2f5;
margin-top: auto;
}
.copyright-text {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 8rpx;
}
.copyright-desc {
font-size: 24rpx;
color: #606266;
margin-bottom: 24rpx;
}
.copyright-policy {
display: flex;
align-items: center;
gap: 24rpx;
}
.policy-item {
font-size: 24rpx;
color: #409eff;
cursor: pointer;
}
.policy-divider {
font-size: 24rpx;
color: #909399;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.about-us-container {
max-width: 900px;
margin: 0 auto;
}
.company-section {
padding: 80rpx 40rpx;
}
.company-name {
font-size: 40rpx;
}
.company-slogan {
font-size: 28rpx;
}
.features-list {
grid-template-columns: repeat(auto-fill, minmax(400rpx, 1fr));
}
.feature-title {
font-size: 32rpx;
}
.feature-desc {
font-size: 28rpx;
}
.contact-value {
font-size: 32rpx;
}
}
</style>

View File

@@ -0,0 +1,620 @@
<template>
<view class="custom-fields-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">自定义字段配置</view>
<view class="header-right" @click="saveFields">
<view class="save-btn">保存</view>
</view>
</view>
<!-- 字段列表 -->
<view class="fields-section">
<view class="section-header">
<view class="section-title">本驾校专属自定义字段</view>
<view class="add-btn" @click="addField">
<view class="add-icon">+</view>
<view class="add-text">添加字段</view>
</view>
</view>
<view class="fields-list">
<view v-for="(field, index) in customFields" :key="field.id" class="field-item">
<view class="field-header">
<view class="field-title">字段 {{ index + 1 }}</view>
<view class="field-actions">
<view class="action-btn up-btn" @click="moveField(index, 'up')" :class="{ disabled: index === 0 }">
</view>
<view class="action-btn down-btn" @click="moveField(index, 'down')" :class="{ disabled: index === customFields.length - 1 }">
</view>
<view class="action-btn delete-btn" @click="deleteField(index)">
×
</view>
</view>
</view>
<view class="field-form">
<view class="form-group">
<view class="form-label">字段名称</view>
<view class="form-control">
<input
v-model="field.name"
class="form-input"
placeholder="请输入字段名称"
maxlength="20"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">字段类型</view>
<view class="form-control">
<picker
v-model="field.type"
:range="fieldTypes"
:range-key="'label'"
class="form-picker"
>
<view class="picker-display">{{ getFieldTypeName(field.type) }}</view>
</picker>
</view>
</view>
<view class="form-group" v-if="field.type === 'select'">
<view class="form-label">选项值</view>
<view class="form-control">
<textarea
v-model="field.options"
class="form-textarea"
placeholder="请输入选项值,多个选项用逗号分隔"
maxlength="200"
rows="2"
></textarea>
</view>
</view>
<view class="form-group">
<view class="form-label">是否必填</view>
<view class="form-control">
<switch
v-model="field.required"
class="form-switch"
active-color="#409eff"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">字段描述</view>
<view class="form-control">
<input
v-model="field.description"
class="form-input"
placeholder="请输入字段描述"
maxlength="100"
/>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 筛选规则配置 -->
<view class="rules-section">
<view class="section-title">筛选规则配置</view>
<view class="rules-content">
<view class="rule-item">
<view class="rule-label">启用字段筛选</view>
<view class="rule-control">
<switch
v-model="filterRules.enabled"
class="form-switch"
active-color="#409eff"
/>
</view>
</view>
<view class="rule-item">
<view class="rule-label">默认显示字段</view>
<view class="rule-control">
<picker
v-model="filterRules.defaultFields"
:range="availableFields"
:range-key="'name'"
mode="multiSelector"
class="form-picker"
>
<view class="picker-display">
{{ filterRules.defaultFields.length }} 个字段
</view>
</picker>
</view>
</view>
</view>
</view>
<!-- 提示信息 -->
<view class="tips-section">
<view class="tips-title">注意事项</view>
<view class="tips-content">
<view class="tip-item"> 自定义字段仅在本驾校生效</view>
<view class="tip-item"> 字段类型包括文本数字日期下拉选择</view>
<view class="tip-item"> 下拉选择类型需要配置选项值</view>
<view class="tip-item"> 修改配置后需点击保存按钮生效</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
// 字段类型选项
const fieldTypes = ref([
{ value: 'text', label: '文本' },
{ value: 'number', label: '数字' },
{ value: 'date', label: '日期' },
{ value: 'select', label: '下拉选择' }
])
// 自定义字段列表
const customFields = ref([
{
id: 1,
name: '学员来源渠道',
type: 'select',
options: '朋友介绍,网络推广,线下广告,其他',
required: false,
description: '记录学员的来源渠道'
},
{
id: 2,
name: '报名时间',
type: 'date',
required: true,
description: '学员报名的具体时间'
}
])
// 筛选规则
const filterRules = ref({
enabled: true,
defaultFields: [0, 1]
})
// 计算可用字段
const availableFields = computed(() => {
return customFields.value.map((field, index) => ({
id: field.id,
name: field.name
}))
})
onMounted(() => {
// 实际项目中应从接口获取自定义字段配置
// loadCustomFields()
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 获取字段类型名称
function getFieldTypeName(type) {
const fieldType = fieldTypes.value.find(item => item.value === type)
return fieldType ? fieldType.label : '请选择'
}
// 添加字段
function addField() {
const newField = {
id: Date.now(),
name: '',
type: 'text',
required: false,
description: ''
}
customFields.value.push(newField)
}
// 删除字段
function deleteField(index) {
uni.showModal({
title: '删除字段',
content: '确定要删除这个字段吗?',
success: function(res) {
if (res.confirm) {
customFields.value.splice(index, 1)
}
}
})
}
// 移动字段
function moveField(index, direction) {
if (direction === 'up' && index > 0) {
const temp = customFields.value[index]
customFields.value[index] = customFields.value[index - 1]
customFields.value[index - 1] = temp
} else if (direction === 'down' && index < customFields.value.length - 1) {
const temp = customFields.value[index]
customFields.value[index] = customFields.value[index + 1]
customFields.value[index + 1] = temp
}
}
// 保存字段配置
function saveFields() {
// 表单验证
const emptyFields = customFields.value.filter(field => !field.name)
if (emptyFields.length > 0) {
uni.showToast({ title: '请填写所有字段名称', icon: 'none' })
return
}
// 实际项目中应调用接口保存配置
uni.showLoading({ title: '保存中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '保存成功', icon: 'success' })
goBack()
}, 1000)
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.custom-fields-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.save-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 字段列表 */
.fields-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
line-height: 1.2;
}
.add-btn {
display: flex;
align-items: center;
padding: 12rpx 24rpx;
background-color: #409eff;
color: #fff;
border-radius: 8rpx;
cursor: pointer;
font-size: 24rpx;
}
.add-icon {
margin-right: 8rpx;
font-size: 28rpx;
}
.fields-list {
display: flex;
flex-direction: column;
gap: 32rpx;
}
.field-item {
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
}
.field-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.field-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
.field-actions {
display: flex;
gap: 12rpx;
}
.action-btn {
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: #e4e7ed;
color: #606266;
cursor: pointer;
font-size: 24rpx;
}
.action-btn:hover {
background-color: #c0c4cc;
}
.action-btn.disabled {
opacity: 0.5;
cursor: not-allowed;
}
.delete-btn {
background-color: #fef0f0;
color: #f56c6c;
}
.delete-btn:hover {
background-color: #fde2e2;
}
/* 字段表单 */
.field-form {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.form-group {
display: flex;
flex-direction: column;
}
.form-label {
font-size: 24rpx;
font-weight: 600;
color: #606266;
margin-bottom: 8rpx;
line-height: 1.2;
}
.form-control {
position: relative;
}
.form-input {
width: 100%;
height: 60rpx;
padding: 0 20rpx;
font-size: 24rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 6rpx;
background-color: #fff;
box-sizing: border-box;
}
.form-input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.form-textarea {
width: 100%;
min-height: 120rpx;
padding: 16rpx;
font-size: 24rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 6rpx;
background-color: #fff;
box-sizing: border-box;
resize: none;
}
.form-textarea:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.form-picker {
width: 100%;
height: 60rpx;
border: 1rpx solid #dcdfe6;
border-radius: 6rpx;
background-color: #fff;
box-sizing: border-box;
}
.picker-display {
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 0 20rpx;
font-size: 24rpx;
color: #303133;
}
.form-switch {
transform: scale(1.2);
}
/* 筛选规则 */
.rules-section {
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.rules-content {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.rule-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #e4e7ed;
}
.rule-item:last-child {
border-bottom: none;
}
.rule-label {
font-size: 28rpx;
color: #303133;
flex: 1;
}
.rule-control {
flex-shrink: 0;
}
/* 提示信息 */
.tips-section {
padding: 32rpx;
background-color: #ecf5ff;
margin: 16rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
.tip-item {
margin-bottom: 8rpx;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.custom-fields-container {
max-width: 900px;
margin: 0 auto;
}
.fields-section {
padding: 40rpx;
}
.field-item {
padding: 32rpx;
}
.form-input {
height: 80rpx;
font-size: 28rpx;
padding: 0 24rpx;
}
.form-textarea {
min-height: 160rpx;
font-size: 28rpx;
padding: 20rpx;
}
.rules-section {
padding: 40rpx;
}
.tips-section {
padding: 40rpx;
}
}
</style>

View File

@@ -0,0 +1,646 @@
<template>
<view class="data-logs-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">数据相关</view>
<view class="header-right"></view>
</view>
<!-- 标签切换 -->
<view class="tab-container">
<view class="tab-item" :class="{ active: activeTab === 'logs' }" @click="switchTab('logs')">
操作日志
</view>
<view class="tab-item" :class="{ active: activeTab === 'backup' }" @click="switchTab('backup')">
数据备份记录
</view>
</view>
<!-- 操作日志 -->
<view v-if="activeTab === 'logs'" class="logs-section">
<view class="section-header">
<view class="section-title">操作日志记录</view>
<view class="search-box">
<input
v-model="logSearch"
class="search-input"
placeholder="搜索操作内容或操作人"
/>
</view>
</view>
<view class="logs-list">
<view v-for="log in filteredLogs" :key="log.id" class="log-item">
<view class="log-header">
<view class="log-actor">{{ log.actor }}</view>
<view class="log-time">{{ log.time }}</view>
</view>
<view class="log-content">{{ log.content }}</view>
<view class="log-ip">{{ log.ip }}</view>
</view>
<view v-if="filteredLogs.length === 0" class="empty-state">
<view class="empty-icon">📋</view>
<view class="empty-text">暂无操作日志</view>
</view>
</view>
<!-- 分页 -->
<view v-if="filteredLogs.length > 0" class="pagination">
<view class="page-info">
{{ filteredLogs.length }} 条记录
</view>
<view class="page-controls">
<view class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
上一页
</view>
<view class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
下一页
</view>
</view>
</view>
</view>
<!-- 数据备份记录 -->
<view v-else class="backup-section">
<view class="section-header">
<view class="section-title">数据备份记录</view>
<view class="backup-info">
<view class="info-text">备份操作由平台控制</view>
</view>
</view>
<view class="backup-list">
<view v-for="backup in backupRecords" :key="backup.id" class="backup-item">
<view class="backup-header">
<view class="backup-time">{{ backup.time }}</view>
<view class="backup-status" :class="backup.status">
{{ backup.statusText }}
</view>
</view>
<view class="backup-details">
<view class="detail-item">
<view class="detail-label">备份类型</view>
<view class="detail-value">{{ backup.type }}</view>
</view>
<view class="detail-item">
<view class="detail-label">备份大小</view>
<view class="detail-value">{{ backup.size }}</view>
</view>
<view class="detail-item">
<view class="detail-label">备份文件</view>
<view class="detail-value">{{ backup.fileName }}</view>
</view>
<view class="detail-item">
<view class="detail-label">操作人</view>
<view class="detail-value">{{ backup.operator }}</view>
</view>
</view>
<view class="backup-actions">
<view class="action-btn view-btn" @click="viewBackup(backup.id)">
查看详情
</view>
</view>
</view>
<view v-if="backupRecords.length === 0" class="empty-state">
<view class="empty-icon">💾</view>
<view class="empty-text">暂无备份记录</view>
</view>
</view>
</view>
<!-- 提示信息 -->
<view class="tips-section">
<view class="tips-title">注意事项</view>
<view class="tips-content">
<view class="tip-item"> 操作日志仅记录核心操作保留最近30天记录</view>
<view class="tip-item"> 数据备份由平台自动执行不可手动操作</view>
<view class="tip-item"> 备份文件仅可查看详情不可下载或恢复</view>
<view class="tip-item"> 如有特殊备份需求请联系平台管理员</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
// 标签切换
const activeTab = ref('logs')
// 操作日志相关
const logSearch = ref('')
const currentPage = ref(1)
const pageSize = ref(10)
// 模拟操作日志数据
const logs = ref([
{
id: 1,
actor: '张校长',
time: '2026-01-29 10:30:45',
content: '修改了驾校信息',
ip: '192.168.1.100'
},
{
id: 2,
actor: '系统管理员',
time: '2026-01-29 09:15:30',
content: '创建了新的分销员账号',
ip: '192.168.1.200'
},
{
id: 3,
actor: '张校长',
time: '2026-01-28 16:45:12',
content: '配置了分润规则',
ip: '192.168.1.100'
},
{
id: 4,
actor: '分销员-李教练',
time: '2026-01-28 14:20:05',
content: '生成了推广二维码',
ip: '192.168.1.150'
},
{
id: 5,
actor: '系统',
time: '2026-01-28 00:00:00',
content: '自动执行数据备份',
ip: '127.0.0.1'
}
])
// 模拟备份记录数据
const backupRecords = ref([
{
id: 1,
time: '2026-01-29 00:00:00',
status: 'success',
statusText: '备份成功',
type: '自动备份',
size: '128 MB',
fileName: 'backup_20260129000000.sql',
operator: '系统自动'
},
{
id: 2,
time: '2026-01-28 00:00:00',
status: 'success',
statusText: '备份成功',
type: '自动备份',
size: '125 MB',
fileName: 'backup_20260128000000.sql',
operator: '系统自动'
},
{
id: 3,
time: '2026-01-27 00:00:00',
status: 'success',
statusText: '备份成功',
type: '自动备份',
size: '122 MB',
fileName: 'backup_20260127000000.sql',
operator: '系统自动'
},
{
id: 4,
time: '2026-01-26 10:00:00',
status: 'success',
statusText: '备份成功',
type: '手动备份',
size: '120 MB',
fileName: 'backup_20260126100000.sql',
operator: '平台管理员'
}
])
// 计算过滤后的日志
const filteredLogs = computed(() => {
if (!logSearch.value) {
return logs.value
}
return logs.value.filter(log => {
return log.actor.includes(logSearch.value) || log.content.includes(logSearch.value)
})
})
// 计算总页数
const totalPages = computed(() => {
return Math.ceil(filteredLogs.value.length / pageSize.value)
})
onMounted(() => {
// 实际项目中应从接口获取操作日志和备份记录
// loadOperationLogs()
// loadBackupRecords()
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 切换标签
function switchTab(tab) {
activeTab.value = tab
}
// 上一页
function prevPage() {
if (currentPage.value > 1) {
currentPage.value--
}
}
// 下一页
function nextPage() {
if (currentPage.value < totalPages.value) {
currentPage.value++
}
}
// 查看备份详情
function viewBackup(backupId) {
uni.showModal({
title: '备份详情',
content: '备份详情查看功能正在开发中',
showCancel: false
})
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.data-logs-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
}
/* 标签切换 */
.tab-container {
display: flex;
background-color: #fff;
margin: 16rpx;
border-radius: 12rpx;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.tab-item {
flex: 1;
padding: 24rpx;
text-align: center;
font-size: 28rpx;
color: #606266;
cursor: pointer;
transition: all 0.3s ease;
}
.tab-item.active {
background-color: #409eff;
color: #fff;
font-weight: 600;
}
/* 日志和备份通用样式 */
.logs-section,
.backup-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
line-height: 1.2;
}
/* 搜索框 */
.search-box {
flex-shrink: 0;
}
.search-input {
width: 300rpx;
height: 60rpx;
padding: 0 24rpx;
background-color: #f9f9f9;
border: 1rpx solid #dcdfe6;
border-radius: 30rpx;
font-size: 24rpx;
color: #303133;
}
/* 操作日志 */
.logs-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.log-item {
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
}
.log-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
}
.log-actor {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
.log-time {
font-size: 24rpx;
color: #909399;
}
.log-content {
font-size: 26rpx;
color: #606266;
margin-bottom: 12rpx;
line-height: 1.4;
}
.log-ip {
font-size: 24rpx;
color: #909399;
}
/* 数据备份 */
.backup-info {
flex-shrink: 0;
}
.info-text {
font-size: 24rpx;
color: #f56c6c;
padding: 8rpx 16rpx;
background-color: #fef0f0;
border-radius: 8rpx;
}
.backup-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.backup-item {
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
}
.backup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.backup-time {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
.backup-status {
padding: 4rpx 16rpx;
border-radius: 12rpx;
font-size: 22rpx;
font-weight: 600;
}
.backup-status.success {
background-color: #f0f9eb;
color: #67c23a;
}
.backup-status.failed {
background-color: #fef0f0;
color: #f56c6c;
}
.backup-details {
margin-bottom: 20rpx;
}
.detail-item {
display: flex;
margin-bottom: 12rpx;
font-size: 24rpx;
line-height: 1.4;
}
.detail-label {
color: #909399;
width: 120rpx;
flex-shrink: 0;
}
.detail-value {
color: #303133;
flex: 1;
}
.backup-actions {
display: flex;
justify-content: flex-end;
gap: 16rpx;
}
.action-btn {
padding: 12rpx 24rpx;
border-radius: 8rpx;
font-size: 24rpx;
cursor: pointer;
}
.view-btn {
background-color: #409eff;
color: #fff;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
text-align: center;
}
.empty-icon {
font-size: 100rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 28rpx;
color: #909399;
}
/* 分页 */
.pagination {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 32rpx;
padding-top: 24rpx;
border-top: 1rpx solid #e4e7ed;
}
.page-info {
font-size: 24rpx;
color: #606266;
}
.page-controls {
display: flex;
gap: 16rpx;
}
.page-btn {
padding: 8rpx 24rpx;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
font-size: 24rpx;
color: #606266;
cursor: pointer;
}
.page-btn:hover {
border-color: #409eff;
color: #409eff;
}
.page-btn.disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* 提示信息 */
.tips-section {
padding: 32rpx;
background-color: #ecf5ff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
.tip-item {
margin-bottom: 8rpx;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.data-logs-container {
max-width: 900px;
margin: 0 auto;
}
.logs-section,
.backup-section {
padding: 40rpx;
}
.log-item,
.backup-item {
padding: 32rpx;
}
.search-input {
width: 400rpx;
}
}
</style>

View File

@@ -0,0 +1,560 @@
<template>
<view class="help-center-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">帮助中心</view>
<view class="header-right"></view>
</view>
<!-- 常见问题 -->
<view class="faq-section">
<view class="section-header">
<view class="section-title">常见问题</view>
<view class="search-box">
<input
v-model="faqSearch"
class="search-input"
placeholder="搜索问题"
/>
</view>
</view>
<view class="faq-list">
<view
v-for="(faq, index) in filteredFaqs"
:key="faq.id"
class="faq-item"
@click="toggleFaq(index)"
>
<view class="faq-header">
<view class="faq-question">{{ faq.question }}</view>
<view class="faq-icon">{{ expandedFaq === index ? '▼' : '▶' }}</view>
</view>
<view
v-if="expandedFaq === index"
class="faq-answer"
>
{{ faq.answer }}
</view>
</view>
<view v-if="filteredFaqs.length === 0" class="empty-state">
<view class="empty-icon"></view>
<view class="empty-text">暂无相关问题</view>
</view>
</view>
</view>
<!-- 使用指南 -->
<view class="guide-section">
<view class="section-title">使用指南</view>
<view class="guide-list">
<view
v-for="guide in guides"
:key="guide.id"
class="guide-item"
@click="viewGuide(guide.id)"
>
<view class="guide-icon">{{ guide.icon }}</view>
<view class="guide-info">
<view class="guide-title">{{ guide.title }}</view>
<view class="guide-desc">{{ guide.description }}</view>
</view>
<view class="guide-arrow"></view>
</view>
</view>
</view>
<!-- 联系客服 -->
<view class="contact-section">
<view class="section-title">联系客服</view>
<view class="contact-info">
<view class="contact-item">
<view class="contact-icon">📞</view>
<view class="contact-details">
<view class="contact-label">客服电话</view>
<view class="contact-value">400-123-4567</view>
</view>
<view class="contact-action" @click="callService">
拨打
</view>
</view>
<view class="contact-item">
<view class="contact-icon">💬</view>
<view class="contact-details">
<view class="contact-label">在线客服</view>
<view class="contact-value">工作时间9:00-18:00</view>
</view>
<view class="contact-action" @click="onlineService">
咨询
</view>
</view>
<view class="contact-item">
<view class="contact-icon">📧</view>
<view class="contact-details">
<view class="contact-label">邮箱</view>
<view class="contact-value">support@shunda.com</view>
</view>
<view class="contact-action" @click="sendEmail">
发送
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from "vue"
// 常见问题
const faqs = ref([
{
id: 1,
question: '如何修改个人密码?',
answer: '在个人中心页面,点击"个人账号管理",然后选择"密码修改",按照提示输入当前密码和新密码即可完成修改。密码修改后需要重新登录。'
},
{
id: 2,
question: '如何查看分销业绩?',
answer: '在工作页面的"统计分析"模块中,点击"分销业绩统计",即可查看您的分销业绩数据,包括总提成、扫码数、付费人数等核心指标。'
},
{
id: 3,
question: '如何生成推广二维码?',
answer: '在工作页面的"分销管理"模块中,点击"个人推广管理",即可生成和领取您的专属推广二维码。您可以将二维码分享给学员,学员扫码后将成为您的推广用户。'
},
{
id: 4,
question: '如何给学员赠送会员?',
answer: '在工作页面的"会员维护"模块中,点击"赠送会员操作",输入学员信息和赠送时长,即可生成赠送会员的核验码,学员使用核验码即可激活会员。'
},
{
id: 5,
question: '如何查看学员学习情况?',
answer: '在工作页面的"学员学情监控"模块中,点击"学员列表管理"查看所有学员,或点击"学情详情查看"输入学员信息查看具体学员的学习数据和进度。'
},
{
id: 6,
question: '如何修改驾校信息?',
answer: '在个人中心页面,点击"驾校信息维护",即可查看和编辑驾校的基础信息,包括名称、地址、联系方式等。核心功能开关由平台控制,不可在此修改。'
},
{
id: 7,
question: '如何配置自定义字段?',
answer: '在个人中心页面,点击"自定义字段配置",即可添加和管理本驾校专属的自定义字段,用于收集学员的额外信息。您可以设置字段名称、类型、是否必填等属性。'
},
{
id: 8,
question: '如何查看操作日志?',
answer: '在个人中心页面,点击"数据相关",然后选择"操作日志"标签,即可查看本驾校的操作日志记录,包括操作人、操作内容、操作时间等信息。'
}
])
// 使用指南
const guides = ref([
{
id: 1,
title: '分销员操作指南',
description: '详细了解如何使用分销功能,包括生成二维码、查看业绩等',
icon: '📱'
},
{
id: 2,
title: '管理员操作指南',
description: '了解管理员的各项功能,包括账号管理、分润配置等',
icon: '🏢'
},
{
id: 3,
title: '学员管理指南',
description: '学习如何管理学员信息和监控学习情况',
icon: '🎓'
},
{
id: 4,
title: '会员管理指南',
description: '了解会员系统的使用方法,包括订单处理、赠送会员等',
icon: '👥'
}
])
// 搜索和展开状态
const faqSearch = ref('')
const expandedFaq = ref(null)
// 过滤后的常见问题
const filteredFaqs = computed(() => {
if (!faqSearch.value) {
return faqs.value
}
return faqs.value.filter(faq => {
return faq.question.includes(faqSearch.value) || faq.answer.includes(faqSearch.value)
})
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 切换FAQ展开状态
function toggleFaq(index) {
expandedFaq.value = expandedFaq.value === index ? null : index
}
// 查看使用指南
function viewGuide(guideId) {
uni.showModal({
title: '使用指南',
content: '使用指南详情页面正在开发中',
showCancel: false
})
}
// 联系客服
function callService() {
uni.makePhoneCall({
phoneNumber: '4001234567'
})
}
function onlineService() {
uni.showModal({
title: '在线客服',
content: '在线客服功能正在开发中,请通过电话联系我们',
showCancel: false
})
}
function sendEmail() {
uni.showModal({
title: '发送邮件',
content: '是否打开邮件应用发送邮件?',
success: function(res) {
if (res.confirm) {
uni.setClipboardData({
data: 'support@shunda.com',
success: function() {
uni.showToast({ title: '邮箱已复制,请粘贴到邮件应用', icon: 'success' })
}
})
}
}
})
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.help-center-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
}
/* 常见问题 */
.faq-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
line-height: 1.2;
}
.search-box {
flex-shrink: 0;
}
.search-input {
width: 300rpx;
height: 60rpx;
padding: 0 24rpx;
background-color: #f9f9f9;
border: 1rpx solid #dcdfe6;
border-radius: 30rpx;
font-size: 24rpx;
color: #303133;
}
.faq-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.faq-item {
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
overflow: hidden;
background-color: #f9f9f9;
}
.faq-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx;
cursor: pointer;
}
.faq-header:hover {
background-color: #f0f0f0;
}
.faq-question {
flex: 1;
font-size: 28rpx;
font-weight: 600;
color: #303133;
line-height: 1.4;
}
.faq-icon {
font-size: 24rpx;
color: #606266;
margin-left: 16rpx;
}
.faq-answer {
padding: 0 24rpx 24rpx;
font-size: 26rpx;
color: #606266;
line-height: 1.6;
}
/* 使用指南 */
.guide-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.guide-list {
display: flex;
flex-direction: column;
gap: 16rpx;
margin-top: 24rpx;
}
.guide-item {
display: flex;
align-items: center;
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
cursor: pointer;
transition: all 0.3s ease;
}
.guide-item:hover {
transform: translateY(-2rpx);
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}
.guide-icon {
font-size: 48rpx;
margin-right: 24rpx;
}
.guide-info {
flex: 1;
}
.guide-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 8rpx;
line-height: 1.2;
}
.guide-desc {
font-size: 24rpx;
color: #606266;
line-height: 1.4;
}
.guide-arrow {
font-size: 32rpx;
color: #909399;
}
/* 联系客服 */
.contact-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.contact-info {
display: flex;
flex-direction: column;
gap: 24rpx;
margin-top: 24rpx;
}
.contact-item {
display: flex;
align-items: center;
padding: 24rpx;
border: 1rpx solid #e4e7ed;
border-radius: 12rpx;
background-color: #f9f9f9;
}
.contact-icon {
font-size: 48rpx;
margin-right: 24rpx;
}
.contact-details {
flex: 1;
}
.contact-label {
font-size: 24rpx;
color: #606266;
margin-bottom: 4rpx;
}
.contact-value {
font-size: 28rpx;
font-weight: 600;
color: #303133;
}
.contact-action {
padding: 12rpx 24rpx;
background-color: #409eff;
color: #fff;
border-radius: 8rpx;
font-size: 24rpx;
cursor: pointer;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
text-align: center;
}
.empty-icon {
font-size: 100rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 28rpx;
color: #909399;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.help-center-container {
max-width: 900px;
margin: 0 auto;
}
.faq-section,
.guide-section,
.contact-section {
padding: 40rpx;
}
.faq-question {
font-size: 32rpx;
}
.faq-answer {
font-size: 28rpx;
}
.guide-title {
font-size: 32rpx;
}
.guide-desc {
font-size: 26rpx;
}
.contact-value {
font-size: 32rpx;
}
}
</style>

View File

@@ -1,187 +1,577 @@
<template>
<view class="mine-container" :style="{height: `${windowHeight}px`}">
<!--顶部个人信息栏-->
<view class="header-section">
<view class="flex padding justify-between">
<view class="flex align-center">
<view v-if="!avatar" class="cu-avatar xl round bg-white">
<view class="iconfont icon-people text-gray icon"></view>
<view class="mine-container">
<!-- 欢迎信息 -->
<view class="welcome-section">
<view class="user-info">
<view class="avatar">
<view class="avatar-icon">{{ userInitial }}</view>
</view>
<image v-if="avatar" @click="handleToAvatar" :src="avatar" class="cu-avatar xl round" mode="widthFix">
</image>
<view v-if="!name" @click="handleToLogin" class="login-tip">
点击登录
</view>
<view v-if="name" @click="handleToInfo" class="user-info">
<view class="u_title">
用户名{{ name }}
<view class="user-details">
<view class="user-name">{{ name }}</view>
<view class="user-role">
<text v-if="userRole === 'admin'">驾校管理员</text>
<text v-else>分销员</text>
</view>
</view>
</view>
<view @click="handleToInfo" class="flex align-center">
<text>个人信息</text>
<view class="iconfont icon-right"></view>
<view class="user-stats">
<view class="stat-item">
<view class="stat-value">{{ stats.scanCount }}</view>
<view class="stat-label">扫码数</view>
</view>
<view class="stat-item">
<view class="stat-value">{{ stats.paidCount }}</view>
<view class="stat-label">付费人数</view>
</view>
<view class="stat-item">
<view class="stat-value">{{ stats.totalProfit }}</view>
<view class="stat-label">提成总额</view>
</view>
</view>
</view>
<view class="content-section">
<view class="mine-actions grid col-4 text-center">
<view class="action-item" @click="handleJiaoLiuQun">
<view class="iconfont icon-friendfill text-pink icon"></view>
<text class="text">交流群</text>
<!-- 角色切换 -->
<view v-if="userRole === 'admin'" class="role-switch">
<view class="role-tab" :class="{ active: currentView === 'admin' }" @click="switchView('admin')">
管理员功能
</view>
<view class="action-item" @click="handleBuilding">
<view class="iconfont icon-service text-blue icon"></view>
<text class="text">在线客服</text>
</view>
<view class="action-item" @click="handleBuilding">
<view class="iconfont icon-community text-mauve icon"></view>
<text class="text">反馈社区</text>
</view>
<view class="action-item" @click="handleBuilding">
<view class="iconfont icon-dianzan text-green icon"></view>
<text class="text">点赞我们</text>
<view class="role-tab" :class="{ active: currentView === 'distributor' }" @click="switchView('distributor')">
分销员功能
</view>
</view>
<view class="menu-list">
<view class="list-cell list-cell-arrow" @click="handleToEditInfo">
<view class="menu-item-box">
<view class="iconfont icon-user menu-icon"></view>
<view>编辑资料</view>
<!-- 管理员功能 -->
<view v-if="currentView === 'admin'" class="feature-section">
<view class="section-title">驾校管理</view>
<view class="feature-grid">
<!-- 驾校信息维护 -->
<view class="feature-card" @click="goToSchoolInfo">
<view class="feature-icon school-icon">
<view class="icon-text">🏢</view>
</view>
<view class="feature-info">
<view class="feature-title">驾校信息维护</view>
<view class="feature-desc">查看编辑本驾校基础信息</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleHelp">
<view class="menu-item-box">
<view class="iconfont icon-help menu-icon"></view>
<view>常见问题</view>
<!-- 自定义字段配置 -->
<view class="feature-card" @click="goToCustomFields">
<view class="feature-icon field-icon">
<view class="icon-text">📝</view>
</view>
<view class="feature-info">
<view class="feature-title">自定义字段配置</view>
<view class="feature-desc">配置本驾校专属自定义字段</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleAbout">
<view class="menu-item-box">
<view class="iconfont icon-aixin menu-icon"></view>
<view>关于我们</view>
<!-- 数据相关 -->
<view class="feature-card" @click="goToDataLogs">
<view class="feature-icon data-icon">
<view class="icon-text">📋</view>
</view>
<view class="feature-info">
<view class="feature-title">数据相关</view>
<view class="feature-desc">查看操作日志和数据备份记录</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleToSetting">
<view class="menu-item-box">
<view class="iconfont icon-setting menu-icon"></view>
<view>应用设置</view>
</view>
</view>
</view>
<!-- 分销员功能 -->
<view v-else class="feature-section">
<view class="section-title">个人设置</view>
<view class="feature-grid">
<!-- 个人资料修改 -->
<view class="feature-card" @click="goToPersonalInfo">
<view class="feature-icon profile-icon">
<view class="icon-text">👤</view>
</view>
<view class="feature-info">
<view class="feature-title">个人资料修改</view>
<view class="feature-desc">修改个人基本信息</view>
</view>
</view>
<!-- 密码修改 -->
<view class="feature-card" @click="goToPasswordChange">
<view class="feature-icon password-icon">
<view class="icon-text">🔒</view>
</view>
<view class="feature-info">
<view class="feature-title">密码修改</view>
<view class="feature-desc">修改登录密码</view>
</view>
</view>
<!-- 驾校信息查看 -->
<view class="feature-card" @click="goToSchoolInfo">
<view class="feature-icon school-icon">
<view class="icon-text">🏢</view>
</view>
<view class="feature-info">
<view class="feature-title">驾校信息查看</view>
<view class="feature-desc">查看本驾校基础信息</view>
</view>
</view>
</view>
</view>
<!-- 通用功能 -->
<view class="feature-section">
<view class="section-title">通用功能</view>
<view class="feature-grid">
<!-- 帮助中心 -->
<view class="feature-card" @click="goToHelpCenter">
<view class="feature-icon help-icon">
<view class="icon-text"></view>
</view>
<view class="feature-info">
<view class="feature-title">帮助中心</view>
<view class="feature-desc">常见问题和使用指南</view>
</view>
</view>
<!-- 关于我们 -->
<view class="feature-card" @click="goToAboutUs">
<view class="feature-icon about-icon">
<view class="icon-text"></view>
</view>
<view class="feature-info">
<view class="feature-title">关于我们</view>
<view class="feature-desc">系统版本和公司信息</view>
</view>
</view>
<!-- 退出登录 -->
<view class="feature-card logout-card" @click="logout">
<view class="feature-icon logout-icon">
<view class="icon-text">🚪</view>
</view>
<view class="feature-info">
<view class="feature-title">退出登录</view>
<view class="feature-desc">退出当前账号</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { useUserStore } from '@/store'
import { computed , getCurrentInstance } from "vue"
import { ref, computed, onMounted } from "vue"
const { proxy } = getCurrentInstance()
const name = useUserStore().name
const avatar = computed(() => useUserStore().avatar)
const windowHeight = computed(() => uni.getSystemInfoSync().windowHeight - 50)
// 用户信息
const name = ref('张教练')
const userRole = ref('admin') // 模拟角色,实际应从登录状态获取
const currentView = ref('admin')
function handleToInfo() {
proxy.$tab.navigateTo('/pages/mine/info/index')
// 模拟统计数据
const stats = ref({
scanCount: 1234,
paidCount: 456,
totalProfit: '¥12,345.67'
})
// 计算用户名首字母
const userInitial = computed(() => {
return name.value ? name.value.charAt(0).toUpperCase() : 'U'
})
onMounted(() => {
// 实际项目中应从登录状态或接口获取用户信息
// loadUserData()
})
// 切换视图
function switchView(view) {
currentView.value = view
}
function handleToEditInfo() {
proxy.$tab.navigateTo('/pages/mine/info/edit')
// 管理员功能跳转
function goToSchoolInfo() {
uni.navigateTo({
url: '/pages/mine/school-info'
})
}
function handleToSetting() {
proxy.$tab.navigateTo('/pages/mine/setting/index')
function goToCustomFields() {
uni.navigateTo({
url: '/pages/mine/custom-fields'
})
}
function handleToLogin() {
proxy.$tab.reLaunch('/pages/login')
function goToDataLogs() {
uni.navigateTo({
url: '/pages/mine/data-logs'
})
}
function handleToAvatar() {
proxy.$tab.navigateTo('/pages/mine/avatar/index')
// 分销员功能跳转
function goToPersonalInfo() {
uni.navigateTo({
url: '/pages/mine/personal-info'
})
}
function handleHelp() {
proxy.$tab.navigateTo('/pages/mine/help/index')
function goToPasswordChange() {
uni.navigateTo({
url: '/pages/mine/password-change'
})
}
function handleAbout() {
proxy.$tab.navigateTo('/pages/mine/about/index')
// 通用功能跳转
function goToHelpCenter() {
uni.navigateTo({
url: '/pages/mine/help-center'
})
}
function handleJiaoLiuQun() {
proxy.$modal.showToast('QQ群①133713780(满)、②146013835(满)、③189091635')
function goToAboutUs() {
uni.navigateTo({
url: '/pages/mine/about-us'
})
}
function handleBuilding() {
proxy.$modal.showToast('模块建设中~')
// 退出登录
function logout() {
uni.showModal({
title: '退出登录',
content: '确定要退出当前账号吗?',
success: function(res) {
if (res.confirm) {
// 实际项目中应清除登录状态
uni.redirectTo({
url: '/pages/login/index'
})
}
}
})
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
background-color: #f5f6f7;
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.mine-container {
width: 100%;
height: 100%;
.header-section {
padding: 15px 15px 45px 15px;
background-color: #3c96f3;
color: white;
.login-tip {
font-size: 18px;
margin-left: 10px;
padding: 20rpx;
min-height: 100vh;
}
.cu-avatar {
border: 2px solid #eaeaea;
.icon {
font-size: 40px;
}
/* 欢迎信息区域 */
.welcome-section {
background: linear-gradient(135deg, #409eff 0%, #667eea 100%);
border-radius: 20rpx;
padding: 40rpx;
margin-bottom: 30rpx;
color: #fff;
box-shadow: 0 8rpx 32rpx rgba(64, 158, 255, 0.3);
}
.user-info {
margin-left: 15px;
.u_title {
font-size: 18px;
line-height: 30px;
display: flex;
align-items: center;
margin-bottom: 32rpx;
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
}
.avatar-icon {
font-size: 64rpx;
font-weight: bold;
color: #fff;
}
.user-details {
flex: 1;
}
.user-name {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 8rpx;
line-height: 1.2;
}
.user-role {
font-size: 24rpx;
opacity: 0.9;
line-height: 1.4;
}
.user-stats {
display: flex;
justify-content: space-around;
padding-top: 24rpx;
border-top: 1rpx solid rgba(255, 255, 255, 0.2);
}
.stat-item {
text-align: center;
}
.stat-value {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 4rpx;
line-height: 1.2;
}
.stat-label {
font-size: 20rpx;
opacity: 0.8;
line-height: 1.3;
}
/* 角色切换 */
.role-switch {
display: flex;
background-color: #fff;
border-radius: 12rpx;
margin-bottom: 30rpx;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.role-tab {
flex: 1;
padding: 24rpx;
text-align: center;
font-size: 28rpx;
font-weight: 500;
color: #606266;
transition: all 0.3s ease;
cursor: pointer;
}
.role-tab.active {
background-color: #409eff;
color: #fff;
}
/* 功能区域 */
.feature-section {
margin-bottom: 30rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 24rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
.feature-grid {
display: flex;
flex-direction: column;
gap: 16rpx;
}
/* 功能卡片 */
.feature-card {
display: flex;
align-items: center;
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
cursor: pointer;
}
.feature-card:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.logout-card {
border: 1rpx solid #f56c6c;
}
/* 图标容器 */
.feature-icon {
width: 80rpx;
height: 80rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
flex-shrink: 0;
}
/* 图标文本样式 */
.icon-text {
font-size: 36rpx;
line-height: 1;
text-align: center;
}
/* 各模块颜色 */
.school-icon {
background-color: #ecf5ff;
}
.field-icon {
background-color: #f0f9eb;
}
.data-icon {
background-color: #fdf6ec;
}
.profile-icon {
background-color: #fef0f0;
}
.password-icon {
background-color: #f4f4f5;
}
.help-icon {
background-color: #f0f5ff;
}
.about-icon {
background-color: #f0f0f0;
}
.logout-icon {
background-color: #fef0f0;
}
/* 功能信息 */
.feature-info {
flex: 1;
min-width: 0;
}
.feature-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 8rpx;
line-height: 1.3;
}
.feature-desc {
font-size: 22rpx;
color: #909399;
line-height: 1.4;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.mine-container {
max-width: 900px;
margin: 0 auto;
padding: 30rpx;
}
.welcome-section {
padding: 50rpx;
}
.user-name {
font-size: 44rpx;
}
.user-role {
font-size: 28rpx;
}
.stat-value {
font-size: 36rpx;
}
.stat-label {
font-size: 24rpx;
}
.section-title {
font-size: 36rpx;
margin-bottom: 30rpx;
}
.feature-card {
padding: 30rpx;
}
.feature-icon {
width: 100rpx;
height: 100rpx;
margin-right: 24rpx;
}
.icon-text {
font-size: 44rpx;
}
.feature-title {
font-size: 32rpx;
}
.feature-desc {
font-size: 24rpx;
}
}
.content-section {
position: relative;
top: -50px;
.mine-actions {
margin: 15px 15px;
padding: 20px 0px;
border-radius: 8px;
background-color: white;
.action-item {
.icon {
font-size: 28px;
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.mine-container {
max-width: 1000px;
}
.text {
display: block;
font-size: 13px;
margin: 8px 0px;
.welcome-section {
padding: 60rpx;
}
.feature-card {
padding: 36rpx;
}
.feature-icon {
width: 120rpx;
height: 120rpx;
}
.icon-text {
font-size: 52rpx;
}
.feature-title {
font-size: 36rpx;
}
.feature-desc {
font-size: 26rpx;
}
}
</style>

View File

@@ -0,0 +1,501 @@
<template>
<view class="password-change-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">密码修改</view>
<view class="header-right" @click="savePassword">
<view class="save-btn">保存</view>
</view>
</view>
<!-- 密码修改表单 -->
<view class="form-section">
<view class="form-group">
<view class="form-label">当前密码</view>
<view class="form-control">
<input
v-model="passwordForm.oldPassword"
class="form-input"
placeholder="请输入当前密码"
maxlength="20"
:type="showPassword ? 'text' : 'password'"
/>
<view class="password-toggle" @click="togglePassword">
{{ showPassword ? '🙈' : '👁' }}
</view>
</view>
</view>
<view class="form-group">
<view class="form-label">新密码</view>
<view class="form-control">
<input
v-model="passwordForm.newPassword"
class="form-input"
placeholder="请输入新密码"
maxlength="20"
:type="showPassword ? 'text' : 'password'"
/>
<view class="password-toggle" @click="togglePassword">
{{ showPassword ? '🙈' : '👁' }}
</view>
</view>
</view>
<view class="form-group">
<view class="form-label">确认新密码</view>
<view class="form-control">
<input
v-model="passwordForm.confirmPassword"
class="form-input"
placeholder="请再次输入新密码"
maxlength="20"
:type="showPassword ? 'text' : 'password'"
/>
<view class="password-toggle" @click="togglePassword">
{{ showPassword ? '🙈' : '👁' }}
</view>
</view>
</view>
</view>
<!-- 密码强度提示 -->
<view class="strength-section">
<view class="section-title">密码强度要求</view>
<view class="strength-tips">
<view class="tip-item" :class="{ active: passwordForm.newPassword.length >= 8 }">
密码长度至少8位
</view>
<view class="tip-item" :class="{ active: /[A-Z]/.test(passwordForm.newPassword) }">
包含大写字母
</view>
<view class="tip-item" :class="{ active: /[a-z]/.test(passwordForm.newPassword) }">
包含小写字母
</view>
<view class="tip-item" :class="{ active: /[0-9]/.test(passwordForm.newPassword) }">
包含数字
</view>
<view class="tip-item" :class="{ active: /[!@#$%^&*(),.?":{}|<>]/.test(passwordForm.newPassword) }">
• 包含特殊字符
</view>
</view>
<!-- 密码强度指示器 -->
<view class="strength-indicator">
<view class="strength-label">密码强度:</view>
<view class="strength-bars">
<view
class="strength-bar"
:class="getStrengthClass()"
></view>
<view class="strength-text">{{ getStrengthText() }}</view>
</view>
</view>
</view>
<!-- 操作提示 -->
<view class="operation-tips">
<view class="tips-title">操作提示</view>
<view class="tips-content">
<view class="tip-item">• 请确保新密码符合强度要求</view>
<view class="tip-item">• 密码修改后需要重新登录</view>
<view class="tip-item">• 如忘记当前密码,请联系管理员重置</view>
<view class="tip-item">• 请妥善保管您的密码,不要泄露给他人</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from "vue"
// 密码表单
const passwordForm = ref({
oldPassword: '',
newPassword: '',
confirmPassword: ''
})
// 显示密码
const showPassword = ref(false)
// 切换密码显示状态
function togglePassword() {
showPassword.value = !showPassword.value
}
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 获取密码强度等级
function getPasswordStrength() {
const password = passwordForm.value.newPassword
if (!password) return 0
let strength = 0
if (password.length >= 8) strength++
if (/[A-Z]/.test(password)) strength++
if (/[a-z]/.test(password)) strength++
if (/[0-9]/.test(password)) strength++
if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) strength++
return strength
}
// 获取密码强度样式类
function getStrengthClass() {
const strength = getPasswordStrength()
switch (strength) {
case 0: return 'weak'
case 1: return 'weak'
case 2: return 'medium'
case 3: return 'medium'
case 4: return 'strong'
case 5: return 'strong'
default: return 'weak'
}
}
// 获取密码强度文本
function getStrengthText() {
const strength = getPasswordStrength()
switch (strength) {
case 0: return '未设置'
case 1: return '弱'
case 2: return '较弱'
case 3: return '中等'
case 4: return '强'
case 5: return '很强'
default: return '未设置'
}
}
// 验证密码
function validatePassword() {
if (!passwordForm.value.oldPassword) {
uni.showToast({ title: '请输入当前密码', icon: 'none' })
return false
}
if (!passwordForm.value.newPassword) {
uni.showToast({ title: '请输入新密码', icon: 'none' })
return false
}
if (passwordForm.value.newPassword.length < 8) {
uni.showToast({ title: '新密码长度至少8位', icon: 'none' })
return false
}
if (passwordForm.value.newPassword !== passwordForm.value.confirmPassword) {
uni.showToast({ title: '两次输入的新密码不一致', icon: 'none' })
return false
}
if (passwordForm.value.newPassword === passwordForm.value.oldPassword) {
uni.showToast({ title: '新密码不能与当前密码相同', icon: 'none' })
return false
}
return true
}
// 保存密码
function savePassword() {
if (!validatePassword()) {
return
}
// 实际项目中应调用接口修改密码
uni.showLoading({ title: '修改中...' })
setTimeout(() => {
uni.hideLoading()
uni.showModal({
title: '修改成功',
content: '密码修改成功,请重新登录',
showCancel: false,
success: function() {
// 实际项目中应跳转到登录页面
uni.redirectTo({
url: '/pages/login/index'
})
}
})
}, 1000)
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.password-change-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.save-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 表单区域 */
.form-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.form-group {
margin-bottom: 32rpx;
}
.form-label {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 12rpx;
line-height: 1.2;
}
.form-control {
position: relative;
}
.form-input {
width: 100%;
height: 80rpx;
padding: 0 100rpx 0 24rpx;
font-size: 28rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
}
.form-input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.password-toggle {
position: absolute;
right: 24rpx;
top: 50%;
transform: translateY(-50%);
font-size: 32rpx;
cursor: pointer;
}
/* 密码强度 */
.strength-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 24rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
.strength-tips {
margin-bottom: 32rpx;
}
.tip-item {
font-size: 24rpx;
color: #606266;
margin-bottom: 12rpx;
line-height: 1.4;
}
.tip-item.active {
color: #67c23a;
}
.strength-indicator {
display: flex;
align-items: center;
padding: 20rpx;
background-color: #f9f9f9;
border-radius: 8rpx;
}
.strength-label {
font-size: 24rpx;
color: #606266;
margin-right: 16rpx;
}
.strength-bars {
flex: 1;
display: flex;
align-items: center;
}
.strength-bar {
height: 8rpx;
border-radius: 4rpx;
flex: 1;
margin-right: 8rpx;
}
.strength-bar.weak {
background-color: #f56c6c;
}
.strength-bar.medium {
background-color: #e6a23c;
}
.strength-bar.strong {
background-color: #67c23a;
}
.strength-text {
font-size: 24rpx;
font-weight: 600;
margin-left: 16rpx;
}
.strength-text.weak {
color: #f56c6c;
}
.strength-text.medium {
color: #e6a23c;
}
.strength-text.strong {
color: #67c23a;
}
/* 操作提示 */
.operation-tips {
padding: 32rpx;
background-color: #ecf5ff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.password-change-container {
max-width: 900px;
margin: 0 auto;
}
.form-section {
padding: 40rpx;
}
.form-group {
margin-bottom: 40rpx;
}
.form-label {
font-size: 32rpx;
margin-bottom: 16rpx;
}
.form-input {
height: 100rpx;
font-size: 32rpx;
padding: 0 120rpx 0 32rpx;
}
.strength-section {
padding: 40rpx;
}
.tip-item {
font-size: 28rpx;
}
.operation-tips {
padding: 40rpx;
}
}
</style>

View File

@@ -0,0 +1,499 @@
<template>
<view class="personal-info-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">个人资料修改</view>
<view class="header-right" @click="saveInfo">
<view class="save-btn">保存</view>
</view>
</view>
<!-- 个人信息表单 -->
<view class="form-section">
<view class="avatar-section">
<view class="avatar-preview" @click="chooseAvatar">
<view v-if="userInfo.avatar" class="avatar-img">
<image :src="userInfo.avatar" mode="aspectFill"></image>
</view>
<view v-else class="avatar-placeholder">
<view class="avatar-icon">{{ userInitial }}</view>
<view class="avatar-tip">点击更换头像</view>
</view>
</view>
</view>
<view class="form-group">
<view class="form-label">姓名</view>
<view class="form-control">
<input
v-model="userInfo.name"
class="form-input"
placeholder="请输入姓名"
maxlength="20"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">手机号</view>
<view class="form-control">
<input
v-model="userInfo.phone"
class="form-input"
placeholder="请输入手机号"
maxlength="15"
type="number"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">邮箱</view>
<view class="form-control">
<input
v-model="userInfo.email"
class="form-input"
placeholder="请输入邮箱"
maxlength="50"
type="email"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">性别</view>
<view class="form-control">
<picker
v-model="userInfo.gender"
:range="genders"
class="form-picker"
>
<view class="picker-display">{{ userInfo.gender || '请选择性别' }}</view>
</picker>
</view>
</view>
<view class="form-group">
<view class="form-label">所属驾校</view>
<view class="form-control">
<view class="form-text">{{ userInfo.school || '顺达驾校' }}</view>
</view>
</view>
<view class="form-group">
<view class="form-label">职位</view>
<view class="form-control">
<input
v-model="userInfo.position"
class="form-input"
placeholder="请输入职位"
maxlength="20"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">简介</view>
<view class="form-control">
<textarea
v-model="userInfo.bio"
class="form-textarea"
placeholder="请输入个人简介"
maxlength="200"
rows="3"
></textarea>
</view>
</view>
</view>
<!-- 账号信息 -->
<view class="account-section">
<view class="section-title">账号信息</view>
<view class="account-info">
<view class="info-item">
<view class="info-label">账号ID</view>
<view class="info-value">{{ userInfo.id || '10001' }}</view>
</view>
<view class="info-item">
<view class="info-label">注册时间</view>
<view class="info-value">{{ userInfo.registerTime || '2026-01-01' }}</view>
</view>
<view class="info-item">
<view class="info-label">最后登录</view>
<view class="info-value">{{ userInfo.lastLogin || '2026-01-29' }}</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
// 性别选项
const genders = ['男', '女', '保密']
// 用户信息
const userInfo = ref({
name: '李教练',
phone: '13900139000',
email: 'li@shunda.com',
gender: '男',
school: '顺达驾校',
position: '科目二教练',
bio: '拥有10年驾驶教学经验擅长科目二倒车入库教学',
id: '10002',
registerTime: '2026-01-15',
lastLogin: '2026-01-29 10:30:00'
})
// 计算用户名首字母
const userInitial = computed(() => {
return userInfo.value.name ? userInfo.value.name.charAt(0).toUpperCase() : 'U'
})
onMounted(() => {
// 实际项目中应从接口获取用户信息
// loadUserInfo()
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 选择头像
function chooseAvatar() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function(res) {
// 实际项目中应上传图片到服务器
userInfo.value.avatar = res.tempFilePaths[0]
}
})
}
// 保存个人信息
function saveInfo() {
// 表单验证
if (!userInfo.value.name) {
uni.showToast({ title: '请输入姓名', icon: 'none' })
return
}
if (!userInfo.value.phone) {
uni.showToast({ title: '请输入手机号', icon: 'none' })
return
}
// 实际项目中应调用接口保存信息
uni.showLoading({ title: '保存中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '保存成功', icon: 'success' })
goBack()
}, 1000)
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.personal-info-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.save-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 表单区域 */
.form-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
/* 头像部分 */
.avatar-section {
display: flex;
justify-content: center;
margin-bottom: 40rpx;
}
.avatar-preview {
width: 200rpx;
height: 200rpx;
border-radius: 50%;
overflow: hidden;
cursor: pointer;
background-color: #f0f0f0;
}
.avatar-img {
width: 100%;
height: 100%;
}
.avatar-img image {
width: 100%;
height: 100%;
}
.avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #409eff 0%, #667eea 100%);
color: #fff;
}
.avatar-icon {
font-size: 80rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.avatar-tip {
font-size: 20rpx;
opacity: 0.9;
}
.form-group {
margin-bottom: 32rpx;
}
.form-label {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 12rpx;
line-height: 1.2;
}
.form-control {
position: relative;
}
.form-input {
width: 100%;
height: 80rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
}
.form-input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.form-textarea {
width: 100%;
min-height: 160rpx;
padding: 24rpx;
font-size: 28rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
resize: none;
}
.form-textarea:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.form-picker {
width: 100%;
height: 80rpx;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
}
.picker-display {
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 0 24rpx;
font-size: 28rpx;
color: #303133;
}
.form-text {
width: 100%;
height: 80rpx;
display: flex;
align-items: center;
padding: 0 24rpx;
font-size: 28rpx;
color: #606266;
background-color: #f9f9f9;
border-radius: 8rpx;
box-sizing: border-box;
}
/* 账号信息 */
.account-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 24rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
.account-info {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #e4e7ed;
}
.info-item:last-child {
border-bottom: none;
}
.info-label {
font-size: 28rpx;
color: #606266;
}
.info-value {
font-size: 28rpx;
color: #303133;
font-weight: 500;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.personal-info-container {
max-width: 900px;
margin: 0 auto;
}
.form-section {
padding: 40rpx;
}
.form-group {
margin-bottom: 40rpx;
}
.form-label {
font-size: 32rpx;
margin-bottom: 16rpx;
}
.form-input {
height: 100rpx;
font-size: 32rpx;
padding: 0 32rpx;
}
.form-textarea {
min-height: 200rpx;
font-size: 32rpx;
padding: 32rpx;
}
.form-text {
height: 100rpx;
font-size: 32rpx;
padding: 0 32rpx;
}
.account-section {
padding: 40rpx;
}
}
</style>

View File

@@ -0,0 +1,383 @@
<template>
<view class="school-info-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">驾校信息维护</view>
<view class="header-right" @click="saveInfo">
<view class="save-btn">保存</view>
</view>
</view>
<!-- 驾校信息表单 -->
<view class="form-section">
<view class="form-group">
<view class="form-label">驾校名称</view>
<view class="form-control">
<input
v-model="schoolInfo.name"
class="form-input"
placeholder="请输入驾校名称"
maxlength="50"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">联系人</view>
<view class="form-control">
<input
v-model="schoolInfo.contact"
class="form-input"
placeholder="请输入联系人姓名"
maxlength="20"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">联系电话</view>
<view class="form-control">
<input
v-model="schoolInfo.phone"
class="form-input"
placeholder="请输入联系电话"
maxlength="15"
type="number"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">地址</view>
<view class="form-control">
<input
v-model="schoolInfo.address"
class="form-input"
placeholder="请输入驾校地址"
maxlength="100"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">邮箱</view>
<view class="form-control">
<input
v-model="schoolInfo.email"
class="form-input"
placeholder="请输入邮箱地址"
maxlength="50"
type="email"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">经营范围</view>
<view class="form-control">
<textarea
v-model="schoolInfo.businessScope"
class="form-textarea"
placeholder="请输入经营范围"
maxlength="200"
rows="3"
></textarea>
</view>
</view>
<view class="form-group">
<view class="form-label">驾校简介</view>
<view class="form-control">
<textarea
v-model="schoolInfo.description"
class="form-textarea"
placeholder="请输入驾校简介"
maxlength="500"
rows="4"
></textarea>
</view>
</view>
</view>
<!-- 提示信息 -->
<view class="tips-section">
<view class="tips-title">注意事项</view>
<view class="tips-content">
<view class="tip-item"> 驾校名称联系人和联系电话为必填项</view>
<view class="tip-item"> 核心功能开关由平台控制不可在此修改</view>
<view class="tip-item"> 修改信息后需点击保存按钮生效</view>
<view class="tip-item"> 请确保填写的信息真实有效</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from "vue"
// 驾校信息
const schoolInfo = ref({
name: '顺达驾校',
contact: '张校长',
phone: '13800138000',
address: '北京市朝阳区建国路88号',
email: 'contact@shunda.com',
businessScope: '机动车驾驶员培训(小型汽车、大型货车)',
description: '顺达驾校成立于2005年是北京市知名的驾驶员培训机构拥有专业的教练团队和完善的教学设施致力于为学员提供优质的驾驶培训服务。'
})
onMounted(() => {
// 实际项目中应从接口获取驾校信息
// loadSchoolInfo()
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 保存驾校信息
function saveInfo() {
// 表单验证
if (!schoolInfo.value.name) {
uni.showToast({ title: '请输入驾校名称', icon: 'none' })
return
}
if (!schoolInfo.value.contact) {
uni.showToast({ title: '请输入联系人', icon: 'none' })
return
}
if (!schoolInfo.value.phone) {
uni.showToast({ title: '请输入联系电话', icon: 'none' })
return
}
// 实际项目中应调用接口保存信息
uni.showLoading({ title: '保存中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '保存成功', icon: 'success' })
goBack()
}, 1000)
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.school-info-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.save-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 表单区域 */
.form-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.form-group {
margin-bottom: 32rpx;
}
.form-label {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 12rpx;
line-height: 1.2;
}
.form-control {
position: relative;
}
.form-input {
width: 100%;
height: 80rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
}
.form-input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.form-textarea {
width: 100%;
min-height: 160rpx;
padding: 24rpx;
font-size: 28rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
resize: none;
}
.form-textarea:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
/* 提示信息 */
.tips-section {
padding: 32rpx;
background-color: #ecf5ff;
margin: 16rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
.tip-item {
margin-bottom: 8rpx;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.school-info-container {
max-width: 900px;
margin: 0 auto;
}
.form-section {
padding: 40rpx;
}
.form-group {
margin-bottom: 40rpx;
}
.form-label {
font-size: 32rpx;
margin-bottom: 16rpx;
}
.form-input {
height: 100rpx;
font-size: 32rpx;
padding: 0 32rpx;
}
.form-textarea {
min-height: 200rpx;
font-size: 32rpx;
padding: 32rpx;
}
.tips-section {
padding: 40rpx;
}
.tips-title {
font-size: 32rpx;
margin-bottom: 24rpx;
}
.tips-content {
font-size: 28rpx;
}
}
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.form-section {
padding: 50rpx;
}
.form-input {
height: 120rpx;
font-size: 36rpx;
}
.form-textarea {
min-height: 240rpx;
font-size: 36rpx;
}
}
</style>

View File

@@ -1,110 +1,485 @@
<template>
<view class="work-container">
<!-- 轮播图 -->
<uni-swiper-dot class="uni-swiper-dot-box" :info="data" :current="current" field="content">
<swiper class="swiper-box" :current="swiperDotIndex" @change="changeSwiper">
<swiper-item v-for="(item, index) in data" :key="index">
<view class="swiper-item" @click="clickBannerItem(item)">
<image :src="item.image" mode="aspectFill" :draggable="false" class="banner-image" />
<!-- 账号管理 -->
<view class="section">
<view class="section-title">账号管理</view>
<view class="feature-row">
<!-- 管理员功能 -->
<view v-if="userRole === 'admin'" class="feature-card" @click="goToAccountManage">
<view class="feature-icon distributor-icon">
<view class="icon-text">👥</view>
</view>
<view class="feature-info">
<view class="feature-title">账号创建与管控</view>
<view class="feature-desc">创建冻结分销员账号配置权限</view>
</view>
</view>
</swiper-item>
</swiper>
</uni-swiper-dot>
<!-- 宫格组件 -->
<view class="grid-body">
<view class="grid-title">系统功能</view>
<uni-grid :column="4" :showBorder="false">
<uni-grid-item @click="goToDistributor">
<view class="grid-item-box distributor">
<view class="icon-container">
<uni-icons type="share" size="36" color="#409eff" />
<view v-if="userRole === 'admin'" class="feature-card" @click="goToQuotaManage">
<view class="feature-icon user-icon">
<view class="icon-text">🎁</view>
</view>
<text class="text">分销员管理</text>
<view class="feature-info">
<view class="feature-title">赠会员额度分配</view>
<view class="feature-desc">分配分销员每月赠会员额度</view>
</view>
</uni-grid-item>
<uni-grid-item @click="showUnderConstruction">
<view class="grid-item-box user">
<view class="icon-container">
<uni-icons type="person-filled" size="36" color="#67c23a" />
</view>
<text class="text">用户管理</text>
<view v-if="userRole === 'admin'" class="feature-card" @click="goToLogManage">
<view class="feature-icon dept-icon">
<view class="icon-text">📋</view>
</view>
</uni-grid-item>
<uni-grid-item @click="showUnderConstruction">
<view class="grid-item-box dept">
<view class="icon-container">
<uni-icons type="settings-filled" size="36" color="#e6a23c" />
<view class="feature-info">
<view class="feature-title">操作日志查看</view>
<view class="feature-desc">查看账号核心操作日志</view>
</view>
<text class="text">部门管理</text>
</view>
</uni-grid-item>
<uni-grid-item @click="showUnderConstruction">
<view class="grid-item-box notice">
<view class="icon-container">
<uni-icons type="chat-filled" size="36" color="#f56c6c" />
<!-- 分销员功能 -->
<view v-if="userRole === 'distributor'" class="feature-card" @click="goToPersonalAccount">
<view class="feature-icon notice-icon">
<view class="icon-text">👤</view>
</view>
<text class="text">通知公告</text>
<view class="feature-info">
<view class="feature-title">个人账号管理</view>
<view class="feature-desc">修改个人资料登录密码</view>
</view>
</view>
</view>
</view>
<!-- 分销管理 -->
<view class="section">
<view class="section-title">分销管理</view>
<view class="feature-row">
<!-- 管理员功能 -->
<view v-if="userRole === 'admin'" class="feature-card" @click="goToDistributorManage">
<view class="feature-icon distributor-icon">
<view class="icon-text">👥</view>
</view>
<view class="feature-info">
<view class="feature-title">分销员管理</view>
<view class="feature-desc">查看编辑批量管理分销员</view>
</view>
</view>
<view v-if="userRole === 'admin'" class="feature-card" @click="goToProfitRule">
<view class="feature-icon user-icon">
<view class="icon-text">💰</view>
</view>
<view class="feature-info">
<view class="feature-title">分润规则配置</view>
<view class="feature-desc">配置扫码注册购买会员分润比例</view>
</view>
</view>
<view v-if="userRole === 'admin'" class="feature-card" @click="goToDistributionData">
<view class="feature-icon dept-icon">
<view class="icon-text">📊</view>
</view>
<view class="feature-info">
<view class="feature-title">分销数据查看</view>
<view class="feature-desc">查看推广数据分润明细</view>
</view>
</view>
<view v-if="userRole === 'admin'" class="feature-card" @click="goToQrCodeManage">
<view class="feature-icon notice-icon">
<view class="icon-text">🔗</view>
</view>
<view class="feature-info">
<view class="feature-title">专属二维码管理</view>
<view class="feature-desc">批量生成推广二维码</view>
</view>
</view>
<!-- 分销员功能 -->
<view v-if="userRole === 'distributor'" class="feature-card" @click="goToPersonalPromotion">
<view class="feature-icon log-icon">
<view class="icon-text">📱</view>
</view>
<view class="feature-info">
<view class="feature-title">个人推广管理</view>
<view class="feature-desc">领取分享个人推广二维码</view>
</view>
</view>
<view v-if="userRole === 'distributor'" class="feature-card" @click="goToProfitQuery">
<view class="feature-icon distributor-icon">
<view class="icon-text">💵</view>
</view>
<view class="feature-info">
<view class="feature-title">分润查询</view>
<view class="feature-desc">查看个人提成总额分润明细</view>
</view>
</view>
</view>
</view>
<!-- 学员学情监控 -->
<view class="section">
<view class="section-title">学员学情监控</view>
<view class="feature-row">
<view class="feature-card" @click="goToStudentList">
<view class="feature-icon dept-icon">
<view class="icon-text">🎓</view>
</view>
<view class="feature-info">
<view class="feature-title">学员列表管理</view>
<view class="feature-desc">查看筛选学员列表</view>
</view>
</view>
<view class="feature-card" @click="goToStudentDetail">
<view class="feature-icon notice-icon">
<view class="icon-text">📈</view>
</view>
<view class="feature-info">
<view class="feature-title">学情详情查看</view>
<view class="feature-desc">查看学员学习数据AI充值状态</view>
</view>
</view>
<view class="feature-card" @click="goToLearningAnalysis">
<view class="feature-icon log-icon">
<view class="icon-text">📊</view>
</view>
<view class="feature-info">
<view class="feature-title">学情统计分析</view>
<view class="feature-desc">查看学情数据可视化报表</view>
</view>
</view>
<view class="feature-card" @click="goToLearningRemind">
<view class="feature-icon distributor-icon">
<view class="icon-text">🔔</view>
</view>
<view class="feature-info">
<view class="feature-title">学习提醒</view>
<view class="feature-desc">向学员发送个性化学习提醒</view>
</view>
</view>
</view>
</view>
<!-- 会员维护 -->
<view class="section">
<view class="section-title">会员维护</view>
<view class="feature-row">
<!-- 管理员功能 -->
<view v-if="userRole === 'admin'" class="feature-card" @click="goToMemberOrder">
<view class="feature-icon user-icon">
<view class="icon-text">🛒</view>
</view>
<view class="feature-info">
<view class="feature-title">会员订单管理</view>
<view class="feature-desc">查看处理会员订单异常</view>
</view>
</view>
<view v-if="userRole === 'admin'" class="feature-card" @click="goToGiftMember">
<view class="feature-icon notice-icon">
<view class="icon-text">🎁</view>
</view>
<view class="feature-info">
<view class="feature-title">赠送会员管理</view>
<view class="feature-desc">生成管理赠送会员核验码</view>
</view>
</view>
<view v-if="userRole === 'admin'" class="feature-card" @click="goToGeneralCode">
<view class="feature-icon log-icon">
<view class="icon-text">🔗</view>
</view>
<view class="feature-info">
<view class="feature-title">通用会员推广码</view>
<view class="feature-desc">生成查看通用推广码</view>
</view>
</view>
<!-- 分销员功能 -->
<view v-if="userRole === 'distributor'" class="feature-card" @click="goToPersonalOrder">
<view class="feature-icon distributor-icon">
<view class="icon-text">📋</view>
</view>
<view class="feature-info">
<view class="feature-title">订单查看</view>
<view class="feature-desc">查看个人名下学员订单概览</view>
</view>
</view>
<view v-if="userRole === 'distributor'" class="feature-card" @click="goToPersonalGiftMember">
<view class="feature-icon user-icon">
<view class="icon-text">🎁</view>
</view>
<view class="feature-info">
<view class="feature-title">赠送会员操作</view>
<view class="feature-desc">生成分享赠送会员核验码</view>
</view>
</view>
</view>
</view>
<!-- 异常提醒 -->
<view class="section">
<view class="section-title">异常提醒</view>
<view class="feature-row">
<view class="feature-card" @click="goToProfitException">
<view class="feature-icon notice-icon">
<view class="icon-text">💰</view>
<view v-if="exceptionCount.profit > 0" class="exception-badge">{{ exceptionCount.profit }}</view>
</view>
<view class="feature-info">
<view class="feature-title">分润异常提醒</view>
<view class="feature-desc">处理账户余额不足等分润异常</view>
</view>
</view>
<view class="feature-card" @click="goToAiRechargeException">
<view class="feature-icon notice-icon">
<view class="icon-text">🤖</view>
<view v-if="exceptionCount.ai > 0" class="exception-badge">{{ exceptionCount.ai }}</view>
</view>
<view class="feature-info">
<view class="feature-title">AI充值订单异常</view>
<view class="feature-desc">处理AI充值订单失败等异常</view>
</view>
</view>
<view class="feature-card" @click="goToMemberOrderException">
<view class="feature-icon notice-icon">
<view class="icon-text">🛒</view>
<view v-if="exceptionCount.member > 0" class="exception-badge">{{ exceptionCount.member }}</view>
</view>
<view class="feature-info">
<view class="feature-title">会员订单异常</view>
<view class="feature-desc">处理会员订单支付失败等异常</view>
</view>
</uni-grid-item>
<uni-grid-item @click="showUnderConstruction">
<view class="grid-item-box log">
<view class="icon-container">
<uni-icons type="wallet-filled" size="36" color="#909399" />
</view>
<text class="text">日志管理</text>
</view>
</uni-grid-item>
</uni-grid>
</view>
</view>
</template>
<script setup>
import { ref, getCurrentInstance } from "vue"
import { ref, getCurrentInstance, onMounted } from "vue"
const { proxy } = getCurrentInstance()
const current = ref(0)
const swiperDotIndex = ref(0)
const data = ref([{ image: '/static/images/banner/banner01.jpg' }, { image: '/static/images/banner/banner02.jpg' }, { image: '/static/images/banner/banner03.jpg' }])
const userRole = ref('admin') // 模拟角色,实际应从登录状态获取
const exceptionCount = ref({ // 模拟异常数量
profit: 2, // 分润异常数量
ai: 1, // AI充值订单异常数量
member: 3 // 会员订单异常数量
})
function clickBannerItem(item) {
console.info(item)
}
onMounted(() => {
// 实际项目中应从登录状态或接口获取用户角色
// userRole.value = getUserRole()
function changeSwiper(e) {
current.value = e.detail.current
}
// 实际项目中应从接口获取异常数量
// getExceptionCount()
})
// 跳转到分销员管理页面
function goToDistributor() {
console.log('准备跳转到分销员管理页面')
// 账号管理相关
function goToAccountManage() {
uni.navigateTo({
url: '/pages/distributor/index',
success: function() {
console.log('跳转成功')
},
fail: function(err) {
console.log('跳转失败:', err)
// 尝试使用其他跳转方式
uni.redirectTo({
url: '/pages/distributor/index',
success: function() {
console.log('redirectTo跳转成功')
},
fail: function(err2) {
console.log('redirectTo跳转失败', err2)
// 显示错误信息
proxy.$modal.showToast('跳转失败,请重试')
}
})
}
url: '/pages/account/manage'
})
}
// 显示建设中提示
function showUnderConstruction() {
proxy.$modal.showToast('模块建设中~')
function goToQuotaManage() {
uni.navigateTo({
url: '/pages/account/quota'
})
}
function goToLogManage() {
uni.navigateTo({
url: '/pages/account/log'
})
}
function goToPersonalAccount() {
uni.navigateTo({
url: '/pages/account/personal'
})
}
// 分销管理相关
function goToDistributorManage() {
uni.navigateTo({
url: '/pages/distributor/index'
})
}
function goToProfitRule() {
uni.navigateTo({
url: '/pages/distribution/profit-rule'
})
}
function goToDistributionData() {
uni.navigateTo({
url: '/pages/distribution/data'
})
}
function goToQrCodeManage() {
uni.navigateTo({
url: '/pages/distribution/qrcode'
})
}
function goToPersonalPromotion() {
uni.navigateTo({
url: '/pages/distribution/personal'
})
}
function goToProfitQuery() {
uni.navigateTo({
url: '/pages/distribution/profit'
})
}
// 学员学情监控相关
function goToStudentList() {
uni.navigateTo({
url: '/pages/student/list'
})
}
function goToStudentDetail() {
uni.navigateTo({
url: '/pages/student/detail'
})
}
function goToLearningAnalysis() {
uni.navigateTo({
url: '/pages/student/analysis'
})
}
function goToLearningRemind() {
uni.navigateTo({
url: '/pages/student/remind'
})
}
// 会员维护相关
function goToMemberOrder() {
uni.navigateTo({
url: '/pages/member/order'
})
}
function goToGiftMember() {
uni.navigateTo({
url: '/pages/member/gift'
})
}
function goToGeneralCode() {
uni.navigateTo({
url: '/pages/member/general-code'
})
}
function goToPersonalOrder() {
uni.navigateTo({
url: '/pages/member/personal-order'
})
}
function goToPersonalGiftMember() {
uni.navigateTo({
url: '/pages/member/personal-gift'
})
}
// 统计分析相关
function goToDistributionStatistics() {
uni.navigateTo({
url: '/pages/stats/distribution'
})
}
function goToMemberStatistics() {
uni.navigateTo({
url: '/pages/stats/member'
})
}
function goToStudentStatistics() {
uni.navigateTo({
url: '/pages/stats/student'
})
}
function goToPersonalStatistics() {
uni.navigateTo({
url: '/pages/stats/personal'
})
}
function goToDataShare() {
// 生成并分享业绩数据图片
uni.showToast({
title: '生成分享图片中...',
duration: 1500
})
setTimeout(() => {
uni.showActionSheet({
itemList: ['分享到微信', '分享到朋友圈', '保存图片'],
success: function(res) {
switch(res.tapIndex) {
case 0:
uni.showToast({ title: '分享到微信', duration: 1000 })
break
case 1:
uni.showToast({ title: '分享到朋友圈', duration: 1000 })
break
case 2:
uni.showToast({ title: '图片已保存', duration: 1000 })
break
}
}
})
}, 1500)
}
// 异常提醒相关
function goToProfitException() {
uni.navigateTo({
url: '/pages/exception/profit'
})
}
function goToAiRechargeException() {
uni.navigateTo({
url: '/pages/exception/ai-recharge'
})
}
function goToMemberOrderException() {
uni.navigateTo({
url: '/pages/exception/member-order'
})
}
// 获取异常数量
function getExceptionCount() {
// 实际项目中应从接口获取异常数量
uni.request({
url: '/api/exception/count',
success: function(res) {
if (res.data.code === 200) {
exceptionCount.value = res.data.data
}
}
})
}
</script>
@@ -130,123 +505,190 @@
min-height: 100vh;
}
/* 轮播图样式 */
.uni-swiper-dot-box {
.section {
margin-bottom: 30rpx;
border-radius: 12rpx;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
}
.swiper-box {
height: 200px;
border-radius: 12rpx;
overflow: hidden;
}
.swiper-item {
height: 200px;
display: flex;
align-items: center;
justify-content: center;
}
.banner-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
/* 宫格样式 */
.grid-body {
background-color: #fff;
border-radius: 12rpx;
padding: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
}
.grid-title {
font-size: 30rpx;
/* 标题样式 */
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 20rpx;
padding-left: 10rpx;
border-left: 6rpx solid #409eff;
margin-bottom: 24rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
.grid-item-box {
flex: 1;
/* 横行排列容器 */
.feature-row {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20rpx 0;
transition: all 0.3s ease;
border-radius: 8rpx;
position: relative;
gap: 16rpx;
}
.grid-item-box:active {
/* 功能卡片样式 */
.feature-card {
display: flex;
align-items: center;
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
cursor: pointer;
}
.feature-card:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.icon-container {
/* 图标容器 */
.feature-icon {
width: 80rpx;
height: 80rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 15rpx;
background-color: #f0f9eb;
margin-right: 20rpx;
flex-shrink: 0;
}
/* 图标文本样式 */
.icon-text {
font-size: 36rpx;
line-height: 1;
text-align: center;
}
/* 异常徽章样式 */
.exception-badge {
position: absolute;
top: -8rpx;
right: -8rpx;
min-width: 36rpx;
height: 36rpx;
padding: 0 12rpx;
background-color: #f56c6c;
color: #fff;
border-radius: 18rpx;
font-size: 20rpx;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 8rpx rgba(245, 108, 108, 0.5);
}
/* 图标容器相对定位,用于异常徽章 */
.feature-icon {
position: relative;
}
/* 各模块颜色 */
.distributor .icon-container {
.distributor-icon {
background-color: #ecf5ff;
}
.user .icon-container {
.user-icon {
background-color: #f0f9eb;
}
.dept .icon-container {
.dept-icon {
background-color: #fdf6ec;
}
.notice .icon-container {
.notice-icon {
background-color: #fef0f0;
}
.log .icon-container {
.log-icon {
background-color: #f4f4f5;
}
.text {
text-align: center;
font-size: 26rpx;
color: #606266;
font-weight: 500;
/* 功能信息 */
.feature-info {
flex: 1;
min-width: 0;
}
.feature-title {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 8rpx;
line-height: 1.3;
}
.feature-desc {
font-size: 22rpx;
color: #909399;
line-height: 1.4;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.work-container {
max-width: 800px;
max-width: 900px;
margin: 0 auto;
padding: 30rpx;
}
.swiper-box {
height: 240px;
.section-title {
font-size: 36rpx;
margin-bottom: 30rpx;
}
.swiper-item {
height: 240px;
.feature-card {
padding: 30rpx;
}
.grid-item-box {
padding: 25rpx 0;
.feature-icon {
width: 100rpx;
height: 100rpx;
margin-right: 24rpx;
}
.icon-text {
font-size: 44rpx;
}
.feature-title {
font-size: 32rpx;
}
.feature-desc {
font-size: 24rpx;
}
}
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.work-container {
max-width: 1000px;
}
.feature-card {
padding: 36rpx;
}
.feature-icon {
width: 120rpx;
height: 120rpx;
}
.icon-text {
font-size: 52rpx;
}
.feature-title {
font-size: 36rpx;
}
.feature-desc {
font-size: 26rpx;
}
}
</style>