Compare commits
74 Commits
Author | SHA1 | Date | |
---|---|---|---|
3dc4d64215 | |||
a3ffe71ccb | |||
342e97d5d6 | |||
e0684ec229 | |||
f47e375bfa | |||
23ab2798d8 | |||
1b4d3e310b | |||
2b48faf50d | |||
fab8d88faf | |||
5fc1378051 | |||
12480f3706 | |||
05af3d221c | |||
f17226cc97 | |||
d5e4f0d7eb | |||
d17f6f09c5 | |||
8a085da7dc | |||
f871831cbc | |||
c1817b6255 | |||
85df7bfc4e | |||
990f1850b1 | |||
c7dd90f669 | |||
d1b4fa8ca3 | |||
3996895c0d | |||
c5f3287e80 | |||
b6a59ce3d8 | |||
2a1082fc9f | |||
90162ad74f | |||
50e892adc4 | |||
0587539253 | |||
5c2082adf4 | |||
fa2a7b3499 | |||
a1d21c67b8 | |||
53d0cc6767 | |||
1a8bcbec9f | |||
0e20be0425 | |||
2350346d95 | |||
b360697a37 | |||
9241e3bce3 | |||
8c0a108e8f | |||
ade53fa60f | |||
9b8b40d2ed | |||
5093eb3058 | |||
3ce43e880d | |||
1e2593fd3b | |||
a5da14642b | |||
0de7e859c2 | |||
152b4995ca | |||
a797150e3e | |||
3d1e60edc5 | |||
c93b471625 | |||
e608c02f8b | |||
2399168f8e | |||
949d39b1b9 | |||
1ef99032ec | |||
d6761b460c | |||
d6bfd2d262 | |||
bd98398c4e | |||
ea403c8ed9 | |||
a8d326cc5f | |||
a48fa01050 | |||
8ea2d7a89e | |||
fc957770ce | |||
6f06dfd826 | |||
7603d8c96c | |||
0739bdcbb8 | |||
dc3837dbff | |||
a51f9bdea8 | |||
ae9886635d | |||
a20fbe81e3 | |||
4d40d86061 | |||
7d63133f54 | |||
8d95fb089d | |||
179f70b65d | |||
c0c6b5b61a |
4
app.js
@ -1,6 +1,6 @@
|
||||
const { checkLogin } = require('./utils/logcheck');
|
||||
App({
|
||||
onLaunch() {
|
||||
// checkLogin();
|
||||
onLaunch: function () {
|
||||
// checkLogin()
|
||||
}
|
||||
});
|
||||
|
34
app.json
@ -1,9 +1,11 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/welcome/homePage/homePage",
|
||||
"pages/loginModule/pwdLogin/pwdLogin",
|
||||
"pages/personCenter/mine/mine",
|
||||
"pages/loginModule/agreement/agreement",
|
||||
"pages/loginModule/privacyPolicy/privacyPolicy",
|
||||
"pages/personCenter/subCommissionSetting/subCommissionSetting",
|
||||
"pages/test/testVideo/testVideo",
|
||||
"pages/personCenter/withdrawal/withdrawal",
|
||||
"pages/personCenter/withdrawalAccount/withdrawalAccount",
|
||||
"pages/personCenter/accountSetting/accountSetting",
|
||||
@ -21,7 +23,27 @@
|
||||
"pages/personCenter/commissionSetting/commissionSetting",
|
||||
"pages/personCenter/resetPwd/resetPwd",
|
||||
"pages/personCenter/bindBankCard/bindBankCard",
|
||||
"pages/projectModule/settlement/settlement"
|
||||
"pages/projectModule/settlement/settlement",
|
||||
"pages/projectModule/subSettlement/subSettlement",
|
||||
"pages/course/homepage/homepage",
|
||||
"pages/course/searchCourses/searchCourses",
|
||||
"pages/course/courseList/courseList",
|
||||
"pages/course/courseDetail/courseDetail",
|
||||
"pages/course/createCourseOrder/createCourseOrder",
|
||||
"pages/course/orderDetail/orderDetail",
|
||||
"pages/course/applyPromotion/applyPromotion",
|
||||
"pages/course/recommendUser/recommendUser",
|
||||
"pages/course/courseOrderList/courseOrderList",
|
||||
"pages/course/courseSettlementRecord/courseSettlementRecord",
|
||||
"pages/loginModule/employeeAccountApply/employeeAccountApply",
|
||||
"pages/loginModule/employeeAccountNotice/employeeAccountNotice",
|
||||
"pages/loginModule/employeeApplyQuery/employeeApplyQuery",
|
||||
"pages/dashboardModule/overviewPerformance/overviewPerformance",
|
||||
"pages/dashboardModule/supervisorPerformance/supervisorPerformance",
|
||||
"pages/dashboardModule/staffPerformance/staffPerformance",
|
||||
"pages/dashboardModule/userOrderPerformance/userOrderPerformance",
|
||||
"pages/dashboardModule/performanceRanking/performanceRanking",
|
||||
"pages/personCenter/component/modifyNamePop/modifyNamePop"
|
||||
],
|
||||
"window": {
|
||||
"navigationBarTextStyle": "black",
|
||||
@ -39,10 +61,10 @@
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/projectModule/projectList/projectList",
|
||||
"text": "接单",
|
||||
"iconPath": "/static/jd1.png",
|
||||
"selectedIconPath": "/static/jd2.png"
|
||||
"pagePath": "pages/course/homepage/homepage",
|
||||
"text": "主页",
|
||||
"iconPath": "/static/kc1.png",
|
||||
"selectedIconPath": "/static/kc2.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/personCenter/mine/mine",
|
||||
|
160
pages/course/applyPromotion/applyPromotion.js
Normal file
@ -0,0 +1,160 @@
|
||||
// pages/course/applyPromotion/applyPromotion.js
|
||||
Page({
|
||||
|
||||
data: {
|
||||
showCode: false,
|
||||
buttonText: '生成推广码',
|
||||
codeImageUrl: 'https://img.picui.cn/free/2025/06/24/685a8953cae83.png'
|
||||
},
|
||||
|
||||
// 点击“生成推广码”或“查看推荐的用户”
|
||||
handleGenerate() {
|
||||
if (!this.data.showCode) {
|
||||
// 1. 显示带遮罩的 loading,防止用户点击其他地方
|
||||
wx.showLoading({
|
||||
title: '生成中...',
|
||||
mask: true
|
||||
});
|
||||
|
||||
// 2. 调用后端接口生成推广码图片
|
||||
wx.request({
|
||||
url: 'https://your-backend.com/api/generatePromotionCode', // TODO: 替换成你真实的接口地址
|
||||
method: 'POST',
|
||||
data: {
|
||||
// 如果需要传用户信息或参数,在这里补充
|
||||
},
|
||||
success: res => {
|
||||
if (1) {
|
||||
// 3. 接口返回正确,更新图片地址并显示
|
||||
this.setData({
|
||||
codeImageUrl: res.data.imageUrl,
|
||||
showCode: true,
|
||||
buttonText: '查看推荐的用户'
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '生成失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '网络错误,请检查连接',
|
||||
icon: 'none'
|
||||
});
|
||||
},
|
||||
complete: () => {
|
||||
// 4. 隐藏 loading
|
||||
wx.hideLoading();
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
// 已生成时,跳转到查看推荐用户页(如有)
|
||||
wx.navigateTo({
|
||||
url: '/pages/course/recommendUser/recommendUser',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 保存图片到相册(与之前一致)
|
||||
saveImage() {
|
||||
const {
|
||||
codeImageUrl
|
||||
} = this.data;
|
||||
wx.showLoading({
|
||||
title: '保存中...',
|
||||
mask: true
|
||||
});
|
||||
wx.downloadFile({
|
||||
url: codeImageUrl,
|
||||
success: res => {
|
||||
if (res.statusCode === 200) {
|
||||
wx.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
},
|
||||
fail: err => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '保存失败',
|
||||
icon: 'none'
|
||||
});
|
||||
console.error('saveImageToPhotosAlbum 失败', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: err => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '下载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
console.error('downloadFile 失败', err);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
36
pages/course/applyPromotion/applyPromotion.wxml
Normal file
@ -0,0 +1,36 @@
|
||||
<!-- pages/course/applyPromotion/applyPromotion.wxml -->
|
||||
<view class="flex-col page">
|
||||
<view class="flex-col items-center group">
|
||||
<!-- 生成推广码按钮,文字垂直居中,点击触发 handleGenerate -->
|
||||
<view class="flex-col justify-center items-center text-wrapper" bindtap="handleGenerate">
|
||||
<text class="font text">{{buttonText}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 只有当 showCode 为 true 时才显示推广码图片 -->
|
||||
<image
|
||||
wx:if="{{showCode}}"
|
||||
class="mt-12 image"
|
||||
src="{{codeImageUrl}}"
|
||||
/>
|
||||
|
||||
<!-- 只有当 showCode 为 true 时才显示保存图片按钮,且垂直居中 -->
|
||||
<view
|
||||
wx:if="{{showCode}}"
|
||||
class="mt-12 flex-col justify-center items-center text-wrapper_2"
|
||||
bindtap="saveImage"
|
||||
>
|
||||
<text class="font">保存图片</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex-col section">
|
||||
<view class="flex-row items-center group_2">
|
||||
<image
|
||||
class="image_2"
|
||||
src="./image/wenhao.png"
|
||||
/>
|
||||
<text class="ml-6 font text_2">推广码说明</text>
|
||||
</view>
|
||||
<view class="section_2"></view>
|
||||
</view>
|
||||
</view>
|
61
pages/course/applyPromotion/applyPromotion.wxss
Normal file
@ -0,0 +1,61 @@
|
||||
/* pages/course/applyPromotion/applyPromotion.wxss */
|
||||
.page {
|
||||
background-color: #f6f7f9;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
.group {
|
||||
padding: 69.38rpx 0 52.5rpx;
|
||||
}
|
||||
/* 上下居中改由 justify-center 控制,无需修改原有 padding */
|
||||
.text-wrapper {
|
||||
padding: 30rpx 0 30rpx;
|
||||
background-color: #a5d63f;
|
||||
border-radius: 46.07rpx;
|
||||
width: 395.63rpx;
|
||||
}
|
||||
.image {
|
||||
width: 667.5rpx;
|
||||
height: 763.13rpx;
|
||||
}
|
||||
.text-wrapper_2 {
|
||||
padding: 30rpx 0 30rpx;
|
||||
background-color: #ff8d1a;
|
||||
border-radius: 46.07rpx;
|
||||
width: 395.63rpx;
|
||||
}
|
||||
.section {
|
||||
padding: 0 30rpx 60rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.group_2 {
|
||||
padding: 35.63rpx 0 30rpx;
|
||||
}
|
||||
.image_2 {
|
||||
width: 45rpx;
|
||||
height: 45rpx;
|
||||
}
|
||||
.font {
|
||||
font-size: 30rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 27.99rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
.text {
|
||||
line-height: 28.29rpx;
|
||||
}
|
||||
.text_2 {
|
||||
color: #000000;
|
||||
font-size: 28.13rpx;
|
||||
line-height: 26.19rpx;
|
||||
}
|
||||
.section_2 {
|
||||
background-color: #ffffff00;
|
||||
height: 813.75rpx;
|
||||
border-left: solid 1.88rpx #000000;
|
||||
border-right: solid 1.88rpx #000000;
|
||||
border-top: solid 1.88rpx #000000;
|
||||
border-bottom: solid 1.88rpx #000000;
|
||||
}
|
BIN
pages/course/applyPromotion/image/wenhao.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
103
pages/course/courseDetail/courseDetail.js
Normal file
@ -0,0 +1,103 @@
|
||||
import { baseUrl, globalImgUrl } from "../../../request";
|
||||
import { decodeBase64 } from "../../../utils/decodebase64";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
|
||||
// pages/course/courseDetail/courseDetail.js
|
||||
Page({
|
||||
data: {
|
||||
activeTab: 'intro', // 默认选中“课程简介”
|
||||
activeIndex: null, // 默认没有任何标题被选中
|
||||
cid: 0, // 课程ID
|
||||
courseObj: '', // 课程对象
|
||||
richText: '', // 课程概述富文本
|
||||
globalImgUrl,
|
||||
},
|
||||
|
||||
// 获取课程详情
|
||||
getCourseDetail() {
|
||||
const cid = this.data.cid;
|
||||
wx.request({
|
||||
url: baseUrl + '/course/query/id',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: cid
|
||||
},
|
||||
header: {
|
||||
Authorization :wx.getStorageSync('token'),
|
||||
},
|
||||
success : res => {
|
||||
console.log(res);
|
||||
if (res.data.code === 1) {
|
||||
this.setData({
|
||||
courseObj: res.data.data,
|
||||
richText: decodeBase64(res.data.data.detail)
|
||||
})
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 切换选项卡 */
|
||||
selectTab(e) {
|
||||
const tab = e.currentTarget.dataset.tab;
|
||||
this.setData({ activeTab: tab });
|
||||
},
|
||||
|
||||
/** 选择课程标题 */
|
||||
selectCourse(e) {
|
||||
const index = e.currentTarget.dataset.index;
|
||||
this.setData({
|
||||
activeIndex: index // 设置选中的课程标题索引
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转课程订单创建页面
|
||||
gotoCourseOrder(e) {
|
||||
const courseId = e.currentTarget.dataset.id;
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/createCourseOrder/createCourseOrder?id=${courseId}`,
|
||||
})
|
||||
},
|
||||
|
||||
// 好像不要了
|
||||
// 跳转申请推广页面
|
||||
gotoApplyPromotion(e) {
|
||||
const courseId = e.currentTarget.dataset.id;
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/applyPromotion/applyPromotion?id=${courseId}`,
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
console.log(options);
|
||||
this.setData({
|
||||
cid: options.id,
|
||||
})
|
||||
this.getCourseDetail()
|
||||
},
|
||||
|
||||
onReady() {},
|
||||
|
||||
onShow() {},
|
||||
|
||||
onHide() {},
|
||||
|
||||
onUnload() {},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.getCourseDetail()
|
||||
// 停止下拉刷新动画
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
onReachBottom() {},
|
||||
|
||||
onShareAppMessage() {}
|
||||
});
|
4
pages/course/courseDetail/courseDetail.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
47
pages/course/courseDetail/courseDetail.wxml
Normal file
@ -0,0 +1,47 @@
|
||||
<!-- pages/course/courseDetail/courseDetail.wxml -->
|
||||
<view class="page">
|
||||
<!-- 滚动内容 -->
|
||||
<scroll-view scroll-y class="content no-scrollbar">
|
||||
<!-- 顶部主图 -->
|
||||
<view class="hero">
|
||||
<image class="hero-img" src="{{ globalImgUrl + courseObj.image }}" mode="aspectFill" lazy-load="true" />
|
||||
</view>
|
||||
|
||||
<!-- 价格 + 标题 -->
|
||||
<view class="card">
|
||||
<view class="price-row">
|
||||
<view class="price-now">
|
||||
<text class="price-num">{{ courseObj.discountPrice }}</text>
|
||||
<text class="price-suffix">元券后价</text>
|
||||
</view>
|
||||
<view class="price-origin">
|
||||
<text class="origin-text">{{ courseObj.originPrice }}元</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="title">{{ courseObj.name }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 课程概述 -->
|
||||
<view class="card">
|
||||
<view class="card-head">
|
||||
<image class="head-icon" src="./image/cal.png" mode="aspectFit" />
|
||||
<text class="head-text">课程概述</text>
|
||||
</view>
|
||||
<rich-text class="rt" nodes="{{ richText }}"></rich-text>
|
||||
</view>
|
||||
|
||||
<!-- 占位,避免被底部栏遮挡 -->
|
||||
<view class="bottom-gap"></view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 固定底部购买栏 -->
|
||||
<view class="buy-bar">
|
||||
<view class="buy-left">
|
||||
<image class="consult-icon" src="./image/messge.png" mode="aspectFit" />
|
||||
<text class="consult-text">咨询</text>
|
||||
</view>
|
||||
<view class="buy-btn" bindtap="gotoCourseOrder" data-id="{{ courseObj.id }}">
|
||||
<text class="buy-btn-text">立即购买</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
148
pages/course/courseDetail/courseDetail.wxss
Normal file
@ -0,0 +1,148 @@
|
||||
/* pages/course/courseDetail/courseDetail.wxss */
|
||||
|
||||
/* ===== 页面骨架:整页固定、内容滚动、底部栏固定 ===== */
|
||||
.page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #f6f7f9;
|
||||
overflow: auto; /* 禁止整页滚动 */
|
||||
box-sizing: border-box;
|
||||
font-family: SourceHanSansCN, PingFang SC, Microsoft YaHei, system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
/* 独立滚动内容区(隐藏滚动条) */
|
||||
.content {
|
||||
flex: 1;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.no-scrollbar::-webkit-scrollbar { display: none; width: 0; height: 0; background: transparent; }
|
||||
.no-scrollbar { scrollbar-width: none; }
|
||||
|
||||
/* ===== 顶部主图(自适应圆角阴影) ===== */
|
||||
.hero {
|
||||
padding: 24rpx 24rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.hero-img {
|
||||
width: 100%;
|
||||
height: 420rpx; /* 沉浸横幅高度 */
|
||||
border-radius: 20rpx;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 12rpx 30rpx rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
/* ===== 通用卡片容器 ===== */
|
||||
.card {
|
||||
margin: 20rpx 24rpx 0;
|
||||
padding: 22rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 10rpx 30rpx rgba(0,0,0,0.05);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ===== 价格区:券后价 + 原价 ===== */
|
||||
.price-row {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.price-now { display: inline-flex; align-items: baseline; gap: 8rpx; }
|
||||
.price-num {
|
||||
font-size: 44rpx;
|
||||
line-height: 1;
|
||||
color: #ff6a00; /* 主题橙 */
|
||||
font-weight: 700;
|
||||
}
|
||||
.price-suffix { font-size: 24rpx; color: #ff6a00; opacity: .9; }
|
||||
.price-origin .origin-text { font-size: 24rpx; color: #9aa0a6; text-decoration: line-through; }
|
||||
|
||||
/* 课程标题 */
|
||||
.title {
|
||||
display: block;
|
||||
margin-top: 14rpx;
|
||||
font-size: 32rpx;
|
||||
line-height: 46rpx;
|
||||
color: #111;
|
||||
font-weight: 600;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* ===== 概述标题行 ===== */
|
||||
.card-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 22rpx;
|
||||
}
|
||||
.head-icon { width: 34rpx; height: 34rpx; }
|
||||
.head-text { font-size: 28rpx; color: #111; font-weight: 600; }
|
||||
|
||||
/* rich-text 内容排版(图片适配) */
|
||||
.rt {
|
||||
font-size: 26rpx;
|
||||
line-height: 42rpx;
|
||||
color: #333;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
.rt p { margin: 8rpx 0; }
|
||||
.rt img { max-width: 100%; height: auto !important; border-radius: 12rpx; }
|
||||
|
||||
/* 底部占位,避免被购买栏遮挡 */
|
||||
.bottom-gap {
|
||||
height: calc(env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* ===== 固定底部购买栏(含安全区) ===== */
|
||||
.buy-bar {
|
||||
position: sticky;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
padding: 12rpx 24rpx calc(12rpx + env(safe-area-inset-bottom));
|
||||
background: #ffffff;
|
||||
box-shadow: 0 -8rpx 20rpx rgba(0,0,0,0.06);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* 左侧咨询 */
|
||||
.buy-left {
|
||||
display: inline-flex; align-items: center; gap: 10rpx;
|
||||
padding: 12rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #f0f2f5;
|
||||
}
|
||||
.consult-icon { width: 36rpx; height: 36rpx; }
|
||||
.consult-text { font-size: 24rpx; color: #333; }
|
||||
|
||||
/* 右侧按钮 */
|
||||
.buy-btn {
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
border-radius: 9999rpx;
|
||||
background: linear-gradient(90deg, #ff6a00, #ff8a2a);
|
||||
box-shadow: 0 10rpx 24rpx rgba(255,106,0,0.26);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.buy-btn-text {
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* ===== 小的间距工具(保留你原有语义) ===== */
|
||||
.mt-9 { margin-top: 16rpx; }
|
||||
.mt-37 { margin-top: 68rpx; }
|
||||
.mt-1 { margin-top: 2rpx; }
|
||||
|
||||
/* 你之前的 class 若仍在别处使用,可继续保留或删去:
|
||||
.image, .section, .group, .group_2, .group_3, .divider, .pos, .text_4, .section_2, .group_4, .image_2, .font, .text_3, .text_2, .text_5, .section_3, .section_4, .image_3, .text_7, .text-wrapper, .text_6
|
||||
当前新版未依赖它们。 */
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: transparent;
|
||||
}
|
BIN
pages/course/courseDetail/image/cal.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
pages/course/courseDetail/image/cal1.png
Normal file
After Width: | Height: | Size: 753 B |
BIN
pages/course/courseDetail/image/lock.png
Normal file
After Width: | Height: | Size: 517 B |
BIN
pages/course/courseDetail/image/messge.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
136
pages/course/courseList/courseList.js
Normal file
@ -0,0 +1,136 @@
|
||||
import { baseUrl, globalImgUrl } from "../../../request";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
// pages/course/courseList/courseList.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
courseList:[], // 课程列表
|
||||
courseType: '', // 课程类别
|
||||
globalImgUrl,
|
||||
tempCourseList: [],
|
||||
searchKeyword: ''
|
||||
},
|
||||
|
||||
// 跳转课程详情页面
|
||||
gotoCourseDetail(e) {
|
||||
|
||||
const courseId = e.currentTarget.dataset.id;
|
||||
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/courseDetail/courseDetail?id=${courseId}` ,
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
const keyword = (e.detail.value || '').trim();
|
||||
this.setData({ searchKeyword: keyword });
|
||||
},
|
||||
// 键盘“搜索/回车”触发:立即搜索
|
||||
onSearch() {
|
||||
const { tempCourseList } = this.data
|
||||
const keyword = (this.data.searchKeyword || '').trim();
|
||||
if (!keyword) {
|
||||
this.setData({courseList: tempCourseList})
|
||||
return;
|
||||
}
|
||||
// 模糊匹配 name
|
||||
const filtered = this.data.courseList.filter(item => item.name.includes(keyword)
|
||||
);
|
||||
this.setData({ courseList: filtered });
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 接收路由参数 type 作为搜索关键字
|
||||
const courseType = options.type || '';
|
||||
this.setData({ courseType }, () => {
|
||||
this.fetchCourseList();
|
||||
});
|
||||
},
|
||||
|
||||
// 从后端拉取课程列表
|
||||
fetchCourseList() {
|
||||
wx.request({
|
||||
url: baseUrl + '/course/query/type',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: {
|
||||
templateString: this.data.courseType
|
||||
},
|
||||
success: res => {
|
||||
console.log('课程列表',res.data.data);
|
||||
if (res.data.code === 1) {
|
||||
this.setData({
|
||||
courseList: res.data.data,
|
||||
tempCourseList: res.data.data
|
||||
});
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: err => {
|
||||
console.error('request failed', err);
|
||||
wx.showToast({
|
||||
icon: 'none',
|
||||
title: '网络请求失败',
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
3
pages/course/courseList/courseList.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
38
pages/course/courseList/courseList.wxml
Normal file
@ -0,0 +1,38 @@
|
||||
<!-- pages/course/searchCourses/searchCourses.wxml -->
|
||||
<view class="page">
|
||||
|
||||
<!-- 顶部搜索条(固定) -->
|
||||
<view class="search-bar" hover-class="hover">
|
||||
<image class="search-icon" src="./image/sousuo.png" mode="aspectFit"/>
|
||||
<input
|
||||
class="search-input"
|
||||
placeholder="搜索更多好课"
|
||||
placeholder-class="search-ph"
|
||||
bindinput="onSearchInput"
|
||||
confirm-type="search"
|
||||
bindconfirm="onSearch"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果(独立滚动 & 隐藏滚动条) -->
|
||||
<scroll-view scroll-y class="list no-scrollbar">
|
||||
<block wx:for="{{courseList}}" wx:for-item="item" wx:key="item.id">
|
||||
<view class="course-card" bindtap="gotoCourseDetail" data-id="{{item.id}}" hover-class="hover">
|
||||
<image class="cover" src="{{ globalImgUrl + item.image }}" mode="aspectFill" lazy-load="true"/>
|
||||
<view class="info">
|
||||
<text class="title">{{item.name}}</text>
|
||||
<view class="meta">
|
||||
<text class="price-pill">券后{{item.discountPrice}}元起</text>
|
||||
<text class="people">{{item.orderCount}}人学习</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 空状态(可选) -->
|
||||
<view wx:if="{{!courseList || courseList.length === 0}}" class="empty">
|
||||
<image class="empty-icon" src="/static/empty.png" mode="aspectFit"/>
|
||||
<text class="empty-text">没找到相关课程,换个关键词试试~</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
131
pages/course/courseList/courseList.wxss
Normal file
@ -0,0 +1,131 @@
|
||||
/* pages/course/searchCourses/searchCourses.wxss */
|
||||
|
||||
/* ===== 页面骨架:整页固定,列表单独滚动 ===== */
|
||||
.page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #ffffff;
|
||||
overflow: hidden; /* 禁止整页滚动 */
|
||||
box-sizing: border-box;
|
||||
font-family: SourceHanSansCN, PingFang SC, Microsoft YaHei, system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* 轻触反馈 */
|
||||
.hover { opacity: .86; transition: opacity .18s ease; }
|
||||
|
||||
/* ===== 顶部搜索条(固定) ===== */
|
||||
.search-bar {
|
||||
padding: 24rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
background: #fff;
|
||||
}
|
||||
.search-icon { width: 36rpx; height: 36rpx; opacity: .9; }
|
||||
|
||||
/* 胶囊输入框 */
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
padding: 0 26rpx;
|
||||
border-radius: 9999rpx;
|
||||
background: #f5f6f7;
|
||||
font-size: 26rpx;
|
||||
color: #111;
|
||||
line-height: 72rpx;
|
||||
box-shadow: inset 0 0 0 1rpx rgba(0,0,0,.04);
|
||||
}
|
||||
.search-ph { color: #a8a8a8; font-size: 26rpx; }
|
||||
|
||||
/* ===== 列表:占满剩余高度,单独滚动,隐藏滚动条 ===== */
|
||||
.list {
|
||||
flex: 1;
|
||||
padding: 0 24rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
background: #fff;
|
||||
}
|
||||
.no-scrollbar::-webkit-scrollbar { display: none; width: 0; height: 0; background: transparent; }
|
||||
.no-scrollbar { scrollbar-width: none; }
|
||||
|
||||
/* ===== 课程卡片(左图右文) ===== */
|
||||
.course-card {
|
||||
display: flex;
|
||||
gap: 22rpx;
|
||||
padding: 20rpx;
|
||||
margin-top: 20rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
border: 1rpx solid #f1f1f1;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,.05);
|
||||
}
|
||||
.cover {
|
||||
width: 280rpx; /* 3:2 比例更舒服 */
|
||||
height: 186rpx;
|
||||
flex: 0 0 280rpx;
|
||||
border-radius: 14rpx;
|
||||
object-fit: cover;
|
||||
}
|
||||
.info {
|
||||
flex: 1;
|
||||
min-width: 0; /* 防文字溢出 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #111;
|
||||
font-weight: 600;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2; /* 两行省略 */
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
.meta {
|
||||
margin-top: 12rpx;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.price-pill {
|
||||
padding: 6rpx 14rpx;
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
border-radius: 9999rpx;
|
||||
background: linear-gradient(90deg, #ff6a00, #ff8a2a);
|
||||
box-shadow: 0 6rpx 16rpx rgba(255,106,0,.22);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.people {
|
||||
font-size: 22rpx;
|
||||
color: #9aa0a6;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ===== 空状态 ===== */
|
||||
.empty {
|
||||
padding: 120rpx 0 80rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 18rpx;
|
||||
color: #9aa0a6;
|
||||
}
|
||||
.empty-icon { width: 240rpx; height: 240rpx; opacity: .7; }
|
||||
.empty-text { font-size: 24rpx; line-height: 34rpx; }
|
||||
|
||||
/* ===== 兼容你项目里可能已有的工具类(可留可删) ===== */
|
||||
.ml-3 { margin-left: 6rpx; }
|
||||
.mt-17 { margin-top: 12rpx; }
|
BIN
pages/course/courseList/image/sousuo.png
Normal file
After Width: | Height: | Size: 812 B |
242
pages/course/courseOrderList/courseOrderList.js
Normal file
@ -0,0 +1,242 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
// pages/course/courseOrderList/courseOrderList.js
|
||||
Page({
|
||||
data: {
|
||||
orderList: [], // 后端返回的订单列表
|
||||
hasModalShown: false, // 本次停留页面只弹一次
|
||||
isMaskVisible: false
|
||||
},
|
||||
|
||||
// —— 内部状态(不放 data,避免多余 setData)
|
||||
_timer: null,
|
||||
_isActive: false, // 页面是否处于“可见/激活”状态
|
||||
_justEnteredAt: 0, // 进入页面时刻(可按需使用)
|
||||
|
||||
onLoad() {
|
||||
this._isActive = true;
|
||||
this._justEnteredAt = Date.now();
|
||||
this.fetchOrders();
|
||||
},
|
||||
onShow() {
|
||||
this._isActive = true;
|
||||
this.fetchOrders(); // 如不想重复拉取可注释
|
||||
},
|
||||
onHide() {
|
||||
this._isActive = false;
|
||||
this._clearTimer();
|
||||
},
|
||||
onUnload() {
|
||||
this._isActive = false;
|
||||
this._clearTimer();
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.fetchOrders(); // stopPullDownRefresh 在 complete 里
|
||||
},
|
||||
|
||||
// ========= 工具函数 =========
|
||||
_clearTimer() {
|
||||
if (this._timer) {
|
||||
clearInterval(this._timer);
|
||||
this._timer = null;
|
||||
}
|
||||
},
|
||||
_pad2(n) {
|
||||
return String(n).padStart(2, '0');
|
||||
},
|
||||
_fmtCountDownStr(totalSec) {
|
||||
const sec = Math.max(0, totalSec | 0);
|
||||
const m = Math.floor(sec / 60);
|
||||
const s = sec % 60;
|
||||
return `${this._pad2(m)}分${this._pad2(s)}秒`;
|
||||
},
|
||||
|
||||
// ========= 拉单 =========
|
||||
fetchOrders() {
|
||||
wx.request({
|
||||
url: baseUrl + '/courseOrder/query/list',
|
||||
method: 'POST',
|
||||
header: { Authorization: wx.getStorageSync('token') },
|
||||
success: res => {
|
||||
if (res.data.code === 1) {
|
||||
const now = Date.now();
|
||||
const list = (res.data.data || []).map(it => {
|
||||
// 解析时间(iOS 兼容 + NaN 兜底)
|
||||
const ts = new Date(String(it.createTime).replace(/-/g, '/')).getTime();
|
||||
const createMs = Number.isFinite(ts) ? ts : now;
|
||||
|
||||
// 统一按 15 分钟有效期(若后端返回 expireTime,建议直接用)
|
||||
const ttlMs = 15 * 60 * 1000;
|
||||
let diff = Math.floor((createMs + ttlMs - now) / 1000);
|
||||
diff = Math.max(0, diff);
|
||||
|
||||
if (it.orderStatus === '待支付') {
|
||||
it.countDown = diff;
|
||||
it.countDownStr = this._fmtCountDownStr(diff);
|
||||
it._expiredNotified = false; // 每单的本地防重复标记
|
||||
|
||||
// 初始化阶段:如果已经超时(diff=0),静默转关闭,不弹窗
|
||||
if (diff === 0) {
|
||||
it.orderStatus = '交易关闭';
|
||||
it.countDownStr = '';
|
||||
}
|
||||
} else {
|
||||
it.countDown = 0;
|
||||
it.countDownStr = '';
|
||||
}
|
||||
return it;
|
||||
});
|
||||
|
||||
// 渲染 + 启动定时器
|
||||
this.setData({ orderList: list }, () => this._startTimer());
|
||||
} else {
|
||||
notLogin(res.data.message);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
},
|
||||
complete: () => {
|
||||
wx.stopPullDownRefresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// ========= 定时器刷新 =========
|
||||
_startTimer() {
|
||||
this._clearTimer();
|
||||
// 如果已经没有“待支付”的订单,就不启动定时器
|
||||
const hasPending = this.data.orderList.some(o => o.orderStatus === '待支付' && o.countDown > 0);
|
||||
if (!hasPending) return;
|
||||
|
||||
this._timer = setInterval(() => {
|
||||
// 不在激活页时不做任何 UI 相关动作(同时兜底不弹窗)
|
||||
if (!this._isActive) return;
|
||||
|
||||
let needRerender = false;
|
||||
const updated = this.data.orderList.map(item => {
|
||||
if (item.orderStatus === '待支付' && item.countDown > 0) {
|
||||
const next = item.countDown - 1;
|
||||
item.countDown = next;
|
||||
item.countDownStr = this._fmtCountDownStr(next);
|
||||
needRerender = true;
|
||||
|
||||
if (next <= 0) {
|
||||
item.orderStatus = '交易关闭';
|
||||
item.countDownStr = '';
|
||||
|
||||
// —— 仅在“当前页面可见”时弹一次,并且每单只弹一次;本页全局也只弹一次
|
||||
if (this._isActive && !item._expiredNotified && !this.data.hasModalShown) {
|
||||
item._expiredNotified = true;
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '订单超时未支付,已关闭',
|
||||
showCancel: false
|
||||
});
|
||||
this.setData({ hasModalShown: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
if (needRerender) {
|
||||
this.setData({ orderList: updated }, () => {
|
||||
// 如果已经没有可继续倒计时的订单,关掉定时器
|
||||
const stillPending = this.data.orderList.some(o => o.orderStatus === '待支付' && o.countDown > 0);
|
||||
if (!stillPending) this._clearTimer();
|
||||
});
|
||||
} else {
|
||||
// 没有需要更新的也关掉
|
||||
this._clearTimer();
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
// ========= 支付相关 =========
|
||||
showIsPayModal(e) {
|
||||
const orderId = e.currentTarget.dataset.orderId;
|
||||
wx.showModal({
|
||||
title: '确认支付',
|
||||
content: '是否立即支付该订单?',
|
||||
cancelText: '取消',
|
||||
confirmText: '去支付',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.payOrder(orderId);
|
||||
} else if (res.cancel) {
|
||||
this.setData({ isMaskVisible: false });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
payOrder(orderId) {
|
||||
this.setData({ isMaskVisible: true });
|
||||
wx.showLoading({ title: '支付中...' });
|
||||
wx.request({
|
||||
url: baseUrl + '/courseOrder/payment',
|
||||
method: 'POST',
|
||||
header: { Authorization: wx.getStorageSync('token') },
|
||||
data: { id: orderId }, // 与后端约定:支付接口传 id;若传 orderId 则改键名
|
||||
success: res => {
|
||||
wx.hideLoading();
|
||||
if (res.data.code === 1) {
|
||||
wx.redirectTo({
|
||||
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
|
||||
complete: () => {
|
||||
this.setData({ isMaskVisible: false });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.setData({ isMaskVisible: false });
|
||||
wx.showToast({ title: res.data.message || '支付失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.hideLoading();
|
||||
this.setData({ isMaskVisible: false });
|
||||
wx.showToast({ title: '网络错误,支付失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// ========= 跳转 & 取消 =========
|
||||
gotoOrderDetail(e) {
|
||||
const orderId = e.currentTarget.dataset.id;
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
|
||||
});
|
||||
},
|
||||
|
||||
cancelOrder(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
wx.showModal({
|
||||
title: '取消订单',
|
||||
content: '是否要取消该订单?',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
wx.request({
|
||||
url: baseUrl + "/courseOrder/cancel",
|
||||
method: 'POST',
|
||||
header: { Authorization: wx.getStorageSync('token') },
|
||||
data: { id }, // 如果后端需要 { orderId: id },改这里的键名即可
|
||||
success: r => {
|
||||
if (r.data && r.data.code !== 1) {
|
||||
wx.showToast({ title: r.data.message || '取消失败', icon: 'none' });
|
||||
}
|
||||
this.fetchOrders();
|
||||
},
|
||||
fail: () => wx.showToast({ title: '网络错误', icon: 'none' })
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
4
pages/course/courseOrderList/courseOrderList.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
55
pages/course/courseOrderList/courseOrderList.wxml
Normal file
@ -0,0 +1,55 @@
|
||||
<!-- pages/course/courseOrderList/courseOrderList.wxml -->
|
||||
<view class="page">
|
||||
|
||||
<!-- 列表滚动区 -->
|
||||
<scroll-view scroll-y class="content no-scrollbar">
|
||||
|
||||
<!-- 空状态(可选) -->
|
||||
<view wx:if="{{ !orderList || orderList.length === 0 }}" class="empty">
|
||||
<image class="empty-img" src="./image/empty.png" mode="aspectFit" />
|
||||
<text class="empty-text">暂无订单</text>
|
||||
</view>
|
||||
|
||||
<!-- 订单卡片列表 -->
|
||||
<view wx:for="{{ orderList }}"
|
||||
wx:for-item="item"
|
||||
wx:for-index="index"
|
||||
wx:key="id"
|
||||
class="card order-item"
|
||||
bind:tap="gotoOrderDetail"
|
||||
data-id="{{ item.id }}">
|
||||
|
||||
<!-- 顶部:订单号 + 状态徽标 -->
|
||||
<view class="topline">
|
||||
<text class="order-no">订单号:{{ item.orderNumber }}</text>
|
||||
<view class="status-badge {{ item.orderStatus === '待支付' ? 'status-pending' : (item.orderStatus === '已支付' || item.orderStatus === '交易成功' ? 'status-success' : 'status-default') }}">
|
||||
<text class="status-text">{{ item.orderStatus }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 课程名称 -->
|
||||
<text class="course-name ellipsis-2">{{ item.name }}</text>
|
||||
|
||||
<!-- 价格 + 倒计时(仅待支付显示) -->
|
||||
<view class="price-line">
|
||||
<text class="amount">¥{{ item.totalAmount }}</text>
|
||||
<view wx:if="{{ item.orderStatus === '待支付' }}" class="countdown-pill">
|
||||
<text class="countdown-text">请在 {{ item.countDownStr }} 内完成支付</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部:下单时间 + 操作按钮(仅待支付显示) -->
|
||||
<view class="bottomline">
|
||||
<text class="ctime">{{ item.createTime }}</text>
|
||||
<view class="actions" wx:if="{{ item.orderStatus === '待支付' }}">
|
||||
<view class="btn btn-ghost" catch:tap="cancelOrder" data-id="{{ item.id }}">取消订单</view>
|
||||
<view class="btn btn-primary" catch:tap="showIsPayModal" data-order-id="{{ item.id }}">支付</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
|
||||
<!-- 遮罩 -->
|
||||
<view wx:if="{{ isMaskVisible }}" class="page-mask"></view>
|
||||
</view>
|
169
pages/course/courseOrderList/courseOrderList.wxss
Normal file
@ -0,0 +1,169 @@
|
||||
/* ===== 页面与滚动 ===== */
|
||||
.page {
|
||||
background: #f7f7f7;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 24rpx 24rpx; /* 统一外边距 */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 遮罩 */
|
||||
.page-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-color: rgba(0, 0, 0, 0.35);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* ===== 空状态 ===== */
|
||||
.empty {
|
||||
padding: 100rpx 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #999999;
|
||||
}
|
||||
.empty-img { width: 280rpx; height: 280rpx; margin-bottom: 20rpx; }
|
||||
.empty-text { font-size: 28rpx; }
|
||||
|
||||
/* ===== 卡片通用 ===== */
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.05);
|
||||
}
|
||||
.card + .card { margin-top: 20rpx; }
|
||||
|
||||
/* ===== 列表项排版 ===== */
|
||||
.order-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
/* 顶部行:订单号 + 状态 */
|
||||
.topline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.order-no {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
height: 40rpx;
|
||||
padding: 0 18rpx;
|
||||
border-radius: 999rpx;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.status-text {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-pending { background: #fff6e6; color: #ff8d1a; } /* 待支付:主题橙 */
|
||||
.status-success { background: #e9fbef; color: #12b05b; } /* 已/成功:绿色 */
|
||||
.status-default { background: #f0f0f0; color: #666666; } /* 其他:灰 */
|
||||
|
||||
/* 课程名称 */
|
||||
.course-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #1f1f1f;
|
||||
line-height: 44rpx;
|
||||
}
|
||||
.ellipsis-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 价格 + 倒计时 */
|
||||
.price-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.amount {
|
||||
font-size: 34rpx;
|
||||
color: #ff5a1a; /* 与你的小程序橙色系统一 */
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.countdown-pill {
|
||||
background: #fff4f2;
|
||||
border: 1rpx solid #ffd6cc;
|
||||
padding: 0 16rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 999rpx;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.countdown-text {
|
||||
font-size: 22rpx;
|
||||
color: #ff5a1a;
|
||||
}
|
||||
|
||||
/* 底部行:时间 + 操作区 */
|
||||
.bottomline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
padding-top: 8rpx;
|
||||
border-top: 1rpx dashed #f0f0f0;
|
||||
}
|
||||
.ctime {
|
||||
font-size: 24rpx;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
/* 按钮 */
|
||||
.btn {
|
||||
height: 64rpx;
|
||||
min-width: 180rpx;
|
||||
padding: 0 24rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.btn-ghost {
|
||||
background: #ffffff;
|
||||
color: #333333;
|
||||
border: 2rpx solid #e6e6e6;
|
||||
}
|
||||
.btn-primary {
|
||||
background: linear-gradient(180deg, #ffa64a 0%, #ff8d1a 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 6rpx 14rpx rgba(255, 141, 26, 0.25);
|
||||
}
|
||||
|
||||
/* ===== 迁移提示:以下旧的散装类可删除(如无外部依赖) ===== */
|
||||
/* .mt-17, .ml-37, .ml-11, .group_1, .list-item, .group, .font*, .text* 等 */
|
BIN
pages/course/courseOrderList/image/empty.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
@ -0,0 +1,66 @@
|
||||
// pages/course/courseSettlementRecord/courseSettlementRecord.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
items: [null,null,null]
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
<!-- pages/course/courseSettlementRecord/courseSettlementRecord.wxml -->
|
||||
<view class="flex-col page">
|
||||
<text class="self-center text">结算记录</text>
|
||||
<view class="mt-14 flex-col self-stretch">
|
||||
<view class="flex-row items-center section">
|
||||
<image
|
||||
class="image"
|
||||
src="https://ide.code.fun/api/image?token=685b63c64ae84d0012336c74&name=1e77401cdad84f355f02111ca86729e8.png"
|
||||
/>
|
||||
<text class="text_2 ml-3">请输入下单用户</text>
|
||||
</view>
|
||||
<view class="flex-col list">
|
||||
<view class="flex-col list-item mt-13" wx:for="{{items}}" wx:for-item="item" wx:for-index="index" wx:key="index">
|
||||
<!-- 课程标题区保持不变 -->
|
||||
<view class="flex-row group">
|
||||
<image
|
||||
class="shrink-0 image_2"
|
||||
src="https://ide.code.fun/api/image?token=685b63c64ae84d0012336c74&name=6ea8ffd561d2d1408e5cbb4f5ee10374.png"
|
||||
/>
|
||||
<text class="flex-1 self-start font text_3 ml-11">【早鸟42折】掌握CAD技能实战技能实战技能实战工作训练营</text>
|
||||
</view>
|
||||
|
||||
<!-- 重新拆分为单行对齐 -->
|
||||
<view class="flex-row justify-between group_row">
|
||||
<text class="font_2">下单用户</text>
|
||||
<text class="font text_5">{{item.user || 'user_cxz'}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between group_row">
|
||||
<text class="font_2">课程价格</text>
|
||||
<text class="font_3">{{item.price || '¥168'}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between group_row">
|
||||
<text class="font_2">下单数量</text>
|
||||
<text class="font_4">{{item.count || '×1'}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between group_row">
|
||||
<text class="font_2">下单时间</text>
|
||||
<text class="font text_11 nowrap">{{item.orderTime || '2025-06-14 18:30:00'}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between group_row">
|
||||
<text class="font_2">抽成比例</text>
|
||||
<text class="font_5 text_13">{{item.rate || '%10'}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between group_row">
|
||||
<text class="font_2">抽成补贴</text>
|
||||
<text class="font text_14">{{item.subsidy || '¥16.8'}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between group_row">
|
||||
<text class="font_2">结算时间</text>
|
||||
<text class="font text_11 nowrap">{{item.settlementTime || '2025-06-20 18:30:00'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
117
pages/course/courseSettlementRecord/courseSettlementRecord.wxss
Normal file
@ -0,0 +1,117 @@
|
||||
/* pages/course/courseSettlementRecord/courseSettlementRecord.wxss */
|
||||
/* 新增统一行样式 */
|
||||
.group_row {
|
||||
margin-top: 22.5rpx;
|
||||
/* 左右对齐 */
|
||||
padding: 0 3.75rpx;
|
||||
}
|
||||
|
||||
/* 取消 time 文本的宽度限制并防止换行 */
|
||||
.text_11 {
|
||||
/* 去掉原先 width: 240rpx; */
|
||||
width: auto !important;
|
||||
}
|
||||
/* 防止文本换行 */
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 以下为原样式,未作改动 */
|
||||
.ml-3 {
|
||||
margin-left: 5.63rpx;
|
||||
}
|
||||
.mt-13 {
|
||||
margin-top: 24.38rpx;
|
||||
}
|
||||
.ml-11 {
|
||||
margin-left: 20.63rpx;
|
||||
}
|
||||
.page {
|
||||
padding: 30rpx 37.5rpx 785.63rpx;
|
||||
background-image: linear-gradient(180deg, #ff8d1a 0%, #ff8d1a00 31.5%);
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
.text {
|
||||
color: #ffffff;
|
||||
font-size: 33.75rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 31.29rpx;
|
||||
}
|
||||
.section {
|
||||
padding: 15rpx 18.75rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.image {
|
||||
width: 35.63rpx;
|
||||
height: 35.63rpx;
|
||||
}
|
||||
.text_2 {
|
||||
color: #b0b0b0;
|
||||
font-size: 30rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 27.94rpx;
|
||||
}
|
||||
.list {
|
||||
padding-top: 22.5rpx;
|
||||
}
|
||||
.list-item {
|
||||
padding: 22.5rpx 7.5rpx 22.5rpx 18.75rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.list-item:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.group {
|
||||
margin-left: 3.75rpx;
|
||||
margin-right: 22.5rpx;
|
||||
}
|
||||
.image_2 {
|
||||
border-radius: 9.38rpx;
|
||||
width: 196.88rpx;
|
||||
height: 125.63rpx;
|
||||
}
|
||||
.font {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 31.88rpx;
|
||||
color: #000000;
|
||||
}
|
||||
.text_3 {
|
||||
margin-top: 3.75rpx;
|
||||
}
|
||||
.font_2 {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 24.34rpx;
|
||||
color: #000000;
|
||||
}
|
||||
.font_3 {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 21.49rpx;
|
||||
color: #fc2f35;
|
||||
}
|
||||
.font_4 {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 19.24rpx;
|
||||
color: #000000;
|
||||
}
|
||||
.font_5 {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 21.49rpx;
|
||||
color: #0ed062;
|
||||
}
|
||||
.text_13 {
|
||||
/* margin-right: 15rpx; */
|
||||
font-size: 28.13rpx;
|
||||
}
|
||||
.text_14 {
|
||||
font-size: 28.13rpx;
|
||||
}
|
239
pages/course/createCourseOrder/createCourseOrder.js
Normal file
@ -0,0 +1,239 @@
|
||||
import { baseUrl, globalImgUrl } from "../../../request";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
import { decodeBase64 } from "../../../utils/decodebase64";
|
||||
|
||||
// pages/course/createCourseOrder/createCourseOrder.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
courseId: 0, // 课程id
|
||||
courseObj: '', // 课程对象
|
||||
globalImgUrl, // 全局图片
|
||||
isMaskVisible: false,
|
||||
isNoticeVisible: true,
|
||||
noticeHtml: '',
|
||||
},
|
||||
|
||||
// 打开/关闭弹窗
|
||||
openNotice() {
|
||||
this.setData({ isNoticeVisible: true });
|
||||
},
|
||||
closeNotice() {
|
||||
this.setData({ isNoticeVisible: false });
|
||||
},
|
||||
// 阻止冒泡/滚动穿透的空函数
|
||||
noop() {},
|
||||
|
||||
|
||||
|
||||
// 创建订单方法
|
||||
createOrder() {
|
||||
const { courseId } = this.data;
|
||||
// 1. 显示遮罩,阻止二次点击
|
||||
this.setData({ isMaskVisible: true });
|
||||
wx.showLoading({ title: '正在创建订单...' });
|
||||
let orderId ;
|
||||
wx.request({
|
||||
url: baseUrl + '/courseOrder/add',
|
||||
method: 'POST',
|
||||
data: {
|
||||
courseId: courseId
|
||||
},
|
||||
header: {
|
||||
Authorization :wx.getStorageSync('token'),
|
||||
},
|
||||
success : res => {
|
||||
orderId = res.data.data
|
||||
this.setData({ orderId })
|
||||
wx.hideLoading();
|
||||
if (res.data.code === 1) {
|
||||
this.showIsPayModal(orderId)
|
||||
} else {
|
||||
// 下单失败,关闭遮罩
|
||||
this.setData({ isMaskVisible: false });
|
||||
wx.showModal({
|
||||
title: '下单失败',
|
||||
content: res.data.message || '下单失败',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.hideLoading();
|
||||
this.setData({ isMaskVisible: false });
|
||||
wx.showToast({ title: '网络错误,下单失败', icon: 'none' });
|
||||
}
|
||||
})
|
||||
},
|
||||
showIsPayModal(orderId) {
|
||||
wx.showModal({
|
||||
title: '下单成功',
|
||||
content: '您确定要支付吗?',
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.payOrder(orderId);
|
||||
} else if (res.cancel) {
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
|
||||
success: res => {
|
||||
// 先把遮罩关掉
|
||||
this.setData({ isMaskVisible: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '网络错误,下单失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
payOrder(orderId) {
|
||||
// 同样先显示遮罩
|
||||
this.setData({ isMaskVisible: true });
|
||||
wx.showLoading({ title: '支付中...'});
|
||||
wx.request({
|
||||
url: baseUrl + '/courseOrder/payment',
|
||||
method: 'POST',
|
||||
header: { Authorization: wx.getStorageSync('token') },
|
||||
data: { id: orderId },
|
||||
success: res => {
|
||||
wx.hideLoading();
|
||||
if (res.data.code === 1) {
|
||||
// 支付成功,跳转详情页
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
|
||||
success: res => {
|
||||
// 先把遮罩关掉
|
||||
this.setData({ isMaskVisible: false });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.setData({ isMaskVisible: false });
|
||||
wx.showToast({ title: res.data.message || '支付失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.hideLoading();
|
||||
this.setData({ isMaskVisible: false });
|
||||
wx.showToast({ title: '网络错误,支付失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 获取课程详情
|
||||
getCourseDetail() {
|
||||
const cid = this.data.courseId;
|
||||
wx.request({
|
||||
url: baseUrl + '/course/detail/id',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: cid
|
||||
},
|
||||
header: {
|
||||
Authorization :wx.getStorageSync('token'),
|
||||
},
|
||||
success : res => {
|
||||
console.log(res);
|
||||
if (res.data.code === 1) {
|
||||
this.setData({
|
||||
courseObj: res.data.data,
|
||||
})
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getCourseDesc() {
|
||||
wx.request({
|
||||
url: baseUrl + '/userInfo/query/courseDesc',
|
||||
method: 'POST',
|
||||
success: res => {
|
||||
console.log('====>购买须知', res.data)
|
||||
if (res.data.code === 1) {
|
||||
this.setData({noticeHtml: decodeBase64(res.data.data)})
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
console.log('课程id--->',options.id);
|
||||
this.setData({
|
||||
courseId: options.id,
|
||||
})
|
||||
this.getCourseDetail()
|
||||
this.getCourseDesc()
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
3
pages/course/createCourseOrder/createCourseOrder.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
77
pages/course/createCourseOrder/createCourseOrder.wxml
Normal file
@ -0,0 +1,77 @@
|
||||
<!-- pages/course/createCourseOrder/createCourseOrder.wxml -->
|
||||
<view class="page">
|
||||
|
||||
<!-- 可滚动内容区:为固定底部预留内边距,避免遮挡 -->
|
||||
<scroll-view scroll-y class="content no-scrollbar">
|
||||
|
||||
<!-- 商品信息卡片 -->
|
||||
<view class="card product">
|
||||
<image
|
||||
class="cover"
|
||||
src="{{ globalImgUrl + courseObj.image }}"
|
||||
mode="aspectFill"
|
||||
lazy-load="true"
|
||||
/>
|
||||
<view class="info">
|
||||
<text class="title ellipsis-2">{{ courseObj.name }}</text>
|
||||
<view class="price-line">
|
||||
<text class="price-now">¥{{ courseObj.discountPrice }}</text>
|
||||
<text class="price-origin">¥{{ courseObj.originPrice }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品价格行 -->
|
||||
<view class="card row">
|
||||
<text class="row-left">商品价格</text>
|
||||
<text class="row-right accent">¥{{ courseObj.discountPrice }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式 -->
|
||||
<view class="card pay">
|
||||
<view class="pay-left">
|
||||
<image class="pay-icon" src="./image/wxpay.png" mode="aspectFit" />
|
||||
<text class="pay-text">微信支付</text>
|
||||
</view>
|
||||
<radio-group class="pay-right" bindchange="onPayMethodChange">
|
||||
<radio value="wxpay" checked></radio>
|
||||
</radio-group>
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
|
||||
<!-- 固定底部结算栏 -->
|
||||
<view class="footer">
|
||||
<view class="footer-inner">
|
||||
<text class="to-pay">应付 <text class="to-pay-amount">¥{{ courseObj.discountPrice }}</text></text>
|
||||
<view class="btn-pay" bindtap="createOrder">立即支付</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 遮罩 -->
|
||||
<view wx:if="{{isMaskVisible}}" class="page-mask"></view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- ===== 购买须知弹窗(富文本) ===== -->
|
||||
<view wx:if="{{isNoticeVisible}}" class="modal-mask" catchtouchmove="noop">
|
||||
<view class="modal" catchtap="noop">
|
||||
<view class="modal-title">课程购买须知</view>
|
||||
|
||||
<!-- 富文本内容:支持 p/h1-h6/strong/em/ul/ol/a 等常见标签 -->
|
||||
<scroll-view scroll-y class="modal-body">
|
||||
<rich-text nodes="{{noticeHtml}}"></rich-text>
|
||||
</scroll-view>
|
||||
|
||||
<view class="modal-actions">
|
||||
<button class="btn-primary" bindtap="closeNotice">我知道了</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 右上角购买须知按钮 -->
|
||||
<view class="notice-icon" bindtap="openNotice">
|
||||
<image src="./image/info.png" mode="aspectFit" class="notice-icon-img" />
|
||||
<text class="notice-icon-text">购买须知</text>
|
||||
</view>
|
||||
|
320
pages/course/createCourseOrder/createCourseOrder.wxss
Normal file
@ -0,0 +1,320 @@
|
||||
/* 页面与滚动容器 */
|
||||
.page {
|
||||
background-color: #f7f7f7;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 24rpx 24rpx 160rpx; /* bottom 预留给固定底部栏 */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 通用卡片 */
|
||||
.card {
|
||||
background-color: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
.card + .card {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
/* 商品信息卡片 */
|
||||
.product {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.cover {
|
||||
width: 260rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 12rpx;
|
||||
flex-shrink: 0;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
min-width: 0; /* 使多行省略生效 */
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1f1f1f;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
|
||||
.ellipsis-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.price-line {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 12rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.price-now {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #ff5a1a; /* 与主题橙统一 */
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.price-origin {
|
||||
font-size: 26rpx;
|
||||
color: #9f9f9f;
|
||||
text-decoration: line-through; /* 用样式处理中划线 */
|
||||
}
|
||||
|
||||
/* 通用行(键值对) */
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.row-left {
|
||||
font-size: 30rpx;
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.row-right {
|
||||
font-size: 30rpx;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
|
||||
.accent {
|
||||
color: #ff5a1a;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 支付方式 */
|
||||
.pay {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.pay-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.pay-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.pay-text {
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.pay-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 固定底部 */
|
||||
.footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 -6rpx 20rpx rgba(0,0,0,0.06);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
/* 兼容旧版 iOS */
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.footer-inner {
|
||||
height: 120rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24rpx;
|
||||
padding: 0 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.to-pay {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.to-pay-amount {
|
||||
font-size: 36rpx;
|
||||
color: #ff5a1a;
|
||||
font-weight: 700;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
/* 支付按钮:使用 view,自定义橙色主题 */
|
||||
.btn-pay {
|
||||
min-width: 260rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 999rpx;
|
||||
background: linear-gradient(180deg, #ffa64a 0%, #ff8d1a 100%);
|
||||
color: #ffffff;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 6rpx 14rpx rgba(255, 141, 26, 0.35);
|
||||
active-opacity: 0.85;
|
||||
}
|
||||
|
||||
/* 遮罩层 */
|
||||
.page-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-color: rgba(0, 0, 0, 0.35);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* 旧样式中可能用到的零散类,若无依赖可移除 */
|
||||
.ml-11 { margin-left: 20rpx; }
|
||||
.mt-15 { margin-top: 28rpx; }
|
||||
.ml-1 { margin-left: 2rpx; }
|
||||
|
||||
|
||||
|
||||
/* 入口小字 */
|
||||
.notice-entry {
|
||||
margin-right: 16rpx;
|
||||
font-size: 24rpx;
|
||||
color: #8a8a8a;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 弹窗遮罩 */
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
z-index: 999; /* 确保在你的 .footer 与其他遮罩之上 */
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.45);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40rpx;
|
||||
}
|
||||
|
||||
/* 弹窗容器 */
|
||||
.modal {
|
||||
width: 86%;
|
||||
max-width: 640rpx;
|
||||
max-height: 70vh;
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 12rpx 40rpx rgba(0,0,0,0.18);
|
||||
}
|
||||
|
||||
/* 标题 */
|
||||
.modal-title {
|
||||
padding: 28rpx 32rpx 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
/* 内容区滚动 */
|
||||
.modal-body {
|
||||
max-height: 48vh;
|
||||
padding: 8rpx 32rpx 24rpx;
|
||||
}
|
||||
rich-text {
|
||||
padding-bottom: 32rpx;
|
||||
}
|
||||
|
||||
/* 富文本默认样式优化 */
|
||||
.modal-body rich-text {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
line-height: 1.75;
|
||||
color: #444;
|
||||
}
|
||||
.modal-body h3 { font-size: 28rpx; margin: 18rpx 0 8rpx; color: #222; }
|
||||
.modal-body p { margin: 10rpx 0; }
|
||||
.modal-body ul, .modal-body ol { margin: 10rpx 0 10rpx 28rpx; }
|
||||
.modal-body a { color: #1677ff; word-break: break-all; }
|
||||
|
||||
/* 底部按钮区 */
|
||||
.modal-actions {
|
||||
padding: 20rpx 24rpx 28rpx;
|
||||
}
|
||||
.btn-primary {
|
||||
width: 100%;
|
||||
height: 84rpx;
|
||||
line-height: 84rpx;
|
||||
text-align: center;
|
||||
border-radius: 16rpx;
|
||||
background: #ff8a00; /* 你的主色调(可换成项目变量) */
|
||||
color: #fff;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.btn-primary:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.notice-icon {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border-radius: 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
padding: 6rpx 14rpx;
|
||||
}
|
||||
|
||||
.notice-icon-img {
|
||||
width: 34rpx;
|
||||
height: 34rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.notice-icon-text {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
}
|
||||
.notice-icon:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
BIN
pages/course/createCourseOrder/image/info.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
pages/course/createCourseOrder/image/wxpay.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
152
pages/course/homepage/homepage.js
Normal file
@ -0,0 +1,152 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
const { globalImgUrl } = require("../../../request")
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
// pages/course/homepage/homepage.js
|
||||
Page({
|
||||
|
||||
data: {
|
||||
courseList: [],
|
||||
bannerList: [],
|
||||
globalImgUrl
|
||||
},
|
||||
|
||||
// 跳转课程列表页
|
||||
gotoCourseList(e) {
|
||||
const courseType = e.currentTarget.dataset.type;
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/courseList/courseList?type=${courseType}`,
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转课程详情
|
||||
gotoCourseDetail(e) {
|
||||
const courseId = e.currentTarget.dataset.id;
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/courseDetail/courseDetail?id=${courseId}`,
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转课程搜索页面
|
||||
gotoSearch() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/course/searchCourses/searchCourses',
|
||||
});
|
||||
},
|
||||
|
||||
// 获取热门课程
|
||||
|
||||
getCourseList() {
|
||||
// 请求后端接口
|
||||
wx.request({
|
||||
url: baseUrl + '/course/query/hot', // ← 替换为真实接口
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data.code === 1) {
|
||||
console.log('课程列表---->',res.data.data);
|
||||
// 将后端的 data 数组绑定到 items
|
||||
this.setData({
|
||||
courseList: res.data.data
|
||||
});
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '网络异常,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getBannerList() {
|
||||
const token = wx.getStorageSync('token')
|
||||
wx.request({
|
||||
url: baseUrl + '/banner/mini/list',
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': token
|
||||
},
|
||||
success: res => {
|
||||
if (res.data.code === 1) {
|
||||
this.setData({
|
||||
bannerList: res.data.data
|
||||
});
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '网络异常,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad() {
|
||||
this.getBannerList()
|
||||
this.getCourseList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
this.getBannerList()
|
||||
this.getCourseList()
|
||||
// 停止下拉刷新动画
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
4
pages/course/homepage/homepage.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
64
pages/course/homepage/homepage.wxml
Normal file
@ -0,0 +1,64 @@
|
||||
<view class="page">
|
||||
|
||||
<!-- 顶部内容:搜索 + 轮播 -->
|
||||
<view class="top">
|
||||
<view class="search-bar" bindtap="gotoSearch" hover-class="hover">
|
||||
<image class="search-icon" src="./image/sousuo.png" mode="aspectFit"/>
|
||||
<text class="search-text">搜索更多好课</text>
|
||||
</view>
|
||||
|
||||
<swiper class="swiper" autoplay="true" interval="3000" circular="true" indicator-dots="true" indicator-active-color="#ff6a00">
|
||||
<block wx:for="{{bannerList}}" wx:for-item="img" wx:key="index">
|
||||
<swiper-item>
|
||||
<image src="{{globalImgUrl + img}}" class="swiper-image" mode="aspectFill" lazy-load="true"/>
|
||||
</swiper-item>
|
||||
</block>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<!-- 三分类 -->
|
||||
<view class="category-row">
|
||||
<view class="category-card" bindtap="gotoCourseList" data-type="考编" hover-class="hover">
|
||||
<image class="category-icon" src="./image/考编.png" mode="aspectFit" lazy-load="true"/>
|
||||
<text class="category-text">考编</text>
|
||||
</view>
|
||||
<view class="category-card" bindtap="gotoCourseList" data-type="考公" hover-class="hover">
|
||||
<image class="category-icon" src="./image/考公.png" mode="aspectFit" lazy-load="true"/>
|
||||
<text class="category-text">考公</text>
|
||||
</view>
|
||||
<view class="category-card" bindtap="gotoCourseList" data-type="考证" hover-class="hover">
|
||||
<image class="category-icon" src="./image/考证.png" mode="aspectFit" lazy-load="true"/>
|
||||
<text class="category-text">考证</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 热门课程标题 -->
|
||||
<view class="section-head">
|
||||
<text class="section-title">热门课程</text>
|
||||
</view>
|
||||
|
||||
<!-- 热门课程两列宫格 -->
|
||||
<scroll-view scroll-y class="list no-scrollbar">
|
||||
<view class="grid">
|
||||
<block wx:for="{{courseList}}" wx:key="item.id" wx:for-item="item">
|
||||
<view class="grid-item" bindtap="gotoCourseDetail" data-id="{{item.id}}" hover-class="hover">
|
||||
<image class="grid-cover" src="{{ globalImgUrl + item.image }}" mode="aspectFill" lazy-load="true"/>
|
||||
<view class="grid-info">
|
||||
<text class="grid-title">{{item.name}}</text>
|
||||
<view class="grid-meta">
|
||||
<text class="grid-price">¥{{item.discountPrice}}</text>
|
||||
<text class="grid-people">{{item.orderCount}}人学习</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view wx:if="{{!courseList || courseList.length == 0}}" class="empty">
|
||||
<image class="empty-icon" src="/static/empty.png" mode="aspectFit"/>
|
||||
<text class="empty-text">暂无课程,去看看其他分类吧~</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
118
pages/course/homepage/homepage.wxss
Normal file
@ -0,0 +1,118 @@
|
||||
.page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #ffffff;
|
||||
overflow: hidden;
|
||||
font-family: SourceHanSansCN, PingFang SC, Microsoft YaHei, system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
.hover { opacity: 0.8; transition: opacity .2s ease; }
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* 顶部 */
|
||||
.top { padding: 30rpx; }
|
||||
.search-bar {
|
||||
display: flex; align-items: center; gap: 14rpx;
|
||||
padding: 18rpx 22rpx; border-radius: 9999rpx;
|
||||
background: #f5f6f7;
|
||||
}
|
||||
.search-icon { width: 36rpx; height: 36rpx; }
|
||||
.search-text { font-size: 26rpx; color: #a8a8a8; }
|
||||
|
||||
.swiper {
|
||||
width: 100%; height: 324rpx; margin-top: 24rpx;
|
||||
border-radius: 16rpx; overflow: hidden;
|
||||
}
|
||||
.swiper-image { width: 100%; height: 100%; }
|
||||
|
||||
/* 分类 */
|
||||
.category-row {
|
||||
display: flex; gap: 24rpx; padding: 0 30rpx; margin-top: 22rpx;
|
||||
}
|
||||
.category-card {
|
||||
flex: 1; background: #fff; border-radius: 20rpx;
|
||||
padding: 22rpx 0 18rpx;
|
||||
display: flex; flex-direction: column; align-items: center; gap: 12rpx;
|
||||
box-shadow: 0 6rpx 24rpx rgba(0,0,0,0.06);
|
||||
}
|
||||
.category-icon { width: 96rpx; height: 96rpx; }
|
||||
.category-text { font-size: 26rpx; color: #111; }
|
||||
|
||||
/* 标题 */
|
||||
.section-head { padding: 28rpx 30rpx 16rpx; }
|
||||
.section-title { font-size: 30rpx; font-weight: 600; }
|
||||
|
||||
/* 列表(滚动) */
|
||||
.list {
|
||||
flex: 1;
|
||||
padding: 0 30rpx;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow: auto;
|
||||
}
|
||||
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||
.no-scrollbar { scrollbar-width: none; }
|
||||
|
||||
/* 宫格布局 */
|
||||
.grid {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
padding-bottom: 30rpx;
|
||||
}
|
||||
.grid-item {
|
||||
width: 335rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.05);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.grid-cover {
|
||||
width: 100%; height: 200rpx;
|
||||
object-fit: cover;
|
||||
}
|
||||
.grid-info {
|
||||
padding: 14rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
}
|
||||
.grid-title {
|
||||
font-size: 26rpx;
|
||||
color: #111;
|
||||
line-height: 36rpx;
|
||||
min-height: 72rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.grid-meta {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
}
|
||||
.grid-price {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #ff6a00;
|
||||
}
|
||||
.grid-people {
|
||||
font-size: 22rpx;
|
||||
color: #9aa0a6;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty {
|
||||
padding: 80rpx 0 60rpx;
|
||||
display: flex; flex-direction: column; align-items: center; gap: 18rpx;
|
||||
color: #9aa0a6;
|
||||
}
|
||||
.empty-icon { width: 220rpx; height: 220rpx; opacity: 0.7; }
|
||||
.empty-text { font-size: 24rpx; }
|
BIN
pages/course/homepage/image/sousuo.png
Normal file
After Width: | Height: | Size: 812 B |
BIN
pages/course/homepage/image/考公.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
pages/course/homepage/image/考编.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
pages/course/homepage/image/考证.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
239
pages/course/orderDetail/orderDetail.js
Normal file
@ -0,0 +1,239 @@
|
||||
import { baseUrl, globalImgUrl } from "../../../request";
|
||||
|
||||
Page({
|
||||
data: {
|
||||
countdown: "",
|
||||
orderId: 0,
|
||||
orderObj: {}, // 订单详情对象
|
||||
_secondsRemaining: 0, // 内部倒计时秒数
|
||||
_hasShownTimeout: false, // 是否已弹过“超时未支付”弹窗(本次页面停留期内)
|
||||
globalImgUrl,
|
||||
isMaskVisible: false,
|
||||
_isActive: false // 页面是否处于可见状态
|
||||
},
|
||||
|
||||
// —— 非 data 状态,避免无谓 setData
|
||||
_timer: null,
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({ orderId: options.id || 0 });
|
||||
this.getOrderDetail();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.setData({ _isActive: true });
|
||||
},
|
||||
|
||||
onHide() {
|
||||
this.setData({ _isActive: false });
|
||||
this._clearTimer();
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
this.setData({ _isActive: false });
|
||||
this._clearTimer();
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.getOrderDetail(); // stopPullDownRefresh 放到 complete 里,更稳
|
||||
},
|
||||
|
||||
// ====== 工具函数 ======
|
||||
_clearTimer() {
|
||||
if (this._timer) {
|
||||
clearInterval(this._timer);
|
||||
this._timer = null;
|
||||
}
|
||||
},
|
||||
_pad2(n) {
|
||||
return String(n).padStart(2, "0");
|
||||
},
|
||||
_format(sec) {
|
||||
const m = Math.floor(sec / 60);
|
||||
const s = sec % 60;
|
||||
return `${this._pad2(m)}分${this._pad2(s)}秒`;
|
||||
},
|
||||
|
||||
// ====== 拉取订单详情并初始化倒计时 ======
|
||||
getOrderDetail() {
|
||||
wx.request({
|
||||
url: baseUrl + "/courseOrder/query/detail",
|
||||
method: "POST",
|
||||
data: { id: this.data.orderId },
|
||||
header: { Authorization: wx.getStorageSync("token") },
|
||||
success: (res) => {
|
||||
if (res.data.code !== 1) {
|
||||
wx.showToast({ title: res.data.message || "获取失败", icon: "none" });
|
||||
return;
|
||||
}
|
||||
|
||||
const order = res.data.data || {};
|
||||
this.setData({ orderObj: order });
|
||||
|
||||
// 只有“待支付”才需要倒计时;其它状态关掉计时器并清空文案
|
||||
if (order.orderStatus === "待支付") {
|
||||
this._initFromCreateTime(order.createTime);
|
||||
} else {
|
||||
this._clearTimer();
|
||||
this.setData({ countdown: "" });
|
||||
}
|
||||
},
|
||||
fail: () => wx.showToast({ title: "网络错误", icon: "none" }),
|
||||
complete: () => wx.stopPullDownRefresh(),
|
||||
});
|
||||
},
|
||||
|
||||
// 计算剩余秒数并启动定时器
|
||||
_initFromCreateTime(createTime) {
|
||||
const ts = new Date(String(createTime).replace(/-/g, "/")).getTime();
|
||||
const createMs = Number.isFinite(ts) ? ts : Date.now();
|
||||
const ttlMs = 15 * 60 * 1000; // 15分钟有效
|
||||
const now = Date.now();
|
||||
let diff = Math.floor((createMs + ttlMs - now) / 1000);
|
||||
diff = Math.max(0, diff);
|
||||
|
||||
// 初始化阶段:如果已过期,静默转“交易关闭”(不弹窗,避免干扰)
|
||||
if (diff === 0) {
|
||||
const o = { ...this.data.orderObj, orderStatus: "交易关闭" };
|
||||
this._clearTimer();
|
||||
this.setData({ orderObj: o, countdown: "" });
|
||||
return;
|
||||
}
|
||||
|
||||
// 未过期:初始化倒计时并启动
|
||||
this._clearTimer();
|
||||
this.setData({
|
||||
_secondsRemaining: diff,
|
||||
countdown: this._format(diff),
|
||||
_hasShownTimeout: false, // 重置本页弹窗标记
|
||||
});
|
||||
this._startTimer();
|
||||
},
|
||||
|
||||
// 每秒递减
|
||||
_startTimer() {
|
||||
this._clearTimer();
|
||||
this._timer = setInterval(() => {
|
||||
const sec = this.data._secondsRemaining - 1;
|
||||
|
||||
if (sec <= 0) {
|
||||
this._clearTimer();
|
||||
this._handleTimeout(); // 到点且在当前页,才弹窗
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({
|
||||
_secondsRemaining: sec,
|
||||
countdown: this._format(sec),
|
||||
});
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
// 超时处理:仅在当前页可见时弹一次,并把状态改为“交易关闭”
|
||||
_handleTimeout() {
|
||||
const { _isActive, _hasShownTimeout } = this.data;
|
||||
|
||||
// 更新状态并隐藏倒计时
|
||||
const o = { ...this.data.orderObj, orderStatus: "交易关闭" };
|
||||
this.setData({ orderObj: o, countdown: "" });
|
||||
|
||||
// 只在当前页面 & 未弹过 时弹一次
|
||||
if (_isActive && !_hasShownTimeout) {
|
||||
wx.showModal({
|
||||
title: "提示",
|
||||
content: "订单超时未支付,已关闭",
|
||||
showCancel: false,
|
||||
complete: () => {
|
||||
// 标记已弹
|
||||
this.setData({ _hasShownTimeout: true });
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.setData({ _hasShownTimeout: true });
|
||||
}
|
||||
},
|
||||
|
||||
// ====== 支付相关 ======
|
||||
showIsPayModal() {
|
||||
const { orderId } = this.data;
|
||||
wx.showModal({
|
||||
title: "确认支付",
|
||||
content: "是否立即支付该订单?",
|
||||
cancelText: "取消",
|
||||
confirmText: "去支付",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.payOrder(orderId);
|
||||
} else if (res.cancel) {
|
||||
this.setData({ isMaskVisible: false });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: "网络错误", icon: "none" });
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
payOrder(orderId) {
|
||||
this.setData({ isMaskVisible: true });
|
||||
wx.showLoading({ title: "支付中..." });
|
||||
|
||||
wx.request({
|
||||
url: baseUrl + "/courseOrder/payment",
|
||||
method: "POST",
|
||||
header: { Authorization: wx.getStorageSync("token") },
|
||||
data: { id: orderId }, // 若后端用 orderId,则把键名改为 orderId
|
||||
success: (res) => {
|
||||
wx.hideLoading();
|
||||
if (res.data.code === 1) {
|
||||
wx.redirectTo({
|
||||
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
|
||||
complete: () => this.setData({ isMaskVisible: false }),
|
||||
});
|
||||
} else {
|
||||
this.setData({ isMaskVisible: false });
|
||||
wx.showToast({ title: res.data.message || "支付失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.hideLoading();
|
||||
this.setData({ isMaskVisible: false });
|
||||
wx.showToast({ title: "网络错误,支付失败", icon: "none" });
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// ====== 取消、退款(示例) ======
|
||||
cancelOrder() {
|
||||
wx.showModal({
|
||||
title: "取消订单",
|
||||
content: "是否要取消订单?",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.request({
|
||||
url: baseUrl + "/courseOrder/cancel",
|
||||
method: "POST",
|
||||
header: { Authorization: wx.getStorageSync("token") },
|
||||
data: { id: this.data.orderId }, // 后端如果需要 { orderId },改键名
|
||||
success: (r) => {
|
||||
if (!r.data || r.data.code !== 1) {
|
||||
wx.showToast({ title: (r.data && r.data.message) || "取消失败", icon: "none" });
|
||||
}
|
||||
this.getOrderDetail();
|
||||
},
|
||||
fail: () => wx.showToast({ title: "网络错误", icon: "none" }),
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
goPay() {
|
||||
wx.showToast({ title: "支付功能稍后开放", icon: "none" });
|
||||
},
|
||||
|
||||
refundOrder() {
|
||||
wx.showToast({ title: "退款功能稍后开放", icon: "none" });
|
||||
},
|
||||
});
|
4
pages/course/orderDetail/orderDetail.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
101
pages/course/orderDetail/orderDetail.wxml
Normal file
@ -0,0 +1,101 @@
|
||||
<!-- pages/order/orderDetail.wxml -->
|
||||
<view class="page">
|
||||
|
||||
<!-- 中间内容滚动,底部按钮固定,所以这里预留底部内边距 -->
|
||||
<scroll-view scroll-y class="content no-scrollbar">
|
||||
|
||||
<!-- 订单状态 + 倒计时 + 课程信息 -->
|
||||
<view class="card header-card">
|
||||
<!-- 状态与倒计时 -->
|
||||
<view class="status-line">
|
||||
<view class="status-badge {{ orderObj.orderStatus === '待支付' ? 'status-pending' : (orderObj.orderStatus === '已支付' || orderObj.orderStatus === '交易成功' ? 'status-success' : 'status-default') }}">
|
||||
<text class="status-text">{{ orderObj.orderStatus }}</text>
|
||||
</view>
|
||||
<view wx:if="{{ orderObj.orderStatus === '待支付' }}" class="countdown-pill">
|
||||
<text class="countdown-text">请在 {{ countdown }} 内完成支付</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 课程信息 -->
|
||||
<view class="course-line">
|
||||
<image class="cover" src="{{ globalImgUrl + orderObj.image }}" mode="aspectFill" lazy-load="true" />
|
||||
<view class="course-info">
|
||||
<text class="course-title ellipsis-2">{{ orderObj.name }}</text>
|
||||
<view class="price-line">
|
||||
<text class="price-origin">¥{{ orderObj.originPrice }}</text>
|
||||
<text class="price-amount">应付:¥{{ orderObj.totalAmount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单详情 -->
|
||||
<view class="card">
|
||||
<view class="kv">
|
||||
<text class="kv-key">订单编号</text>
|
||||
<text class="kv-val selectable">{{ orderObj.orderNumber }}</text>
|
||||
</view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">下单时间</text>
|
||||
<text class="kv-val">{{ orderObj.createTime }}</text>
|
||||
</view>
|
||||
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">支付方式</text>
|
||||
<text class="kv-val">微信支付</text>
|
||||
</view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">交易号</text>
|
||||
<!-- 这里可替换为真实字段 -->
|
||||
<text class="kv-val selectable">4002506191307440406460485418</text>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{ orderObj.orderStatus === '交易成功' }}" class="kv">
|
||||
<text class="kv-key">交付时间</text>
|
||||
<text class="kv-val">{{ orderObj.updateTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 价格明细 -->
|
||||
<view class="card">
|
||||
<view class="kv">
|
||||
<text class="kv-key">课程价格</text>
|
||||
<text class="kv-val">¥{{ orderObj.originPrice }}</text>
|
||||
</view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">价格折扣</text>
|
||||
<text class="kv-val discount">-¥{{ (orderObj.originPrice - orderObj.totalAmount) >= 0 ? (orderObj.originPrice - orderObj.totalAmount) : 0 }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="kv total">
|
||||
<text class="kv-key total-key">订单金额</text>
|
||||
<text class="kv-val total-val">¥{{ orderObj.totalAmount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部按钮:待支付 -->
|
||||
<view class="footer" wx:if="{{ orderObj.orderStatus === '待支付' }}">
|
||||
<view class="footer-inner two-btns">
|
||||
<view class="btn btn-ghost" bindtap="cancelOrder">取消</view>
|
||||
<view class="btn btn-primary" bindtap="showIsPayModal">立即支付</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部按钮:已支付 -->
|
||||
<view class="footer" wx:if="{{ orderObj.orderStatus === '已支付' }}">
|
||||
<view class="footer-inner one-btn">
|
||||
<view class="btn btn-primary" bindtap="refundOrder">退款</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 遮罩 -->
|
||||
<view wx:if="{{ isMaskVisible }}" class="page-mask"></view>
|
||||
</view>
|
255
pages/course/orderDetail/orderDetail.wxss
Normal file
@ -0,0 +1,255 @@
|
||||
/* ===== 页面框架 ===== */
|
||||
.page {
|
||||
background: #f7f7f7;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 24rpx 24rpx 200rpx; /* 为底部固定按钮预留空间 */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 遮罩 */
|
||||
.page-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-color: rgba(0, 0, 0, 0.35);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* ===== 卡片通用 ===== */
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.card + .card {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
/* ===== 顶部卡片:状态 + 倒计时 + 课程 ===== */
|
||||
.header-card .status-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
height: 48rpx;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 999rpx;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background: #fff6e6;
|
||||
color: #ff8d1a;
|
||||
}
|
||||
|
||||
.status-success {
|
||||
background: #e9fbef;
|
||||
color: #12b05b;
|
||||
}
|
||||
|
||||
.status-default {
|
||||
background: #f0f0f0;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.countdown-pill {
|
||||
background: #fff4f2;
|
||||
border: 1rpx solid #ffd6cc;
|
||||
padding: 0 18rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 999rpx;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.countdown-text {
|
||||
font-size: 24rpx;
|
||||
color: #ff5a1a;
|
||||
}
|
||||
|
||||
/* 课程行 */
|
||||
.course-line {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.cover {
|
||||
width: 240rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #f2f2f2;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.course-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.course-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1f1f1f;
|
||||
line-height: 44rpx;
|
||||
}
|
||||
|
||||
.ellipsis-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.price-line {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 16rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.price-origin {
|
||||
font-size: 28rpx;
|
||||
color: #9f9f9f;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.price-amount {
|
||||
font-size: 30rpx;
|
||||
color: #ff5a1a;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ===== 键值对(订单详情 / 价格明细) ===== */
|
||||
.kv {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12rpx 0;
|
||||
}
|
||||
|
||||
.kv + .kv {
|
||||
border-top: 1rpx dashed #f0f0f0;
|
||||
}
|
||||
|
||||
.kv-key {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.kv-val {
|
||||
font-size: 28rpx;
|
||||
color: #1f1f1f;
|
||||
max-width: 70%;
|
||||
text-align: right;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.selectable {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1rpx;
|
||||
background: #f2f2f2;
|
||||
margin: 8rpx 0 12rpx;
|
||||
}
|
||||
|
||||
.discount {
|
||||
color: #12b05b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.total {
|
||||
border-top: 1rpx solid #f2f2f2;
|
||||
margin-top: 8rpx;
|
||||
padding-top: 16rpx;
|
||||
}
|
||||
|
||||
.total-key {
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.total-val {
|
||||
font-size: 34rpx;
|
||||
color: #ff5a1a;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ===== 底部操作栏 ===== */
|
||||
.footer {
|
||||
position: fixed;
|
||||
left: 0; right: 0; bottom: 0;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 -6rpx 20rpx rgba(0,0,0,0.06);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.footer-inner {
|
||||
height: 120rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24rpx;
|
||||
padding: 0 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.footer-inner.two-btns { justify-content: space-between; }
|
||||
.footer-inner.one-btn { justify-content: flex-end; }
|
||||
|
||||
.btn {
|
||||
height: 88rpx;
|
||||
min-width: 260rpx;
|
||||
border-radius: 999rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background: #ffffff;
|
||||
color: #333333;
|
||||
border: 2rpx solid #e6e6e6;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(180deg, #ffa64a 0%, #ff8d1a 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 6rpx 14rpx rgba(255, 141, 26, 0.35);
|
||||
}
|
||||
|
||||
/* ===== 迁移提示:以下旧的散装类建议删除(如无外部依赖) ===== */
|
||||
/* .ml-37, .ml-7, .mt-15, .ml-3, .ml-23, .mt-17, .mt-11, .mt-389 等 */
|
BIN
pages/course/recommendUser/image/right.png
Normal file
After Width: | Height: | Size: 321 B |
67
pages/course/recommendUser/recommendUser.js
Normal file
@ -0,0 +1,67 @@
|
||||
// pages/course/recommendUser/recommendUser.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
items: [null, null, null],
|
||||
items_1: [null, null, null],
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
3
pages/course/recommendUser/recommendUser.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
78
pages/course/recommendUser/recommendUser.wxml
Normal file
@ -0,0 +1,78 @@
|
||||
<view class="flex-col page">
|
||||
<view class="flex-col">
|
||||
<text class="self-center text">我推荐的用户</text>
|
||||
|
||||
<!-- 直推用户 -->
|
||||
<text class="self-start font text_2">直推用户</text>
|
||||
<view class="flex-col self-stretch section view">
|
||||
<!-- 表头 -->
|
||||
<view class="flex-row justify-between group">
|
||||
<text class="font_2 text_3">用户名</text>
|
||||
<text class="font_2">给我创造的收益</text>
|
||||
<text class="font_2 text_4">绑定时间</text>
|
||||
<text class="font_2 text_5">联系</text>
|
||||
</view>
|
||||
<!-- 列表项 -->
|
||||
<view class="flex-col mt-13">
|
||||
<view
|
||||
class="list-item mt-13"
|
||||
wx:for="{{items}}"
|
||||
wx:for-item="item"
|
||||
wx:for-index="index"
|
||||
wx:key="index"
|
||||
>
|
||||
<view class="flex-row justify-between">
|
||||
<!-- 用户名:固定宽度、任意字符处断行 -->
|
||||
<text class="font_3 name">{{item.userName || 'user_cxzsdfdfs'}}</text>
|
||||
<view class="flex-row items-center">
|
||||
<text class="font_4">¥{{item.revenue || '160.00'}}</text>
|
||||
<view class="flex-row items-center shrink-0 ml-35">
|
||||
<text class="font_4">{{item.bindTime || '2025-06-20'}}</text>
|
||||
<image
|
||||
class="shrink-0 image ml-27"
|
||||
src="./image/right.png"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 间推用户 -->
|
||||
<view class="mt-36 flex-col">
|
||||
<text class="self-start font text_6">间推用户</text>
|
||||
<view class="mt-14 flex-col self-stretch section">
|
||||
<view class="flex-row justify-between group">
|
||||
<text class="font_2 text_3">用户名</text>
|
||||
<text class="font_2">给我创造的收益</text>
|
||||
<text class="font_2 text_4">绑定时间</text>
|
||||
<text class="font_2 text_5">联系</text>
|
||||
</view>
|
||||
<view class="flex-col mt-13">
|
||||
<view
|
||||
class="list-item_2 mt-13"
|
||||
wx:for="{{items_1}}"
|
||||
wx:for-item="item"
|
||||
wx:for-index="index"
|
||||
wx:key="index"
|
||||
>
|
||||
<view class="flex-row justify-between">
|
||||
<text class="font_3 name">{{item.userName || 'user_cxzsdfdfs'}}</text>
|
||||
<view class="flex-row items-center">
|
||||
<text class="font_4">¥{{item.revenue || '160.00'}}</text>
|
||||
<view class="flex-row items-center shrink-0 ml-35">
|
||||
<text class="font_4">{{item.bindTime || '2025-06-20'}}</text>
|
||||
<image
|
||||
class="shrink-0 image ml-27"
|
||||
src="./image/right.png"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
122
pages/course/recommendUser/recommendUser.wxss
Normal file
@ -0,0 +1,122 @@
|
||||
/*=========== 公共间距 ===========*/
|
||||
.ml-35 {
|
||||
margin-left: 65.63rpx;
|
||||
}
|
||||
.ml-27 {
|
||||
margin-left: 50.63rpx;
|
||||
}
|
||||
.mt-13 {
|
||||
margin-top: 24.38rpx;
|
||||
}
|
||||
|
||||
/*=========== 页面整体 ===========*/
|
||||
.page {
|
||||
padding: 37.76rpx 41.25rpx 980.63rpx;
|
||||
background-image: linear-gradient(180deg, #ff8d1a 0%, #ff8d1a00 27%);
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*=========== 文本样式,均放大一号 ===========*/
|
||||
/* 主标题 “我推荐的用户” */
|
||||
.text {
|
||||
color: #ffffff;
|
||||
font-size: 36rpx; /* 原 33.75rpx → 36rpx */
|
||||
line-height: 34rpx; /* 对应行高 */
|
||||
font-family: SourceHanSansCN;
|
||||
}
|
||||
|
||||
/* 次级标题 “直推用户”/“间推用户” */
|
||||
.text_2 {
|
||||
margin-top: 40.42rpx;
|
||||
color: #ffffff;
|
||||
font-size: 36rpx; /* 新增字号 */
|
||||
line-height: 34rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
}
|
||||
|
||||
/* 通用白字 */
|
||||
.font {
|
||||
font-size: 33rpx; /* 原 30rpx → 33rpx */
|
||||
line-height: 30rpx;
|
||||
color: #ffffff;
|
||||
font-family: SourceHanSansCN;
|
||||
}
|
||||
|
||||
/* 卡片容器 */
|
||||
.section {
|
||||
padding: 27.66rpx 27.09rpx 22.67rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.view {
|
||||
margin-top: 25.58rpx;
|
||||
}
|
||||
.group {
|
||||
padding-left: 14.06rpx;
|
||||
}
|
||||
|
||||
/* 表头文字 */
|
||||
.font_2 {
|
||||
font-size: 30rpx; /* 原 26.25rpx → 30rpx */
|
||||
line-height: 28rpx;
|
||||
color: #323232;
|
||||
font-family: SourceHanSansCN;
|
||||
}
|
||||
|
||||
/* 表格内容:收益、时间 */
|
||||
.font_4 {
|
||||
font-size: 30rpx; /* 原 26.25rpx → 30rpx */
|
||||
line-height: 23rpx;
|
||||
color: #323232;
|
||||
font-family: SourceHanSansCN;
|
||||
}
|
||||
|
||||
/* 小图标 */
|
||||
.image {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
}
|
||||
|
||||
/* “间推用户”前缀 */
|
||||
.text_6 {
|
||||
margin-left: 2.74rpx;
|
||||
color: #323232;
|
||||
font-size: 30rpx; /* 新增字号 */
|
||||
line-height: 28rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
}
|
||||
|
||||
/* 用户名文字,放大一号 */
|
||||
.font_3 {
|
||||
font-size: 30rpx; /* 原 26.25rpx → 30rpx */
|
||||
line-height: 36rpx; /* 支持两行 */
|
||||
color: #323232;
|
||||
font-family: SourceHanSansCN;
|
||||
}
|
||||
|
||||
/*=========== 新增:用户名自动换行 ===========*/
|
||||
/* 固定宽度,在“sdfdfs”处自动断行 */
|
||||
.name {
|
||||
flex: none; /* 关闭 flex 自动拉伸 */
|
||||
width: 127rpx; /* 根据字符长度微调,200rpx 在 “user_cxz” 后换行 */
|
||||
word-break: break-all; /* 任意字符处断行 */
|
||||
white-space: normal; /* 允许多行 */
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
|
||||
/* 列表条目顶部对齐,支持多行用户名 */
|
||||
.list-item,
|
||||
.list-item_2 {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-right: 12.28rpx;
|
||||
}
|
||||
.list-item:first-child,
|
||||
.list-item_2:first-child {
|
||||
margin-top: 0;
|
||||
}
|
BIN
pages/course/searchCourses/images/sousuo.png
Normal file
After Width: | Height: | Size: 812 B |
98
pages/course/searchCourses/searchCourses.js
Normal file
@ -0,0 +1,98 @@
|
||||
// pages/course/searchCourses/searchCourses.js
|
||||
import { baseUrl, globalImgUrl } from "../../../request";
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
courseList: [],
|
||||
searchKeyword: '',
|
||||
globalImgUrl,
|
||||
},
|
||||
// 每次用户输入都会进这里
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
});
|
||||
},
|
||||
gotoCourseDetail(e) {
|
||||
const courseId = e.currentTarget.dataset.id;
|
||||
wx.navigateTo({
|
||||
url: `/pages/course/courseDetail/courseDetail?id=${courseId}`,
|
||||
});
|
||||
},
|
||||
onSearch() {
|
||||
const token = wx.getStorageSync('token')
|
||||
const { searchKeyword } = this.data
|
||||
wx.request({
|
||||
url: baseUrl + '/course/query/keyword',
|
||||
header: {
|
||||
Authorization: token
|
||||
},
|
||||
method: 'POST',
|
||||
data: {
|
||||
templateString: searchKeyword
|
||||
},
|
||||
success: res => {
|
||||
let result = res.data.data
|
||||
this.setData({courseList: result})
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
3
pages/course/searchCourses/searchCourses.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
42
pages/course/searchCourses/searchCourses.wxml
Normal file
@ -0,0 +1,42 @@
|
||||
<!-- pages/course/searchCourses/searchCourses.wxml -->
|
||||
<view class="page">
|
||||
|
||||
<!-- 顶部搜索条(固定) -->
|
||||
<view class="search-bar" hover-class="hover">
|
||||
<image class="search-icon" src="./images/sousuo.png" mode="aspectFit"/>
|
||||
<input
|
||||
class="search-input"
|
||||
placeholder="搜索更多好课"
|
||||
placeholder-class="search-ph"
|
||||
bindinput="onSearchInput"
|
||||
confirm-type="search"
|
||||
bindconfirm="onSearch"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果(独立滚动,隐藏滚动条) -->
|
||||
<scroll-view scroll-y class="list no-scrollbar">
|
||||
<block wx:for="{{courseList}}" wx:key="item.id" wx:for-item="item">
|
||||
<view class="course-card" bindtap="gotoCourseDetail" data-id="{{item.id}}" hover-class="hover">
|
||||
<!-- 封面 -->
|
||||
<image class="cover" src="{{globalImgUrl + item.image}}" mode="aspectFill" lazy-load="true"/>
|
||||
|
||||
<!-- 文案 -->
|
||||
<view class="info">
|
||||
<text class="title">{{item.name}}</text>
|
||||
<view class="meta">
|
||||
<text class="price-pill">券后{{item.discountPrice}}元起</text>
|
||||
<text class="people">{{item.orderCount}}人学习</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 空状态(可选) -->
|
||||
<view wx:if="{{!courseList || courseList.length === 0}}" class="empty">
|
||||
<image class="empty-icon" src="/static/empty.png" mode="aspectFit"/>
|
||||
<text class="empty-text">没找到相关课程,换个关键词试试~</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
138
pages/course/searchCourses/searchCourses.wxss
Normal file
@ -0,0 +1,138 @@
|
||||
/* pages/course/searchCourses/searchCourses.wxss */
|
||||
|
||||
/* ===== 页面骨架:整页固定,仅列表滚动 ===== */
|
||||
.page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #ffffff;
|
||||
overflow: hidden; /* 禁止整页滚动 */
|
||||
box-sizing: border-box;
|
||||
font-family: SourceHanSansCN, PingFang SC, Microsoft YaHei, system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
/* 触摸反馈 */
|
||||
.hover { opacity: .86; transition: opacity .18s ease; }
|
||||
|
||||
/* ===== 顶部搜索条(固定) ===== */
|
||||
.search-bar {
|
||||
padding: 24rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
background: #fff;
|
||||
}
|
||||
.search-icon { width: 36rpx; height: 36rpx; opacity: .9; }
|
||||
|
||||
/* 胶囊输入框 */
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
padding: 0 26rpx;
|
||||
border-radius: 9999rpx;
|
||||
background: #f5f6f7;
|
||||
font-size: 26rpx;
|
||||
color: #111;
|
||||
line-height: 72rpx;
|
||||
box-shadow: inset 0 0 0 1rpx rgba(0,0,0,.04);
|
||||
}
|
||||
.search-ph { color: #a8a8a8; font-size: 26rpx; }
|
||||
|
||||
/* ===== 列表:占满剩余高度,独立滚动,隐藏滚动条 ===== */
|
||||
.list {
|
||||
flex: 1;
|
||||
padding: 0 24rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
background: #fff;
|
||||
}
|
||||
.no-scrollbar::-webkit-scrollbar { display: none; width: 0; height: 0; background: transparent; }
|
||||
.no-scrollbar { scrollbar-width: none; }
|
||||
|
||||
/* ===== 课程卡片(左图右文,更工整) ===== */
|
||||
.course-card {
|
||||
display: flex;
|
||||
gap: 22rpx;
|
||||
padding: 20rpx;
|
||||
margin-top: 20rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
border: 1rpx solid #f1f1f1;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,.05);
|
||||
}
|
||||
|
||||
/* 封面:3:2 比例,圆角 */
|
||||
.cover {
|
||||
width: 280rpx;
|
||||
height: 186rpx;
|
||||
flex: 0 0 280rpx;
|
||||
border-radius: 14rpx;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* 信息区 */
|
||||
.info {
|
||||
flex: 1;
|
||||
min-width: 0; /* 防文字溢出 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* 标题:两行省略 */
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #111;
|
||||
font-weight: 600;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2; /* 两行省略 */
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* 元信息:价格胶囊 + 学习人数 */
|
||||
.meta {
|
||||
margin-top: 12rpx;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.price-pill {
|
||||
padding: 6rpx 14rpx;
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
border-radius: 9999rpx;
|
||||
background: linear-gradient(90deg, #ff6a00, #ff8a2a);
|
||||
box-shadow: 0 6rpx 16rpx rgba(255,106,0,.22);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.people {
|
||||
font-size: 22rpx;
|
||||
color: #9aa0a6;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ===== 空状态 ===== */
|
||||
.empty {
|
||||
padding: 120rpx 0 80rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 18rpx;
|
||||
color: #9aa0a6;
|
||||
}
|
||||
.empty-icon { width: 240rpx; height: 240rpx; opacity: .7; }
|
||||
.empty-text { font-size: 24rpx; line-height: 34rpx; }
|
||||
|
||||
/* ===== 如你项目里已有的工具类,可保留或删除 ===== */
|
||||
.ml-3 { margin-left: 6rpx; }
|
||||
.mt-17 { margin-top: 12rpx; }
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: transparent;
|
||||
}
|
66
pages/course/waitPayOrder/waitPayOrder.js
Normal file
@ -0,0 +1,66 @@
|
||||
// pages/course/waitPayOrder/waitPayOrder.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
2
pages/course/waitPayOrder/waitPayOrder.wxml
Normal file
@ -0,0 +1,2 @@
|
||||
<!--pages/course/waitPayOrder/waitPayOrder.wxml-->
|
||||
<text>pages/course/waitPayOrder/waitPayOrder.wxml</text>
|
@ -0,0 +1,88 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
// pages/dashboardModule/overviewPerformance/overviewPerformance.js
|
||||
Page({
|
||||
data: {
|
||||
totalAmount: 0, // 订单总金额
|
||||
netAmount: 0, // 净成交
|
||||
promoCount: 0, // 客户数量
|
||||
superCount: 0, // 主管数量
|
||||
empCount: 0, // 员工数量
|
||||
orderCount: 0, // 下单数量
|
||||
toRelease: 0, // 待释放
|
||||
toSettle: 0, // 可结算
|
||||
settled: 0, // 已结算
|
||||
refunded: 0, // 已退回
|
||||
todayOrderCount: 0, // 今日下单数量
|
||||
todayOrderAmount: 0, // 今日下单总金额
|
||||
todayRefundCount: 0, // 今日退款数量
|
||||
todayRefundAmount: 0, // 今日退款总金额
|
||||
todayPromotionCount: 0, // 今日推广数量
|
||||
monthOrderCount: 0, // 本月下单数量
|
||||
monthOrderAmount: 0, // 本月下单总金额
|
||||
monthRefundCount: 0, // 本月退款数量
|
||||
monthRefundAmount: 0, // 本月退款总金额
|
||||
monthPromotionCount: 0, // 本月推广数量
|
||||
userRole: '', // 用户角色
|
||||
isShowArr: [],
|
||||
widthRate: '30%'
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
console.log('--->',options);
|
||||
this.fetchPerformance();
|
||||
this.setData({
|
||||
userRole: options.role
|
||||
})
|
||||
let showRole = '';
|
||||
switch (options.role) {
|
||||
case 'manager':
|
||||
showRole = '经理';
|
||||
break;
|
||||
case 'supervisor':
|
||||
showRole = '主管';
|
||||
break;
|
||||
case 'staff':
|
||||
showRole = '员工';
|
||||
break;
|
||||
}
|
||||
this.setData({ showRole });
|
||||
if (options.role === 'manager') this.setData({isShowArr: [true, true, true]})
|
||||
else if (options.role === 'supervisor') this.setData({isShowArr: [false, true, true]})
|
||||
else if (options.role === 'staff') this.setData({isShowArr: [false, false, true]})
|
||||
const trueCount = this.data.isShowArr.filter(v => v === true).length;
|
||||
if (trueCount === 3) this.setData({widthRate: '30%'})
|
||||
else if (trueCount === 2) this.setData({widthRate: '47.5%'})
|
||||
else if (trueCount === 1) this.setData({widthRate: '100%'})
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.fetchPerformance()
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
fetchPerformance() {
|
||||
wx.request({
|
||||
url: baseUrl + '/perform/mini/query/dashboard',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data.code === 1) {
|
||||
// 直接把后端 data 对象铺平到页面 data
|
||||
this.setData(res.data.data);
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '请求失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
<view class="flex-col page">
|
||||
<text class="self-center text">{{ showRole }}端绩效总览</text>
|
||||
<view class="flex-col justify-start self-stretch relative group mt-41">
|
||||
<view class="flex-col group_2">
|
||||
|
||||
<!-- 今日数据 -->
|
||||
<view class="flex-row equal-division">
|
||||
<view class="flex-col items-start equal-division-item section">
|
||||
<text class="font_3 text_8">今日数据</text>
|
||||
<text class="font text_10">今日下单数量</text>
|
||||
<text class="font_2 text_12">{{todayOrderCount}}</text>
|
||||
<text class="font text_14">今日订单总金额</text>
|
||||
<text class="font_2 text_16">¥{{todayOrderAmount}}</text>
|
||||
<text class="font text_18">今日退单数量</text>
|
||||
<text class="font_2 text_20">{{todayRefundCount}}</text>
|
||||
<text class="font text_22">今日退款总金额</text>
|
||||
<text class="font_2 text_24">¥{{todayRefundAmount}}</text>
|
||||
<text class="font_4 text_26">今日推广数量</text>
|
||||
<text class="font_2 text_28">{{todayPromotionCount}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 本月数据 -->
|
||||
<view class="flex-col items-start equal-division-item section_2 ml-19">
|
||||
<text class="font_3 text_9">本月数据</text>
|
||||
<text class="font text_11">本月下单数量</text>
|
||||
<text class="font_2 text_13">{{monthOrderCount}}</text>
|
||||
<text class="font text_15">本月订单总金额</text>
|
||||
<text class="font_2 text_17">¥{{monthOrderAmount}}</text>
|
||||
<text class="font text_19">本月退单数量</text>
|
||||
<text class="font_2 text_21">{{monthRefundCount}}</text>
|
||||
<text class="font text_23">本月退款总金额</text>
|
||||
<text class="font_2 text_25">¥{{monthRefundAmount}}</text>
|
||||
<text class="font_4 text_27">本月推广数量</text>
|
||||
<text class="font_2 text_29">{{monthPromotionCount}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 财务状态 -->
|
||||
<view class="mt-30 flex-col section_3">
|
||||
<text class="self-start font_3">财务状态</text>
|
||||
<view class="mt-26 flex-col self-stretch">
|
||||
<view class="flex-row justify-between items-baseline">
|
||||
<text class="font text_30">待释放</text>
|
||||
<text class="font_2 text_31">{{toRelease}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between items-baseline mt-19">
|
||||
<text class="font text_32">可结算</text>
|
||||
<text class="font_2 text_33">{{toSettle}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between items-baseline mt-19">
|
||||
<text class="font text_34">已结算</text>
|
||||
<text class="font_2 text_35">{{settled}}</text>
|
||||
</view>
|
||||
<view class="flex-row justify-between items-baseline mt-19">
|
||||
<text class="font text_36">已退回</text>
|
||||
<text class="font_2 text_37">{{refunded}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 底部网格 -->
|
||||
<view class="pos">
|
||||
<view class="flex-row" style="justify-content: space-between;">
|
||||
<view style="width: {{widthRate}};" class="flex-col items-center grid-item" wx:if="{{isShowArr[0]}}">
|
||||
<text class="font text_2">主管数量</text>
|
||||
<text class="mt-20 font_2">{{superCount}}</text>
|
||||
</view>
|
||||
<view style="width: {{widthRate}};" class="flex-col items-center grid-item" wx:if="{{isShowArr[1]}}">
|
||||
<text class="font text_3">员工数量</text>
|
||||
<text class="mt-20 font_2">{{empCount}}</text>
|
||||
</view>
|
||||
<view style="width: {{widthRate}};" class="flex-col items-center grid-item" wx:if="{{isShowArr[2]}}">
|
||||
<text class="font text_4">客户数量</text>
|
||||
<text class="mt-20 font_2">{{promoCount}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex-row" style="justify-content: space-between;">
|
||||
<view class="flex-col items-center grid-item_2" style="margin-right: 10rpx">
|
||||
<text class="font text_5">订单总金额</text>
|
||||
<text class="mt-20 font_2">¥{{totalAmount}}</text>
|
||||
</view>
|
||||
<view class="flex-col items-center grid-item_2" style="margin: 40rpx 10rpx 0">
|
||||
<text class="font text_6">订单净成交</text>
|
||||
<text class="mt-20 font_2">¥{{netAmount}}</text>
|
||||
</view>
|
||||
<view class="flex-col items-center grid-item_2" style="margin-left: 10rpx">
|
||||
<text class="font text_7">下单数量</text>
|
||||
<text class="mt-20 font_2">{{orderCount}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
@ -0,0 +1,254 @@
|
||||
.mt-41 {
|
||||
margin-top: 76.88rpx;
|
||||
}
|
||||
.ml-19 {
|
||||
margin-left: 35.63rpx;
|
||||
}
|
||||
.mt-19 {
|
||||
margin-top: 35.63rpx;
|
||||
}
|
||||
.page {
|
||||
padding-top: 71.25rpx;
|
||||
background-color: #fefbf6;
|
||||
box-shadow: 0rpx 3.75rpx 7.5rpx #00000040;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
.text {
|
||||
color: #e67e22;
|
||||
font-size: 45rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
font-weight: 700;
|
||||
line-height: 42.71rpx;
|
||||
}
|
||||
.group {
|
||||
padding-top: 168.75rpx;
|
||||
}
|
||||
.group_2 {
|
||||
margin-right: 33.75rpx;
|
||||
padding: 138.75rpx 0 120rpx 41.25rpx;
|
||||
filter: drop-shadow(0rpx 3.75rpx 3.75rpx #00000040);
|
||||
}
|
||||
.equal-division {
|
||||
padding-top: 48.75rpx;
|
||||
}
|
||||
.equal-division-item {
|
||||
flex: 1 1 320.63rpx;
|
||||
}
|
||||
.section {
|
||||
padding: 41.25rpx 33.75rpx 33.75rpx;
|
||||
filter: drop-shadow(0rpx 3.75rpx 3.75rpx #00000040);
|
||||
background-color: #ffffff;
|
||||
border-radius: 9.38rpx;
|
||||
height: 684.38rpx;
|
||||
border-left: solid 5.88rpx #e67e22;
|
||||
/* border-right: solid 1.88rpx #e67e22; */
|
||||
border-top: solid 5.88rpx #e67e22;
|
||||
/* border-bottom: solid 1.88rpx #e67e22; */
|
||||
}
|
||||
.font_3 {
|
||||
font-size: 30rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 28.01rpx;
|
||||
color: #e67e22;
|
||||
}
|
||||
.text_8 {
|
||||
line-height: 28.24rpx;
|
||||
}
|
||||
.font {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 22.91rpx;
|
||||
color: #666666;
|
||||
}
|
||||
.text_10 {
|
||||
margin-top: 33.75rpx;
|
||||
line-height: 24.69rpx;
|
||||
}
|
||||
.text_14 {
|
||||
margin-top: 41.25rpx;
|
||||
line-height: 24.75rpx;
|
||||
}
|
||||
.text_18 {
|
||||
margin-top: 41.25rpx;
|
||||
line-height: 24.69rpx;
|
||||
}
|
||||
.text_22 {
|
||||
margin-top: 41.25rpx;
|
||||
line-height: 24.75rpx;
|
||||
}
|
||||
.font_4 {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 24.92rpx;
|
||||
color: #666666;
|
||||
}
|
||||
.text_26 {
|
||||
margin-top: 41.25rpx;
|
||||
}
|
||||
.section_2 {
|
||||
padding: 41.25rpx 33.75rpx 33.75rpx;
|
||||
filter: drop-shadow(0rpx 3.75rpx 3.75rpx #00000040);
|
||||
background-color: #ffffff;
|
||||
border-radius: 9.38rpx;
|
||||
height: 684.38rpx;
|
||||
border-left: solid 5.88rpx #f1c40f;
|
||||
/* border-right: solid 1.88rpx #f1c40f; */
|
||||
border-top: solid 5.88rpx #f1c40f;
|
||||
/* border-bottom: solid 1.88rpx #f1c40f; */
|
||||
}
|
||||
.text_9 {
|
||||
color: #f1c40f;
|
||||
line-height: 27.99rpx;
|
||||
}
|
||||
.text_11 {
|
||||
margin-top: 33.75rpx;
|
||||
line-height: 24.69rpx;
|
||||
}
|
||||
.text_15 {
|
||||
margin-top: 41.25rpx;
|
||||
line-height: 24.75rpx;
|
||||
}
|
||||
.text_19 {
|
||||
margin-top: 41.25rpx;
|
||||
line-height: 24.69rpx;
|
||||
}
|
||||
.text_23 {
|
||||
margin-top: 41.25rpx;
|
||||
line-height: 24.75rpx;
|
||||
}
|
||||
.text_27 {
|
||||
margin-top: 41.25rpx;
|
||||
}
|
||||
.section_3 {
|
||||
padding: 37.5rpx 20rpx 37.5rpx 33.75rpx;
|
||||
filter: drop-shadow(0rpx 3.75rpx 3.75rpx #00000040);
|
||||
background-color: #ffffff;
|
||||
border-radius: 9.38rpx;
|
||||
border-left: solid 5.88rpx #e67e22;
|
||||
/* border-right: solid 1.88rpx #e67e22; */
|
||||
border-top: solid 5.88rpx #e67e22;
|
||||
/* border-bottom: solid 1.88rpx #e67e22; */
|
||||
}
|
||||
.text_30 {
|
||||
line-height: 24.3rpx;
|
||||
}
|
||||
.text_32 {
|
||||
line-height: 24.3rpx;
|
||||
}
|
||||
.text_34 {
|
||||
line-height: 24.3rpx;
|
||||
}
|
||||
.text_36 {
|
||||
line-height: 24.3rpx;
|
||||
}
|
||||
.grid {
|
||||
height: 306.56rpx;
|
||||
display: grid;
|
||||
grid-template-rows: repeat(2, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
row-gap: 32.94rpx;
|
||||
column-gap: 50.19rpx;
|
||||
}
|
||||
.pos {
|
||||
position: absolute;
|
||||
left: 39.38rpx;
|
||||
right: 33rpx;
|
||||
top: 0;
|
||||
}
|
||||
.grid-item {
|
||||
padding: 22.5rpx 0;
|
||||
filter: drop-shadow(0rpx 3.75rpx 3.75rpx #00000040);
|
||||
background-color: #ffffff;
|
||||
border-radius: 9.38rpx;
|
||||
border-left: solid 5.88rpx #e67e22;
|
||||
/* border-right: solid 1.88rpx #e67e22; */
|
||||
border-top: solid 5.88rpx #e67e22;
|
||||
/* border-bottom: solid 1.88rpx #e67e22; */
|
||||
}
|
||||
.text_2 {
|
||||
line-height: 24.34rpx;
|
||||
}
|
||||
.font_2 {
|
||||
font-size: 30rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 22.91rpx;
|
||||
color: #e67e22;
|
||||
}
|
||||
.text_37 {
|
||||
margin-right: 7.5rpx;
|
||||
}
|
||||
.text_35 {
|
||||
margin-right: 3.75rpx;
|
||||
}
|
||||
.text_33 {
|
||||
margin-right: 3.75rpx;
|
||||
}
|
||||
.text_31 {
|
||||
margin-right: 3.75rpx;
|
||||
}
|
||||
.text_29 {
|
||||
margin-top: 26.25rpx;
|
||||
}
|
||||
.text_25 {
|
||||
margin-left: 3.75rpx;
|
||||
margin-top: 26.25rpx;
|
||||
}
|
||||
.text_21 {
|
||||
margin-top: 26.25rpx;
|
||||
line-height: 22.54rpx;
|
||||
}
|
||||
.text_17 {
|
||||
margin-left: 3.75rpx;
|
||||
margin-top: 26.25rpx;
|
||||
}
|
||||
.text_13 {
|
||||
margin-top: 26.25rpx;
|
||||
}
|
||||
.text_28 {
|
||||
margin-top: 26.25rpx;
|
||||
}
|
||||
.text_24 {
|
||||
margin-left: 3.75rpx;
|
||||
margin-top: 26.25rpx;
|
||||
}
|
||||
.text_20 {
|
||||
margin-top: 26.25rpx;
|
||||
line-height: 22.54rpx;
|
||||
}
|
||||
.text_16 {
|
||||
margin-left: 3.75rpx;
|
||||
margin-top: 26.25rpx;
|
||||
}
|
||||
.text_12 {
|
||||
margin-top: 26.25rpx;
|
||||
}
|
||||
.text_3 {
|
||||
line-height: 24.28rpx;
|
||||
}
|
||||
.text_4 {
|
||||
line-height: 24.54rpx;
|
||||
}
|
||||
.grid-item_2 {
|
||||
width: 30%;
|
||||
margin-top: 40rpx;
|
||||
padding: 22.5rpx 0;
|
||||
filter: drop-shadow(0rpx 3.75rpx 3.75rpx #00000040);
|
||||
background-color: #ffffff;
|
||||
border-radius: 9.38rpx;
|
||||
border-left: solid 5.88rpx #f1c40f;
|
||||
/* border-right: solid 1.88rpx #f1c40f; */
|
||||
border-top: solid 5.88rpx #f1c40f;
|
||||
/* border-bottom: solid 1.88rpx #f1c40f; */
|
||||
}
|
||||
.text_5 {
|
||||
line-height: 24.49rpx;
|
||||
}
|
||||
.text_6 {
|
||||
line-height: 24.56rpx;
|
||||
}
|
||||
.text_7 {
|
||||
line-height: 24.26rpx;
|
||||
}
|
BIN
pages/dashboardModule/performanceRanking/images/bottom.png
Normal file
After Width: | Height: | Size: 259 B |
209
pages/dashboardModule/performanceRanking/performanceRanking.js
Normal file
@ -0,0 +1,209 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 用于存储输入框数据
|
||||
nickName: '',
|
||||
phoneNumber: '',
|
||||
selectedSortField: '员工数量', // 默认选择"员工数量"
|
||||
selectedSortOrder: '降序', // 默认选择升序
|
||||
sortFieldsByManager: ['员工数量', '推广人数', '下单数量', '总订单金额', '净成交金额'],
|
||||
sortFieldsBySupervisor: ['推广人数', '下单数量', '总订单金额', '净成交金额'],
|
||||
sortField: 'empCount',
|
||||
sortOrder: 'descend',
|
||||
sortOrders: ['升序', '降序'],
|
||||
items: [], // 用于存储查询结果
|
||||
role: '', // 假设初始为主管角色,可以根据实际情况动态设置
|
||||
k: 1,
|
||||
showRole: ''
|
||||
},
|
||||
|
||||
// 主管名称输入
|
||||
onNameInput(e) {
|
||||
this.setData({
|
||||
nickName: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
// 手机号输入
|
||||
onPhoneInput(e) {
|
||||
this.setData({
|
||||
phoneNumber: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
// 选择排序字段
|
||||
onSortFieldChange(e) {
|
||||
const sortFieldsMap = {
|
||||
'员工数量': 'empCount',
|
||||
'推广人数': 'promoCount',
|
||||
'下单数量': 'orderCount',
|
||||
'总订单金额': 'totalAmount',
|
||||
'净成交金额': 'netAmount'
|
||||
};
|
||||
const { showRole, sortFieldsByManager, sortFieldsBySupervisor } = this.data
|
||||
let selectedField = showRole === '主管' ? sortFieldsByManager[e.detail.value] : sortFieldsBySupervisor[e.detail.value];
|
||||
this.setData({
|
||||
selectedSortField: selectedField,
|
||||
sortField: sortFieldsMap[selectedField], // 默认是 id
|
||||
});
|
||||
this.onSearch()
|
||||
},
|
||||
|
||||
// 选择排序顺序
|
||||
onSortOrderChange(e) {
|
||||
const selectedOrder = e.detail.value === '0' ? 'ascend' : 'descend';
|
||||
this.setData({
|
||||
selectedSortOrder: selectedOrder === 'ascend' ? '升序' : '降序',
|
||||
sortOrder: selectedOrder,
|
||||
});
|
||||
this.onSearch()
|
||||
},
|
||||
|
||||
// 搜索按钮点击
|
||||
onSearch() {
|
||||
const { showRole, role } = this.data;
|
||||
// // —— 新增:校验主管名称 ——
|
||||
// const nameRegex = /^[\u4e00-\u9fa5]+$/;
|
||||
// if (!this.data.nickName) {
|
||||
// wx.showToast({ title: '主管名称不能为空', icon: 'none' });
|
||||
// return;
|
||||
// }
|
||||
// if (!nameRegex.test(this.data.nickName)) {
|
||||
// wx.showToast({ title: '主管名称只能为汉字', icon: 'none' });
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // —— 新增:校验手机号 ——
|
||||
// if (!this.data.phoneNumber) {
|
||||
// wx.showToast({ title: '手机号不能为空', icon: 'none' });
|
||||
// return;
|
||||
// }
|
||||
// if (this.data.phoneNumber.length < 11) {
|
||||
// wx.showToast({ title: '手机号不够11位', icon: 'none' });
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 原排序条件校验,保持不变
|
||||
// if (this.data.selectedSortField === '待选择') {
|
||||
// wx.showToast({
|
||||
// title: '排序条件不能为空',
|
||||
// icon: 'none'
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 显示加载中
|
||||
wx.showLoading({
|
||||
title: '加载中...',
|
||||
mask: true // 显示遮罩层
|
||||
});
|
||||
|
||||
if (showRole === '员工') {
|
||||
this.setData({ sortField: 'promoCount' })
|
||||
}
|
||||
|
||||
const requestData = {
|
||||
nickName: this.data.nickName,
|
||||
phoneNumber: this.data.phoneNumber,
|
||||
sortField: this.data.sortField || '',
|
||||
sortOrder: this.data.sortOrder || 'ascend'
|
||||
};
|
||||
console.log('requestData====>', requestData)
|
||||
|
||||
if(role === 'manager') {
|
||||
wx.request({
|
||||
url: baseUrl + '/perform/rank/supervisor', // 替换为实际API地址
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: requestData,
|
||||
success: (res) => {
|
||||
console.log('看看后端--->', res.data);
|
||||
// 请求成功后,隐藏loading
|
||||
wx.hideLoading();
|
||||
|
||||
if (res.data.code === 1) {
|
||||
this.setData({
|
||||
items: res.data.data
|
||||
});
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 请求失败后,隐藏loading
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '请求失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if( role === 'supervisor' || role === 'staff') {
|
||||
wx.request({
|
||||
url: baseUrl + '/perform/rank/staff', // 替换为实际API地址
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: requestData,
|
||||
success: (res) => {
|
||||
console.log('看看后端--->', res.data);
|
||||
// 请求成功后,隐藏loading
|
||||
wx.hideLoading();
|
||||
|
||||
if (res.data.code === 1) {
|
||||
this.setData({
|
||||
items: res.data.data
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '没有数据',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 请求失败后,隐藏loading
|
||||
wx.hideLoading();
|
||||
|
||||
wx.showToast({
|
||||
title: '请求失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 根据身份确定角色
|
||||
const role = options.role;
|
||||
this.setData({k: options.k})
|
||||
if (role === 'staff') this.setData({selectedSortField: '推广人数'})
|
||||
console.log('角色---->',options.role);
|
||||
this.setData({ role });
|
||||
let showRole = '';
|
||||
switch (options.role) {
|
||||
case 'manager':
|
||||
showRole = '主管';
|
||||
break;
|
||||
case 'supervisor':
|
||||
showRole = '员工';
|
||||
break;
|
||||
case 'staff':
|
||||
showRole = '员工'
|
||||
}
|
||||
this.setData({ showRole });
|
||||
this.onSearch()
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.onSearch()
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
});
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
127
pages/dashboardModule/performanceRanking/performanceRanking.wxml
Normal file
@ -0,0 +1,127 @@
|
||||
<!-- pages/dashboardModule/ranking/ranking.wxml(按你的实际路径命名) -->
|
||||
<view class="page">
|
||||
<!-- 页面标题 -->
|
||||
<view class="page-title">
|
||||
<text class="title">{{ showRole }}绩效排名</text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="content no-scrollbar">
|
||||
<!-- 表单卡片 -->
|
||||
<view class="card form-card">
|
||||
<!-- 名称 -->
|
||||
<view class="field">
|
||||
<text class="field-label">{{ showRole }}名称</text>
|
||||
<view class="input-box">
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入{{ showRole }}名称"
|
||||
bindinput="onNameInput"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 -->
|
||||
<view class="field">
|
||||
<text class="field-label">手机号</text>
|
||||
<view class="input-box">
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入手机号"
|
||||
bindinput="onPhoneInput"
|
||||
maxlength="11"
|
||||
type="number"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 排序条件 -->
|
||||
<view class="field">
|
||||
<text class="field-label">排序条件</text>
|
||||
<view class="picker-row">
|
||||
<!-- 排序字段 -->
|
||||
<view class="picker-box">
|
||||
<picker wx:if="{{ role === 'manager' }}"
|
||||
mode="selector"
|
||||
range="{{ sortFieldsByManager }}"
|
||||
bindchange="onSortFieldChange">
|
||||
<view class="picker-inner">
|
||||
<text class="picker-text">{{ selectedSortField }}</text>
|
||||
<image class="arrow" src="./images/bottom.png"/>
|
||||
</view>
|
||||
</picker>
|
||||
|
||||
<picker wx:if="{{ role === 'supervisor' || role === 'staff' }}"
|
||||
mode="selector"
|
||||
range="{{ sortFieldsBySupervisor }}"
|
||||
bindchange="onSortFieldChange">
|
||||
<view class="picker-inner">
|
||||
<text class="picker-text">{{ selectedSortField }}</text>
|
||||
<image class="arrow" src="./images/bottom.png" />
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 排序顺序 -->
|
||||
<view class="picker-box">
|
||||
<picker mode="selector"
|
||||
range="{{ sortOrders }}"
|
||||
bindchange="onSortOrderChange">
|
||||
<view class="picker-inner">
|
||||
<text class="picker-text">{{ selectedSortOrder }}</text>
|
||||
<image class="arrow" src="./images/bottom.png" />
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索按钮 -->
|
||||
<view class="btn btn-primary" bindtap="onSearch">搜索</view>
|
||||
</view>
|
||||
|
||||
<!-- 结果列表 -->
|
||||
<view class="result-wrap">
|
||||
<view class="card item-card"
|
||||
wx:for="{{ items }}"
|
||||
wx:for-item="item"
|
||||
wx:for-index="index"
|
||||
wx:key="index">
|
||||
|
||||
<!-- 头部:排名 + 基本信息 -->
|
||||
<view class="item-head">
|
||||
<view class="rank-badge {{ index < 3 ? 'rank-top' : '' }}">
|
||||
<text class="rank-text">{{ index + 1 }}</text>
|
||||
</view>
|
||||
|
||||
<view class="person-line">
|
||||
<text class="name">{{ item.nickName }}</text>
|
||||
<text class="phone">{{ item.phoneNumber }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 指标 chips -->
|
||||
<view class="chips">
|
||||
<view wx:if="{{ k === '1' }}" class="chip">员工:{{ item.empCount }}</view>
|
||||
<view class="chip">推广:{{ item.promoCount }}</view>
|
||||
<view class="chip">下单:{{ item.orderCount }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 金额类键值行 -->
|
||||
<view class="kv">
|
||||
<text class="kv-key">总额</text>
|
||||
<text class="kv-val money">¥{{ item.totalAmount }}</text>
|
||||
</view>
|
||||
<view class="kv">
|
||||
<text class="kv-key">净成交</text>
|
||||
<text class="kv-val money">¥{{ item.netAmount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view wx:if="{{ !items || !items.length }}" class="empty">
|
||||
<image class="empty-img" src="/assets/empty-list.png" mode="aspectFit" />
|
||||
<text class="empty-text">暂无数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
189
pages/dashboardModule/performanceRanking/performanceRanking.wxss
Normal file
@ -0,0 +1,189 @@
|
||||
/* ===== 页面框架 ===== */
|
||||
.page {
|
||||
background: #fefbf6;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
padding: 24rpx 24rpx 0;
|
||||
}
|
||||
.title {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #ff8a00; /* 主色:亮橙 */
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 隐藏滚动条 */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ===== 卡片通用 ===== */
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border-radius: 18rpx;
|
||||
padding: 24rpx;
|
||||
border: 2rpx solid #ffeaa7; /* 与你项目的浅橙描边一致 */
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.05);
|
||||
}
|
||||
.card + .card { margin-top: 20rpx; }
|
||||
|
||||
/* ===== 表单区 ===== */
|
||||
.form-card .field + .field { margin-top: 20rpx; }
|
||||
|
||||
.field-label {
|
||||
font-size: 28rpx;
|
||||
color: #555555;
|
||||
margin-bottom: 12rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 输入框 */
|
||||
.input-box {
|
||||
height: 84rpx;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid #ffeaa7;
|
||||
background: #ffffff;
|
||||
padding: 0 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
|
||||
/* 选择器行 */
|
||||
.picker-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.picker-box {
|
||||
height: 84rpx;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid #ffeaa7;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
.picker-inner {
|
||||
padding: 0 20rpx;
|
||||
width: 270rpx;
|
||||
height: 84rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.picker-text { font-size: 28rpx; color: #1f1f1f;}
|
||||
.arrow { width: 28rpx; height: 28rpx; position: absolute; right: 20rpx;}
|
||||
|
||||
/* 搜索按钮 */
|
||||
.btn {
|
||||
height: 88rpx;
|
||||
border-radius: 999rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
.btn-primary {
|
||||
background: linear-gradient(180deg, #ffa400 0%, #ff8a00 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 6rpx 14rpx rgba(255,138,0,0.30);
|
||||
}
|
||||
|
||||
/* ===== 列表与条目 ===== */
|
||||
.result-wrap { margin-top: 20rpx; }
|
||||
|
||||
.item-card { padding-top: 20rpx; }
|
||||
|
||||
/* 顶部信息 */
|
||||
.item-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.rank-badge {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f0f0f0;
|
||||
border: 2rpx solid #e6e6e6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rank-top {
|
||||
background: #fff6e6;
|
||||
border-color: #ffd6b3;
|
||||
}
|
||||
.rank-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #ff8a00; /* 改为亮橙 */
|
||||
}
|
||||
|
||||
.person-line {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 12rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.name { font-size: 30rpx; font-weight: 600; color: #1f1f1f; }
|
||||
.phone { font-size: 26rpx; color: #666666; }
|
||||
|
||||
/* 指标 Chips */
|
||||
.chips {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
flex-wrap: wrap;
|
||||
margin: 8rpx 0 4rpx;
|
||||
}
|
||||
.chip {
|
||||
padding: 10rpx 16rpx;
|
||||
background: #f7f9fc;
|
||||
color: #3d4f6e;
|
||||
border: 1rpx solid #e6edf7;
|
||||
border-radius: 12rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* 金额类键值行 */
|
||||
.kv {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12rpx 0;
|
||||
border-top: 1rpx dashed #f0f0f0;
|
||||
}
|
||||
.kv:first-of-type { border-top: 0; }
|
||||
.kv-key { font-size: 26rpx; color: #666666; }
|
||||
.kv-val { font-size: 28rpx; color: #1f1f1f; }
|
||||
.money { color: #ff8a00; font-weight: 700; }
|
||||
|
||||
/* ===== 空状态 ===== */
|
||||
.empty {
|
||||
padding: 120rpx 0 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #999999;
|
||||
}
|
||||
.empty-img { width: 300rpx; height: 300rpx; margin-bottom: 16rpx; }
|
||||
.empty-text { font-size: 26rpx; }
|
122
pages/dashboardModule/staffPerformance/staffPerformance.js
Normal file
@ -0,0 +1,122 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
// pages/dashboardModule/supervisorPerformance/supervisorPerformance.js
|
||||
Page({
|
||||
data: {
|
||||
nickName: '', // 主管名称
|
||||
phoneNumber: '', // 手机号
|
||||
showList: false, // 是否显示绩效列表
|
||||
performanceList: [], // 绩效列表数据,含 ratePercent 字段
|
||||
supervisorUserId: 0, // 上级主管id
|
||||
},
|
||||
|
||||
onNameInput(e) {
|
||||
this.setData({ nickName: e.detail.value });
|
||||
},
|
||||
onPhoneInput(e) {
|
||||
this.setData({ phoneNumber: e.detail.value });
|
||||
},
|
||||
|
||||
onSearch() {
|
||||
const nickName = this.data.nickName.trim();
|
||||
const phoneNumber = this.data.phoneNumber.trim();
|
||||
const { supervisorUserId } = this.data;
|
||||
|
||||
wx.request({
|
||||
url: baseUrl + '/perform/query/staff',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: {
|
||||
nickName: nickName,
|
||||
phoneNumber: phoneNumber,
|
||||
supervisorUserId: supervisorUserId,
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('--->后端返回记录',res.data);
|
||||
if (res.data.code === 1) {
|
||||
// 预处理:给每条记录加一个 ratePercent 字段
|
||||
const listWithRate = res.data.data.map(item => {
|
||||
const ratePercent = (item.rakeRewardsRate * 100).toFixed(2);
|
||||
return Object.assign({}, item, { ratePercent });
|
||||
});
|
||||
// 分两次 setData,不链
|
||||
this.setData({ performanceList: listWithRate });
|
||||
this.setData({ showList: true });
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 全查
|
||||
onSearchSupId() {
|
||||
|
||||
const { supervisorUserId } = this.data;
|
||||
|
||||
wx.request({
|
||||
url: baseUrl + '/perform/query/staff',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: { supervisorUserId },
|
||||
success: (res) => {
|
||||
console.log('--->后端返回记录',res.data);
|
||||
if (res.data.code === 1) {
|
||||
// 预处理:给每条记录加一个 ratePercent 字段
|
||||
const listWithRate = res.data.data.map(item => {
|
||||
const ratePercent = (item.rakeRewardsRate * 100).toFixed(2);
|
||||
return Object.assign({}, item, { ratePercent });
|
||||
});
|
||||
// 分两次 setData,不链
|
||||
this.setData({ performanceList: listWithRate });
|
||||
this.setData({ showList: true });
|
||||
} else {
|
||||
wx.showToast({ title: res.data.message || '查询失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onCopyPhone(e) {
|
||||
const phone = e.currentTarget.dataset.phone;
|
||||
wx.setClipboardData({
|
||||
data: phone,
|
||||
success() {
|
||||
wx.showToast({ title: '手机号已复制', icon: 'success' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
console.log('========>', options)
|
||||
this.setData({
|
||||
supervisorUserId: options.supId,
|
||||
})
|
||||
this.onSearchSupId();
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.onSearchSupId()
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
// 跳转用户订单
|
||||
gotoUser(e) {
|
||||
const { id } = e.currentTarget.dataset;
|
||||
|
||||
wx.navigateTo({
|
||||
url: `/pages/dashboardModule/userOrderPerformance/userOrderPerformance?userId=${id}`,
|
||||
})
|
||||
},
|
||||
});
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
128
pages/dashboardModule/staffPerformance/staffPerformance.wxml
Normal file
@ -0,0 +1,128 @@
|
||||
<!-- pages/dashboardModule/supervisorPerformance/supervisorPerformance.wxml -->
|
||||
<view class="page">
|
||||
<!-- 标题 -->
|
||||
<view class="page-title">
|
||||
<text class="title">员工业绩报表</text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="content no-scrollbar">
|
||||
<!-- 搜索表单 -->
|
||||
<view class="card form-card">
|
||||
<!-- 员工名称 -->
|
||||
<view class="field">
|
||||
<text class="field-label">员工名称</text>
|
||||
<view class="input-box">
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入员工名称"
|
||||
placeholder-class="ph"
|
||||
bindinput="onNameInput"
|
||||
value="{{ nickName }}"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 -->
|
||||
<view class="field">
|
||||
<text class="field-label">手机号</text>
|
||||
<view class="input-box">
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入手机号"
|
||||
placeholder-class="ph"
|
||||
bindinput="onPhoneInput"
|
||||
value="{{ phoneNumber }}"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索 -->
|
||||
<view class="btn btn-primary" bindtap="onSearch">搜索</view>
|
||||
</view>
|
||||
|
||||
<!-- 业绩列表 -->
|
||||
<block wx:if="{{ showList }}">
|
||||
<!-- 空状态(可选) -->
|
||||
<view wx:if="{{ !performanceList || performanceList.length === 0 }}" class="empty">
|
||||
<image class="empty-img" src="/assets/empty-list.png" mode="aspectFit" />
|
||||
<text class="empty-text">暂无数据</text>
|
||||
</view>
|
||||
|
||||
<!-- 列表卡片 -->
|
||||
<view wx:for="{{ performanceList }}"
|
||||
wx:key="item.id"
|
||||
wx:for-item="item"
|
||||
wx:for-index="index"
|
||||
class="card perf-card">
|
||||
|
||||
<!-- 顶部:编号 + 员工 + 跳转 -->
|
||||
<view class="topline">
|
||||
<view class="id-and-name">
|
||||
<text class="no">编号:{{ index + 1 }}</text>
|
||||
<text class="name">员工:{{ item.nickName }}</text>
|
||||
</view>
|
||||
<view class="link-btn" bind:tap="gotoUser" data-id="{{ item.userId }}">
|
||||
<text class="link-text">客户订单明细 >></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 + 复制 -->
|
||||
<view class="row">
|
||||
<text class="row-key">手机号</text>
|
||||
<view class="row-val">
|
||||
<text class="mono">{{ item.phoneNumber }}</text>
|
||||
<text class="copy" bindtap="onCopyPhone" data-phone="{{ item.phoneNumber }}">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 客户数 + 抽成比例(徽章) -->
|
||||
<view class="chips">
|
||||
<view class="chip">客户数:{{ item.empCount }}</view>
|
||||
<view class="chip">比例:{{ item.ratePercent }}%</view>
|
||||
</view>
|
||||
|
||||
<!-- 业绩九宫格 -->
|
||||
<view class="grid">
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">下单量</text>
|
||||
<text class="gi-value">{{ item.orderCount }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">总订单</text>
|
||||
<text class="gi-value money">¥{{ item.totalAmount }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">净成交</text>
|
||||
<text class="gi-value money">¥{{ item.netAmount }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">待释放</text>
|
||||
<text class="gi-value money">¥{{ item.toRelease }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">可结算</text>
|
||||
<text class="gi-value">{{ item.toSettle }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">已结算</text>
|
||||
<text class="gi-value money">¥{{ item.settled }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">推广数</text>
|
||||
<text class="gi-value">{{ item.promoCount }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">退款</text>
|
||||
<text class="gi-value money">¥{{ item.refunded }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">已回退</text>
|
||||
<text class="gi-value money">¥0</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
176
pages/dashboardModule/staffPerformance/staffPerformance.wxss
Normal file
@ -0,0 +1,176 @@
|
||||
/* 基础 */
|
||||
.page {
|
||||
background: #fefbf6; /* 暖米黄背景 */
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-title { padding: 24rpx 24rpx 0; }
|
||||
.title {
|
||||
color: #ff8a00; /* 主标题亮橙 */
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 隐藏滚动条 */
|
||||
.no-scrollbar::-webkit-scrollbar { width: 0; height: 0; display: none; }
|
||||
|
||||
/* 卡片 */
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border-radius: 18rpx;
|
||||
padding: 24rpx;
|
||||
border: 2rpx solid #ffeaa7; /* 浅橙描边 */
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.05);
|
||||
}
|
||||
.card + .card { margin-top: 20rpx; }
|
||||
|
||||
/* 表单 */
|
||||
.form-card .field + .field { margin-top: 20rpx; }
|
||||
|
||||
.field-label {
|
||||
font-size: 28rpx;
|
||||
color: #555555;
|
||||
margin-bottom: 12rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.input-box {
|
||||
background: #ffffff;
|
||||
border: 2rpx solid #ffeaa7;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 84rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
.ph { color: #b8b8b8; }
|
||||
|
||||
/* 按钮 */
|
||||
.btn {
|
||||
height: 88rpx;
|
||||
border-radius: 999rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
.btn-primary {
|
||||
background: linear-gradient(180deg, #ffa400 0%, #ff8a00 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 6rpx 14rpx rgba(255,138,0,0.30);
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty {
|
||||
padding: 120rpx 0 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #999999;
|
||||
}
|
||||
.empty-img { width: 300rpx; height: 300rpx; margin-bottom: 16rpx; }
|
||||
.empty-text { font-size: 26rpx; }
|
||||
|
||||
/* 列表头部行 */
|
||||
.topline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.id-and-name {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 16rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.no { font-size: 24rpx; color: #666666; }
|
||||
.name { font-size: 28rpx; color: #1f1f1f; font-weight: 600; }
|
||||
|
||||
.link-btn {
|
||||
height: 56rpx;
|
||||
padding: 0 18rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #fff6e6;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1rpx solid #ffd6b3;
|
||||
}
|
||||
.link-text { font-size: 24rpx; color: #ff8a00; font-weight: 600; }
|
||||
|
||||
/* 键值行 */
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12rpx 0;
|
||||
border-top: 1rpx dashed #f0f0f0;
|
||||
}
|
||||
.row-key { font-size: 26rpx; color: #666666; }
|
||||
.row-val { display: flex; align-items: center; gap: 16rpx; }
|
||||
.mono { font-size: 28rpx; color: #1f1f1f; }
|
||||
.copy {
|
||||
font-size: 24rpx;
|
||||
color: #ff8a00;
|
||||
padding: 8rpx 14rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #fff4f2;
|
||||
border: 1rpx solid #ffd6cc;
|
||||
}
|
||||
|
||||
/* 徽章 Chips */
|
||||
.chips { display: flex; gap: 12rpx; flex-wrap: wrap; margin: 12rpx 0 4rpx; }
|
||||
.chip {
|
||||
padding: 10rpx 16rpx;
|
||||
background: #f7f9fc;
|
||||
color: #3d4f6e;
|
||||
border: 1rpx solid #e6edf7;
|
||||
border-radius: 12rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* 九宫格 */
|
||||
.grid {
|
||||
margin-top: 8rpx;
|
||||
margin-left: -10rpx;
|
||||
margin-right: -10rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.grid-item {
|
||||
width: 33.3333%;
|
||||
padding: 14rpx 10rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.gi-label { font-size: 24rpx; color: #666666; }
|
||||
.gi-value {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
.gi-value.money { color: #ff8a00; }
|
||||
|
||||
/* 小屏两列适配 */
|
||||
@media (max-width: 360px) {
|
||||
.grid-item { width: 50%; }
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
// pages/dashboardModule/supervisorPerformance/supervisorPerformance.js
|
||||
Page({
|
||||
data: {
|
||||
nickName: '', // 主管名称
|
||||
phoneNumber: '', // 手机号
|
||||
showList: false, // 是否显示绩效列表
|
||||
performanceList: [], // 绩效列表数据,含 ratePercent 字段
|
||||
userRole: '', // 用户角色
|
||||
id: 0,
|
||||
},
|
||||
|
||||
onNameInput(e) {
|
||||
this.setData({ nickName: e.detail.value });
|
||||
},
|
||||
onPhoneInput(e) {
|
||||
this.setData({ phoneNumber: e.detail.value });
|
||||
},
|
||||
|
||||
onSearch() {
|
||||
const nickName = this.data.nickName.trim();
|
||||
const phoneNumber = this.data.phoneNumber.trim();
|
||||
|
||||
wx.request({
|
||||
url: baseUrl + '/perform/query/supervisor',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: {
|
||||
nickName: nickName,
|
||||
phoneNumber: phoneNumber,
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('--->后端返回记录',res.data);
|
||||
if (res.data.code === 1) {
|
||||
// 预处理:给每条记录加一个 ratePercent 字段
|
||||
const listWithRate = res.data.data.map(item => {
|
||||
const ratePercent = (item.rakeRewardsRate * 100).toFixed(2);
|
||||
return Object.assign({}, item, { ratePercent });
|
||||
});
|
||||
// 分两次 setData,不链
|
||||
this.setData({ performanceList: listWithRate });
|
||||
this.setData({ showList: true });
|
||||
} else {
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onCopyPhone(e) {
|
||||
const phone = e.currentTarget.dataset.phone;
|
||||
wx.setClipboardData({
|
||||
data: phone,
|
||||
success() {
|
||||
wx.showToast({ title: '手机号已复制', icon: 'success' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
console.log('--->',options);
|
||||
this.setData({
|
||||
userRole: options.role,
|
||||
id: options.id,
|
||||
})
|
||||
let showRole = '';
|
||||
switch (options.role) {
|
||||
case 'manager':
|
||||
showRole = '主管';
|
||||
break;
|
||||
case 'supervisor':
|
||||
showRole = '员工';
|
||||
break;
|
||||
}
|
||||
this.setData({ showRole });
|
||||
this.onSearch()
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.onSearch()
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
changeStaff(e) {
|
||||
|
||||
const { id } = e.currentTarget.dataset;
|
||||
console.log(id)
|
||||
wx.navigateTo({
|
||||
url: `/pages/dashboardModule/staffPerformance/staffPerformance?supId=${id}`,
|
||||
})
|
||||
},
|
||||
|
||||
});
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
<!-- pages/dashboardModule/supervisorPerformance/supervisorPerformance.wxml -->
|
||||
<view class="page">
|
||||
<!-- 标题 -->
|
||||
<view class="page-title">
|
||||
<text class="title">{{ showRole }}业绩报表</text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="content no-scrollbar">
|
||||
<!-- 搜索表单 -->
|
||||
<view class="card form-card">
|
||||
<!-- 主管名称 -->
|
||||
<view class="field">
|
||||
<text class="field-label">{{ showRole }}名称</text>
|
||||
<view class="input-box">
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入{{ showRole }}名称"
|
||||
placeholder-class="ph"
|
||||
bindinput="onNameInput"
|
||||
value="{{ nickName }}"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 -->
|
||||
<view class="field">
|
||||
<text class="field-label">手机号</text>
|
||||
<view class="input-box">
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入手机号"
|
||||
placeholder-class="ph"
|
||||
bindinput="onPhoneInput"
|
||||
value="{{ phoneNumber }}"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索按钮 -->
|
||||
<view class="btn btn-primary" bindtap="onSearch">搜索</view>
|
||||
</view>
|
||||
|
||||
<!-- 业绩列表(按需显示) -->
|
||||
<block wx:if="{{ showList }}">
|
||||
<!-- 空状态(可选) -->
|
||||
<view wx:if="{{ !performanceList || performanceList.length === 0 }}" class="empty">
|
||||
<image class="empty-img" src="/assets/empty-list.png" mode="aspectFit" />
|
||||
<text class="empty-text">暂无数据</text>
|
||||
</view>
|
||||
|
||||
<!-- 列表卡片 -->
|
||||
<view wx:for="{{ performanceList }}"
|
||||
wx:for-item="item"
|
||||
wx:for-index="index"
|
||||
wx:key="item.id"
|
||||
class="card perf-card">
|
||||
|
||||
<!-- 顶部:编号 + 主管 + 跳转员工绩效 -->
|
||||
<view class="topline">
|
||||
<view class="id-and-name">
|
||||
<text class="no">编号:{{ index + 1 }}</text>
|
||||
<text class="name">主管:{{ item.nickName }}</text>
|
||||
</view>
|
||||
<view class="link-btn" bind:tap="changeStaff" data-id="{{ item.userId }}">
|
||||
<text class="link-text">员工绩效排名 >></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 + 复制 -->
|
||||
<view class="row">
|
||||
<text class="row-key">手机号</text>
|
||||
<view class="row-val">
|
||||
<text class="mono">{{ item.phoneNumber }}</text>
|
||||
<text class="copy" bindtap="onCopyPhone" data-phone="{{ item.phoneNumber }}">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 员工数 + 抽成比例(徽标 chip) -->
|
||||
<view class="chips">
|
||||
<view class="chip">员工数:{{ item.empCount }}</view>
|
||||
<view class="chip">比例:{{ item.ratePercent }}%</view>
|
||||
</view>
|
||||
|
||||
<!-- 业绩九宫格 -->
|
||||
<view class="grid">
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">下单量</text>
|
||||
<text class="gi-value">{{ item.orderCount }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">总订单</text>
|
||||
<text class="gi-value">¥{{ item.totalAmount }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">净成交</text>
|
||||
<text class="gi-value">¥{{ item.netAmount }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">待释放</text>
|
||||
<text class="gi-value">¥{{ item.toRelease }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">可结算</text>
|
||||
<text class="gi-value">{{ item.toSettle }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">已结算</text>
|
||||
<text class="gi-value">¥{{ item.settled }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">推广数</text>
|
||||
<text class="gi-value">{{ item.promoCount }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">退款</text>
|
||||
<text class="gi-value">¥{{ item.refunded }}</text>
|
||||
</view>
|
||||
<view class="grid-item">
|
||||
<text class="gi-label">已回退</text>
|
||||
<text class="gi-value">¥0</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
@ -0,0 +1,235 @@
|
||||
/* ===== 页面与滚动 ===== */
|
||||
.page {
|
||||
background: #fefbf6;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
padding: 24rpx 24rpx 0;
|
||||
}
|
||||
.title {
|
||||
color: #ff8a00; /* 主标题亮橙 */
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ===== 卡片通用 ===== */
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border-radius: 18rpx;
|
||||
padding: 24rpx;
|
||||
border: 2rpx solid #ffeaa7; /* 浅橙描边 */
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.05);
|
||||
}
|
||||
.card + .card { margin-top: 20rpx; }
|
||||
|
||||
/* ===== 表单 ===== */
|
||||
.form-card .field + .field { margin-top: 20rpx; }
|
||||
|
||||
.field-label {
|
||||
font-size: 28rpx;
|
||||
color: #555555;
|
||||
margin-bottom: 12rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.input-box {
|
||||
background: #ffffff;
|
||||
border: 2rpx solid #ffeaa7;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 84rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
|
||||
.ph {
|
||||
color: #b8b8b8;
|
||||
}
|
||||
|
||||
/* 按钮 */
|
||||
.btn {
|
||||
height: 88rpx;
|
||||
border-radius: 999rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(180deg, #ffa400 0%, #ff8a00 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 6rpx 14rpx rgba(255, 138, 0, 0.30);
|
||||
}
|
||||
|
||||
/* ===== 空状态 ===== */
|
||||
.empty {
|
||||
padding: 120rpx 0 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #999999;
|
||||
}
|
||||
.empty-img { width: 300rpx; height: 300rpx; margin-bottom: 16rpx; }
|
||||
.empty-text { font-size: 26rpx; }
|
||||
|
||||
/* ===== 业绩卡片 ===== */
|
||||
.topline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.id-and-name {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 16rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.no {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
color: #1f1f1f;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.link-btn {
|
||||
height: 56rpx;
|
||||
padding: 0 18rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #fff6e6;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1rpx solid #ffd6b3;
|
||||
}
|
||||
|
||||
.link-text {
|
||||
font-size: 24rpx;
|
||||
color: #ff8a00;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 行:键值对 */
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12rpx 0;
|
||||
border-top: 1rpx dashed #f0f0f0;
|
||||
}
|
||||
|
||||
.row-key {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.row-val {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-size: 28rpx;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
|
||||
.copy {
|
||||
font-size: 24rpx;
|
||||
color: #ff8a00;
|
||||
padding: 8rpx 14rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #fff4f2;
|
||||
border: 1rpx solid #ffd6cc;
|
||||
}
|
||||
|
||||
/* 徽标 chips */
|
||||
.chips {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
flex-wrap: wrap;
|
||||
margin: 12rpx 0 4rpx;
|
||||
}
|
||||
|
||||
.chip {
|
||||
padding: 10rpx 16rpx;
|
||||
background: #f7f9fc;
|
||||
color: #3d4f6e;
|
||||
border: 1rpx solid #e6edf7;
|
||||
border-radius: 12rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* 九宫格:3 列自适应 */
|
||||
.grid {
|
||||
margin-top: 8rpx;
|
||||
margin-left: -10rpx;
|
||||
margin-right: -10rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
width: 33.3333%;
|
||||
padding: 14rpx 10rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.gi-label {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.gi-value {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
|
||||
/* 金额类,用主题橙强调 */
|
||||
.grid-item:nth-child(2) .gi-value,
|
||||
.grid-item:nth-child(3) .gi-value,
|
||||
.grid-item:nth-child(4) .gi-value,
|
||||
.grid-item:nth-child(6) .gi-value,
|
||||
.grid-item:nth-child(8) .gi-value,
|
||||
.grid-item:nth-child(9) .gi-value {
|
||||
color: #ff8a00;
|
||||
}
|
||||
|
||||
/* 小屏两列适配 */
|
||||
@media (max-width: 360px) {
|
||||
.grid-item { width: 50%; }
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
const { notLogin } = require('../../../utils/util')
|
||||
|
||||
// pages/dashboardModule/userOrderPerformance/userOrderPerformance.js
|
||||
Page({
|
||||
data: {
|
||||
orderNumber: '', // 双向绑定的输入框内容
|
||||
staffUserId: 0, // 后期改为动态注入
|
||||
OrderItems: [] // 接口返回的订单列表
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
console.log('options-->',options);
|
||||
this.setData({
|
||||
staffUserId: options.userId
|
||||
})
|
||||
this.searchOrderByStaffId()
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.searchOrderByStaffId()
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
// 输入框内容变化
|
||||
onOrderNumberInput(e) {
|
||||
this.setData({
|
||||
orderNumber: e.detail.value.trim()
|
||||
});
|
||||
},
|
||||
|
||||
// 点击搜索按钮
|
||||
searchOrder() {
|
||||
const { orderNumber, staffUserId } = this.data;
|
||||
|
||||
// 简单校验:非空
|
||||
// if (!orderNumber) {
|
||||
// return wx.showToast({
|
||||
// title: '请输入订单号',
|
||||
// icon: 'none'
|
||||
// });
|
||||
// }
|
||||
|
||||
// 发起 POST 请求
|
||||
wx.request({
|
||||
url: baseUrl + '/perform/query/user',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: {
|
||||
orderNumber,
|
||||
staffUserId
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data.code === 1) {
|
||||
// 更新列表
|
||||
this.setData({
|
||||
OrderItems: res.data.data
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: res.data.message || '未找到订单',
|
||||
icon: 'none'
|
||||
});
|
||||
this.setData({ OrderItems: [] });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '请求失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 根据上级订单搜索
|
||||
searchOrderByStaffId() {
|
||||
const { staffUserId } = this.data;
|
||||
|
||||
// 发起 POST 请求
|
||||
wx.request({
|
||||
url: baseUrl + '/perform/query/user',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: {
|
||||
staffUserId
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data.code === 1) {
|
||||
// 更新列表
|
||||
this.setData({
|
||||
OrderItems: res.data.data
|
||||
});
|
||||
} else {
|
||||
this.setData({ OrderItems: [] });
|
||||
notLogin(res.data.message)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '请求失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<!-- pages/dashboardModule/userOrderPerformance/userOrderPerformance.wxml -->
|
||||
<view class="page">
|
||||
<!-- 标题 -->
|
||||
<view class="page-title">
|
||||
<text class="title">客户订单明细</text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="content no-scrollbar">
|
||||
<!-- 搜索表单 -->
|
||||
<view class="card form-card">
|
||||
<view class="field">
|
||||
<text class="field-label">订单号</text>
|
||||
<view class="input-box">
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入订单号"
|
||||
placeholder-class="ph"
|
||||
value="{{ orderNumber }}"
|
||||
type="number"
|
||||
bindinput="onOrderNumberInput"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="btn btn-primary" bindtap="searchOrder">搜索</view>
|
||||
</view>
|
||||
|
||||
<!-- 结果列表 -->
|
||||
<view class="result-wrap">
|
||||
<!-- 有数据 -->
|
||||
<block wx:if="{{ OrderItems.length }}">
|
||||
<view
|
||||
wx:for="{{ OrderItems }}"
|
||||
wx:for-item="item"
|
||||
wx:for-index="index"
|
||||
wx:key="id"
|
||||
class="card order-card"
|
||||
>
|
||||
<!-- 顶部:订单号 + 状态徽标 -->
|
||||
<view class="topline">
|
||||
<view class="row-left">
|
||||
<text class="label">订单号</text>
|
||||
<text class="mono">{{ item.orderNumber }}</text>
|
||||
</view>
|
||||
<view class="badge {{ item.orderStatus === '待支付' ? 'badge-pending' : (item.orderStatus === '已支付' || item.orderStatus === '交易成功' ? 'badge-success' : 'badge-default') }}">
|
||||
<text class="badge-text">{{ item.orderStatus }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 键值对信息 -->
|
||||
<view class="kv">
|
||||
<text class="kv-key">用户</text>
|
||||
<text class="kv-val">{{ item.nickName }}</text>
|
||||
</view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">手机号</text>
|
||||
<text class="kv-val">{{ item.phoneNumber }}</text>
|
||||
</view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">金额</text>
|
||||
<text class="kv-val money">¥{{ item.totalAmount }}</text>
|
||||
</view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">抽成</text>
|
||||
<text class="kv-val">主管:{{ item.firstRate * 100 }}%,员工:{{ item.secondRate * 100 }}%</text>
|
||||
</view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">奖励</text>
|
||||
<text class="kv-val">主管:¥{{ item.firstReward }},员工:¥{{ item.secondReward }}</text>
|
||||
</view>
|
||||
|
||||
<view class="kv">
|
||||
<text class="kv-key">提成状态</text>
|
||||
<text class="kv-val">{{ item.commissionStatus }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 无数据 -->
|
||||
<block wx:else>
|
||||
<view class="empty">
|
||||
<image class="empty-img" src="/assets/empty-list.png" mode="aspectFit" />
|
||||
<text class="empty-text">暂无数据</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
@ -0,0 +1,133 @@
|
||||
/* ===== 页面与滚动 ===== */
|
||||
.page {
|
||||
background: #fefbf6; /* 与你项目的暖米黄保持一致 */
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.page-title { padding: 24rpx 24rpx 0; }
|
||||
.title {
|
||||
color: #ff8a00; /* 亮橙主色 */
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.no-scrollbar::-webkit-scrollbar { width: 0; height: 0; display: none; }
|
||||
|
||||
/* ===== 卡片 ===== */
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border-radius: 18rpx;
|
||||
padding: 24rpx;
|
||||
border: 2rpx solid #ffeaa7; /* 浅橙描边,延续你原风格 */
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.05);
|
||||
}
|
||||
.card + .card { margin-top: 20rpx; }
|
||||
|
||||
/* ===== 表单 ===== */
|
||||
.form-card .field + .field { margin-top: 20rpx; }
|
||||
.field-label {
|
||||
font-size: 28rpx;
|
||||
color: #555555;
|
||||
margin-bottom: 12rpx;
|
||||
display: block;
|
||||
}
|
||||
.input-box {
|
||||
height: 84rpx;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid #ffeaa7;
|
||||
background: #ffffff;
|
||||
padding: 0 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
.ph { color: #b8b8b8; }
|
||||
|
||||
.btn {
|
||||
height: 88rpx;
|
||||
border-radius: 999rpx;
|
||||
margin-top: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.btn-primary {
|
||||
background: linear-gradient(180deg, #ffa400 0%, #ff8a00 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 6rpx 14rpx rgba(255,138,0,0.30);
|
||||
}
|
||||
|
||||
/* ===== 列表容器 ===== */
|
||||
.result-wrap { margin-top: 20rpx; }
|
||||
|
||||
/* 顶部行:订单号 + 状态徽标 */
|
||||
.topline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
.row-left {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 12rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.label { font-size: 26rpx; color: #666666; }
|
||||
.mono { font-size: 28rpx; color: #1f1f1f; }
|
||||
|
||||
.badge {
|
||||
height: 40rpx;
|
||||
padding: 0 16rpx;
|
||||
border-radius: 999rpx;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.badge-text { font-size: 22rpx; font-weight: 600; }
|
||||
.badge-pending{ background: #fff6e6; color: #ff8d1a; border: 1rpx solid #ffd6b3; }
|
||||
.badge-success{ background: #e9fbef; color: #12b05b; border: 1rpx solid #b9f0cf; }
|
||||
.badge-default{ background: #f0f0f0; color: #666666; border: 1rpx solid #e6e6e6; }
|
||||
|
||||
/* 键值行 */
|
||||
.kv {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12rpx 0;
|
||||
border-top: 1rpx dashed #f0f0f0;
|
||||
}
|
||||
.kv:first-of-type { border-top: 0; }
|
||||
.kv-key { font-size: 26rpx; color: #666666; }
|
||||
.kv-val {
|
||||
font-size: 28rpx;
|
||||
color: #1f1f1f;
|
||||
text-align: right;
|
||||
max-width: 70%;
|
||||
word-break: break-all;
|
||||
}
|
||||
.money { color: #ff8a00; font-weight: 700; }
|
||||
|
||||
/* 空状态 */
|
||||
.empty {
|
||||
padding: 120rpx 0 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #999999;
|
||||
}
|
||||
.empty-img { width: 300rpx; height: 300rpx; margin-bottom: 16rpx; }
|
||||
.empty-text { font-size: 26rpx; }
|
66
pages/loginModule/agreement/agreement.js
Normal file
@ -0,0 +1,66 @@
|
||||
// pages/loginModule/agreement/agreement.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
3
pages/loginModule/agreement/agreement.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
175
pages/loginModule/agreement/agreement.wxml
Normal file
@ -0,0 +1,175 @@
|
||||
<view class="myOne">
|
||||
<view class="my-div">
|
||||
<text class="yhxy">用户协议</text>
|
||||
|
||||
<view>
|
||||
一、总则
|
||||
<view>
|
||||
1、用户在注册及使用前请认真阅读本协议,确保充分理解本协议中所有条款。除非您接受本协议所有条款,否则您无权注册、登录或使用本协议所涉服务。您的注册、登录、使用等行为将视为无条件接受本协议所有条款的约束。
|
||||
2、除非另有明确规定,本产品所推出的新功能、新服务,均无条件的使用本协议。
|
||||
3、我公司保留在任何时候修改本协议条款的权利,且无需另行通知。在我公司修改协议条款后,如果您不接受修改后的条款,请立即停止使用本产品提供的服务,继续使用本产品提供的服务将被视为接受修改后的协议。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view>
|
||||
二、用户注册
|
||||
<view>
|
||||
1、用户应当同意本协议的全部条款并按照页面提示完成全部注册程序(未成年人应与法定监护人共同完成)。用户在注册过程中点击“下一步”按钮即表示完全接受本协议全部条款。
|
||||
2、用户在使用本服务前需要注册一个本产品账号。本产品账号应当使用手机号码绑定注册,请用户使用尚未与本产品账号绑定且未被本产品根据本协议封禁的手机号码注册账号。本产品可以根据用户需求或产品需求对账号注册和绑定的方式进行更改,而无须事先通知用户。
|
||||
3、用户在使用本产品服务过程中应保证各项服务业务所需信息的真实性,如果因信息不真实而引起的问题,以及问题发生所带来的后果,本公司不负任何责任。
|
||||
4、在用户注册及使用本产品时,要搜集能识别用户身份的个人信息以便系统可以在必要时联系用户,或为用户提供更好的使用体验。系统搜集的信息包括但不限于用户的性别、年龄、出生日期、所在城市;系统同意对这些信息的使用将受限于用户个人隐私信息保护的约束。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
三、服务内容
|
||||
<view>
|
||||
1、本服务的具体内容由本产品根据实际情况提供,包括但不限于用户使用本产品等。本产品可以对提供的服务予以变更,且本产品提供的服务内容可能随时变更,用户将会收到关于服务变更的通知。
|
||||
2、除非本协议另有其他明示规定,本公司所推出的新产品、新功能、新服务,均受到本协议条款之规范。
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
四、服务变更、中断或终止
|
||||
<view>
|
||||
1、鉴于网络服务的特殊性(包括但不限于服务器的稳定性问题、恶意的网络攻击等行为的存在及其他无法控制的情形),用户同意我公司有权随时中断或终止部分或全部的服务。
|
||||
2、我公司需要定期或不定期地对提供服务的系统或相关设备进行检修或维护,如因此类情况而造成服务在合理时间内的中断,我公司无需为此承担任何责任。
|
||||
3、如发生下列任何一种情形,我公司有权随时变更、中断或终止向用户提供本协议项下的服务而无需对用户或任何第三方承担任何责任:
|
||||
(1)根据法律规定用户应提交真实信息,而用户提供的个人资料不真实、或与注册时信息不一致又未能提供合理证明;
|
||||
(2)用户违反相关法律法规或本协议的约定;
|
||||
(3)按照法律规定或有权机关的要求;
|
||||
(4)出于安全的原因或其他必要的情形。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
五、用户个人隐私信息保护
|
||||
<view>
|
||||
1、依据法律的规定,我们将在特定情形下收集、使用和披露您的个人信息。以下条款描述了我们如何收集、使用和披露您的个人信息。
|
||||
2、信息收集
|
||||
(1)用户提供
|
||||
我们会对您直接提供的信息进行保存。比如:我们会记录您的注册信息、寻求客服或者其他和我们沟通的记录。记录信息的种类包括:头像、昵称、性别、出生日期、所在地区以及其他您选择提供的信息。我们收集、使用和披露个人信息是为了通过创建账户、识别用户、回应查询和邮件等方式来为您提供服务。
|
||||
当你接触或者使用我们的服务时,我们将自动收集您的信息包括:
|
||||
Log信息(我们记录所有您使用服务时的log信息,包括浏览器信息、使用时间、浏览的网页、IP地址及来源)。我们使用多种技术记录信息,包括但不限于:向您的移动设备种Cookies。Cookies是一些存在您的硬件上的小数据包,用以帮助我们提高服务的质量及您的使用体验,了解在哪些区域和功能上受欢迎,以及统计流量等。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
3、信息使用
|
||||
<view>
|
||||
(1)除本隐私政策未载明或本隐私政策的更新未能首先通知您的情况下,您的个人信息将不会用于其他目的。
|
||||
(2)匿名汇总统计数据不是我公司所定义的个人用户信息,我们将为多种目的,包括但不限于分析和使用模式的报告等,来保存和使用此类信息。我公司保留以任何目的或单方面许可第三方使用和披露匿名汇总统计数据的权利。
|
||||
(3)您在本产品中上传的信息,有可能会损坏您或他人的合法权益,您必须充分意识此类风险的存在。您明确同意,自行承担因上传信息所存在的一切风险及后果,我公司无需承担任何责任。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
4、法定披露
|
||||
<view>
|
||||
虽然我们会尽最大努力保护用户隐私,但当我们有理由相信只有公开个人信息才能遵循现行司法程序、 法院指令或其他法律程序或者保护我公司、我公司用户或第三方的权利、财产或安全时,我们可能披露个人信息。
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
5、信息安全
|
||||
<view>
|
||||
|
||||
我们会采取合理的实际及电子手段以及规程保障措施来保护您的个人信息。 虽然通过因特网信息传输数据并非100% 安全,但我们已经采取并将继续采取商业范畴内合理的努力来确保您的个人信息得到保护。
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view>
|
||||
6、未成年人隐私保护
|
||||
<view>
|
||||
我公司重视对未成年人个人隐私信息的保护。我公司将依赖用户提供的个人信息判断用户是否为未成年人。任何18岁以下的未成年人注册账号或使用本服务应事先取得家长或其法定监护人(以下简称“监护人”)的书面同意。除根据法律法规的规定及有权机关的指示披露外,我公司不会使用向任何第三方透露未成年人的个人隐私信息。
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
<view>
|
||||
六、内容规范
|
||||
<view>
|
||||
1、本项规范所述内容是指用户使用本服务过程中所制作、上载、复制、发布、传播的任何内容,包括但不限于账号头像、名称、个性签名等注册信息及认证资料,或文字、语音、图片、图文等发送、回复消息和相关链接页面,以及其他使用本产品账号或本服务所产生的内容。
|
||||
2、用户承诺使用本产品的服务时必须符合中华人民共和国有关法律法规,不得利用本产品的服务制作、上载、复制、发布、传播以下内容:
|
||||
<view>
|
||||
(1)反对宪法所确定的基本原则的;(2)危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的; (3)损害国家荣誉和利益的;(4)煽动民族仇恨、民族歧视,破坏民族团结的;(5)破坏国家宗教政策,宣扬邪教和封建迷信的;(6)散布谣言,扰乱社会秩序,破坏社会稳定的;(7)散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的;(8)侮辱或者诽谤他人,侵害他人合法权益的;(9)含有法律、行政法规禁止的其他内容的。
|
||||
</view>
|
||||
3、用户不得利用本产品账号或本服务制作、上载、复制、发布、传播下干扰本产品正常运营,以及侵犯其他用户或第三方合作权益的内容:
|
||||
<view>
|
||||
(1)含有任何性暗示的;
|
||||
(2)含有辱骂、恐吓、威胁内容的;
|
||||
(3)含有骚扰、垃圾广告、恶意信息、诱骗信息的;
|
||||
(4)涉及他人隐私、个人信息或资料的;
|
||||
(5)含有其他干扰本服务正常运营和侵犯其他用户或第三方合法权益的。
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view>
|
||||
七、使用规则
|
||||
<view>
|
||||
1、用户在本服务中或通过本服务所传送、发布的任何内容并不反映或代表,也不得被视为反映或代表我公司的观点、立场或政策,我公司对此不承担任何责任。
|
||||
|
||||
2、用户在使用本产品时,必须遵守中华人民共和国相关法律法规的规定,同意将不会利用本产品进行任何违法或不正当的活动,包括但不限于下列行为:
|
||||
(1)干扰或破坏有关服务,或与有关服务连接的任何服务器或网络,或与有关服务相关的任何政策、要求或规定;
|
||||
(2)采集并存储涉及任何其他用户的个人信息,以用于任何被禁止的活动;
|
||||
(3)故意或非故意违反任何相关的中国法律、法规、规章、条例等其他具有法律效力的规范。
|
||||
3、用户须对利用本产品账号或本服务传送信息的真实性、合法性、无害性、准确性、有效性等全权负责,与用户所传播信息相关的任何法律责任由用户自行承担,与我公司无关。如因此给我公司或第三方造成损害的,用户应当依法予以赔偿。
|
||||
4、本产品提供的服务中可能包括广告,用户同意在使用过程中显示本产品和第三方供应商、合作伙伴提供的广告。除法律法规明确规定外,用户应自行对该广告信息进行的交易负责,对用户因该广告信息进行的交易或前述广告商提供的内容或遭受的损失或损害,我公司不承担任何责任。
|
||||
5、用户为使用本产品,须自行配备进入国际互联网所必需的设备,包括电脑、手机及其他与接入国际互联网有关的装置,并自行支付与此服务有关的费用。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
八、免责声明
|
||||
<view>
|
||||
1、对于经由本产品服务而传送的内容,我公司不保证前述内容的正确性、完整性或品质。用户在接受有关服务时,有可能会接触到令人不快、不适当或令人厌恶的内容。在任何情况下,我公司均不对任何内容负责,包括但不限于任何内容发生任何错误或纰漏以及衍生的任何损失或损害。用户使用上述内容,应自行承担风险。
|
||||
|
||||
2、用户明确同意其使用本产品所存在的风险及其后果将完全由其自己承担,我公司对用户不承担任何责任。如因用户违反有关法律、法规或本协议项下的任何条款而给任何其他第三人造成损失,用户同意承担由此造成的损害赔偿责任。
|
||||
3、我公司尊重并保护用户的个人隐私权。但因恶意的网络攻击等行为及其他无法控制的情形,导致用户隐私信息泄露的,用户同意我公司不承担任何责任。
|
||||
4、对于因电信系统或互联网网络故障、计算机故障、计算机系统问题或其它任何不可抗力原因而产生损失,我公司不承担任何责任,但将尽力减少因此给用户造成的损失和影响。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view>
|
||||
九、知识产权声明
|
||||
<view>
|
||||
1、本产品服务中包含的任何文字、图表、音频、视频和软件(包括但不限于软件中包含的图表、动画、音频、视频、界面实际、数据和程序、代码、文档)等信息或材料均受著作权法、商标法和其它法律法规保护,未经相关权利人书面同意,用户不得以任何方式使用该信息或材料。
|
||||
2、本协议未授予用户使用本产品任何商标、服务标记、标识、域名和其他显著品牌特征的权利,任何人不得擅自(包括但不限于:以非法的方式复制、传播、展示、镜像、上载、下载)使用,否则我公司将依法追究法律责任。
|
||||
3、除本协议明确允许以外,用户不得以任何形式或任何方式对本产品部分或全部内容进行修改、出租、租赁、出借、出售、分发、复制、创作衍生品或用于任何商业用途。
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
<view>
|
||||
十、法律适用
|
||||
<view>
|
||||
1、本协议的订立、执行和解释及争议的解决均应适用中国法律并受中国法院管辖。如服务条款任何一部分与中华人民共和国法律相抵触,则该部分条款应按法律规定重新解释,部分条款无效或重新解释不影响其余条款法律效力。
|
||||
2、用户和我公司一致同意本协议。在执行本协议过程中如发生纠纷,双方应友好协商解决;协商不成时,任何一方可直接向所在地的人民法院提起诉讼。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view>
|
||||
十一、其他规定
|
||||
<view>
|
||||
1、本协议中的标题仅为方便而设,在解释本协议时应被忽略。
|
||||
2、本协议及其修改权、最终解释权归我公司所有。
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
</view>
|
17
pages/loginModule/agreement/agreement.wxss
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
.myOne{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-bottom: 60rpx;
|
||||
}
|
||||
.my-div{
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
}
|
||||
.yhxy{
|
||||
justify-content: center;
|
||||
color: black;
|
||||
font-size: 40rpx;
|
||||
font-weight: 600;
|
||||
}
|
224
pages/loginModule/employeeAccountApply/employeeAccountApply.js
Normal file
@ -0,0 +1,224 @@
|
||||
const { baseUrl } = require('../../../request');
|
||||
const { validate } = require('../../../utils/validate');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
name: '',
|
||||
phone: '',
|
||||
code: '', // 验证码
|
||||
idcard: '', // 身份证号
|
||||
codeSent: false,
|
||||
countdown: 0, // 剩余秒数
|
||||
codeButtonText: '获取验证码',
|
||||
_timer: null,
|
||||
isUploading: false,
|
||||
resumeUploaded: false,
|
||||
resumeFilePath: '',
|
||||
fileCode: '', // 上传文件后端返回的码
|
||||
credential: '', // 用户申请后的唯一凭证,用于查询用户是否审核通过
|
||||
},
|
||||
|
||||
onInput(e) {
|
||||
const field = e.currentTarget.dataset.field;
|
||||
this.setData({
|
||||
[field]: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
// 获取验证码(仅校验手机号)
|
||||
getSmsCode() {
|
||||
const { phone } = this.data;
|
||||
|
||||
// 1. 非空校验
|
||||
if (!validate(this.data, { phone: '请输入手机号' })) {
|
||||
return;
|
||||
}
|
||||
// 2. 格式校验
|
||||
if (!/^1\d{10}$/.test(phone)) {
|
||||
return wx.showToast({ title: '手机号格式不正确', icon: 'none' });
|
||||
}
|
||||
|
||||
// 3. 发送验证码请求
|
||||
wx.request({
|
||||
url: baseUrl + '/userInfo/code/register',
|
||||
method: 'POST',
|
||||
data: {
|
||||
phoneNumber: phone,
|
||||
userRole: 'staff'
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('验证码发送--->',res.data);
|
||||
if (res.data.code === 1) {
|
||||
wx.showToast({ title: '验证码已发送', icon: 'none' });
|
||||
this._startCountdown(60);
|
||||
} else {
|
||||
wx.showToast({ title: res.data.message, icon: 'none' });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '发送失败,请重试', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 开始倒计时
|
||||
_startCountdown(seconds) {
|
||||
this.setData({
|
||||
countdown: seconds,
|
||||
codeButtonText: `${seconds}s后重试`
|
||||
});
|
||||
// 如果已有定时器,不重复创建
|
||||
if (this.data._timer) return;
|
||||
this.data._timer = setInterval(() => {
|
||||
const cd = this.data.countdown - 1;
|
||||
if (cd <= 0) {
|
||||
this._clearTimer();
|
||||
this.setData({
|
||||
countdown: 0,
|
||||
codeButtonText: '获取验证码'
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
countdown: cd,
|
||||
codeButtonText: `${cd}s后重试`
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
// 清除倒计时定时器
|
||||
_clearTimer() {
|
||||
if (this.data._timer) {
|
||||
clearInterval(this.data._timer);
|
||||
this.data._timer = null;
|
||||
}
|
||||
},
|
||||
|
||||
// 选择并上传简历
|
||||
chooseResume() {
|
||||
if (this.data.resumeUploaded) return;
|
||||
wx.chooseMessageFile({
|
||||
count: 1,
|
||||
type: 'file',
|
||||
success: res => {
|
||||
const file = res.tempFiles[0];
|
||||
this.uploadResume(file);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 上传简历
|
||||
uploadResume(file) {
|
||||
this.setData({ isUploading: true });
|
||||
wx.uploadFile({
|
||||
url: baseUrl + '/file/upload',
|
||||
method: 'POST',
|
||||
name: 'file',
|
||||
header : {
|
||||
Authorization: wx.getStorageSync('token'),
|
||||
},
|
||||
formData: {
|
||||
biz: 'default', // 传 biz 文本字段
|
||||
},
|
||||
filePath: file.path,
|
||||
success: res => {
|
||||
console.log('简历上传后端返回--->',JSON.parse(res.data));
|
||||
const data = JSON.parse(res.data);
|
||||
console.log('后端返回文件码--->',data.data);
|
||||
if (data.code === 1) {
|
||||
wx.showToast({ title: '上传成功', icon: 'success' });
|
||||
this.setData({
|
||||
isUploading: false,
|
||||
resumeUploaded: true,
|
||||
resumeFilePath: file.path,
|
||||
fileCode: data.data
|
||||
});
|
||||
} else {
|
||||
wx.showToast({ title: data.message || '上传失败', icon: 'none' });
|
||||
this.setData({ isUploading: false });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '上传失败,请重试', icon: 'none' });
|
||||
this.setData({ isUploading: false });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 提交表单
|
||||
handleSubmit() {
|
||||
const { name, phone, code, idcard, fileCode } = this.data;
|
||||
|
||||
// 校验用户是否填写所有必要信息
|
||||
if (!name || !phone || !code || !idcard || !fileCode) {
|
||||
wx.showToast({ title: '请填写所有信息', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 姓名只能中文或英文
|
||||
if (!/^[\u4e00-\u9fa5A-Za-z]+$/.test(name)) {
|
||||
wx.showToast({ title: '姓名只能为中英文', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 校验身份证号
|
||||
const idCardReg = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
|
||||
if (!idCardReg.test(idcard)) {
|
||||
wx.showToast({
|
||||
title: '身份证号格式不正确',
|
||||
icon: 'none'
|
||||
})
|
||||
return ;
|
||||
}
|
||||
|
||||
// 提交表单数据到后端
|
||||
wx.request({
|
||||
url: baseUrl + '/advancementApply/add',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: {
|
||||
name: name,
|
||||
phone: phone,
|
||||
verificationCode: code,
|
||||
idCard: idcard,
|
||||
resume: fileCode
|
||||
},
|
||||
success: res => {
|
||||
console.log('后端返回的申请---->', res);
|
||||
if (res.data.code === 1) {
|
||||
wx.showToast({ title: '提交成功', icon: 'success' });
|
||||
|
||||
// 清空表单内容
|
||||
this.setData({
|
||||
name: '',
|
||||
phone: '',
|
||||
code: '',
|
||||
idcard: '',
|
||||
fileCode: '',
|
||||
resumeUploaded: false, // 重置简历上传状态
|
||||
resumeFilePath: '', // 清空简历文件路径
|
||||
credential: '' // 清空凭证
|
||||
});
|
||||
} else {
|
||||
wx.showToast({ title: res.data.message, icon: 'none' });
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转申请须知
|
||||
gotoNotice() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/loginModule/employeeAccountNotice/employeeAccountNotice',
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转我的申请记录
|
||||
gotoQuery() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/loginModule/employeeApplyQuery/employeeApplyQuery',
|
||||
})
|
||||
},
|
||||
});
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
108
pages/loginModule/employeeAccountApply/employeeAccountApply.wxml
Normal file
@ -0,0 +1,108 @@
|
||||
<view class="page">
|
||||
|
||||
<!-- 遮罩层(上传时显示) -->
|
||||
<view wx:if="{{isUploading}}" class="mask">
|
||||
<text class="loading-text">上传中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 顶部 Logo / 标题 -->
|
||||
<image class="logo" src="/static/logo.jpg" mode="aspectFit" />
|
||||
<text class="page-title">员工申请 - 丁香校园</text>
|
||||
|
||||
<!-- 主卡片 -->
|
||||
<view class="card">
|
||||
|
||||
<!-- 标题 + 须知入口 -->
|
||||
<view class="card-head">
|
||||
<text class="card-title">员工账号申请</text>
|
||||
<view class="head-link" bind:tap="gotoNotice">
|
||||
<text class="head-link-text">员工账号申请须知</text>
|
||||
<image class="head-link-icon" src="./images/right.png" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单 -->
|
||||
<view class="form">
|
||||
|
||||
<!-- 姓名 -->
|
||||
<view class="field">
|
||||
<input
|
||||
class="field-input"
|
||||
placeholder="请输入姓名"
|
||||
placeholder-class="ph"
|
||||
maxlength="8"
|
||||
bindinput="onInput"
|
||||
data-field="name"
|
||||
value="{{name}}"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 -->
|
||||
<view class="field">
|
||||
<input
|
||||
class="field-input"
|
||||
placeholder="请输入手机号"
|
||||
placeholder-class="ph"
|
||||
maxlength="11"
|
||||
type="number"
|
||||
bindinput="onInput"
|
||||
data-field="phone"
|
||||
value="{{phone}}"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 验证码 + 发送 -->
|
||||
<view class="field field-row">
|
||||
<input
|
||||
class="field-input flex-1"
|
||||
placeholder="请输入验证码"
|
||||
placeholder-class="ph"
|
||||
type="number"
|
||||
maxlength="6"
|
||||
bindinput="onInput"
|
||||
data-field="code"
|
||||
value="{{code}}"
|
||||
/>
|
||||
<view
|
||||
class="code-btn"
|
||||
bindtap="getSmsCode"
|
||||
>
|
||||
<text class="code-btn-text">{{ codeButtonText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 身份证号 -->
|
||||
<view class="field">
|
||||
<input
|
||||
class="field-input"
|
||||
placeholder="请输入身份证号"
|
||||
placeholder-class="ph"
|
||||
type="idcard"
|
||||
maxlength="18"
|
||||
bindinput="onInput"
|
||||
data-field="idcard"
|
||||
value="{{idcard}}"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 上传简历 -->
|
||||
<view class="upload-box" bindtap="chooseResume">
|
||||
<image class="upload-icon" src="./images/resume.png" mode="aspectFit" />
|
||||
<text class="{{ resumeUploaded ? 'upload-success-text' : 'upload-tip' }}">{{ resumeUploaded ? '简历上传成功!' : '点击上传简历' }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view class="btn-primary" bindtap="handleSubmit">
|
||||
<text class="btn-primary-text">提交申请</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 我的申请记录 -->
|
||||
<view class="record" bind:tap="gotoQuery">
|
||||
<text class="record-text">我的申请记录</text>
|
||||
<image class="record-icon" src="./images/right.png" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
208
pages/loginModule/employeeAccountApply/employeeAccountApply.wxss
Normal file
@ -0,0 +1,208 @@
|
||||
/* ===== 页面与顶区 ===== */
|
||||
.page {
|
||||
box-sizing: border-box;
|
||||
min-height: 100vh;
|
||||
padding: 56rpx 32rpx 40rpx;
|
||||
background-image: linear-gradient(180deg, #ffe3c4 0%, #fff 38%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin-top: 12rpx;
|
||||
font-size: 34rpx;
|
||||
color: #1c2023;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ===== 遮罩(上传中) ===== */
|
||||
.mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.35);
|
||||
backdrop-filter: blur(2rpx);
|
||||
z-index: 99;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.loading-text {
|
||||
padding: 20rpx 28rpx;
|
||||
background: #000000cc;
|
||||
color: #fff;
|
||||
border-radius: 16rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* ===== 主卡片 ===== */
|
||||
.card {
|
||||
width: 100%;
|
||||
margin-top: 24rpx;
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 12rpx 36rpx rgba(0,0,0,0.08);
|
||||
padding: 24rpx 24rpx 16rpx;
|
||||
}
|
||||
|
||||
.card-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 12rpx;
|
||||
border-bottom: 1rpx solid #f1f1f1;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #1c2023;
|
||||
}
|
||||
|
||||
/* 须知入口 */
|
||||
.head-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
.head-link-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
.head-link-text {
|
||||
font-size: 26rpx;
|
||||
color: #ff8d1a;
|
||||
}
|
||||
|
||||
/* ===== 表单 ===== */
|
||||
.form { padding-top: 16rpx; }
|
||||
|
||||
.field {
|
||||
background: #fff;
|
||||
border: 1rpx solid #e9e9ec;
|
||||
border-radius: 16rpx;
|
||||
padding: 18rpx 22rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0,0,0,0.04);
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
.field:focus-within {
|
||||
border-color: #ff8d1a;
|
||||
box-shadow: 0 10rpx 24rpx rgba(255,141,26,0.14);
|
||||
}
|
||||
|
||||
.field-input {
|
||||
width: 100%;
|
||||
font-size: 30rpx;
|
||||
color: #1c2023;
|
||||
line-height: 44rpx;
|
||||
}
|
||||
.ph { color: #9aa0a6; }
|
||||
|
||||
/* 验证码行 */
|
||||
.field-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding-right: 16rpx;
|
||||
}
|
||||
.flex-1 { flex: 1; }
|
||||
|
||||
.code-btn {
|
||||
height: 44rpx;
|
||||
padding: 0 22rpx;
|
||||
background: #ff8d1a;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 8rpx 18rpx rgba(255,141,26,0.25);
|
||||
transition: transform .08s ease-in-out, opacity .2s;
|
||||
}
|
||||
.code-btn:active { transform: scale(0.98); }
|
||||
.code-btn-text {
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ===== 上传简历 ===== */
|
||||
.upload-box {
|
||||
margin-top: 18rpx;
|
||||
border: 1rpx dashed #ffb66a;
|
||||
background: #fffaf4;
|
||||
border-radius: 16rpx;
|
||||
padding: 28rpx 22rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
transition: transform .06s ease-in-out, background .2s;
|
||||
}
|
||||
.upload-box:active { transform: scale(0.992); }
|
||||
.upload-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
}
|
||||
.upload-tip {
|
||||
font-size: 26rpx;
|
||||
color: #666a73;
|
||||
}
|
||||
.upload-success-text {
|
||||
font-size: 26rpx;
|
||||
color: #13b26b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ===== 提交按钮 ===== */
|
||||
.btn-primary {
|
||||
margin-top: 22rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 48rpx; /* 胶囊 */
|
||||
background: linear-gradient(180deg, #ff9a2d 0%, #ff8d1a 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 14rpx 28rpx rgba(255,141,26,0.28);
|
||||
transition: transform .06s ease-in-out;
|
||||
}
|
||||
.btn-primary:active { transform: scale(0.985); }
|
||||
.btn-primary-text {
|
||||
color: #ffffff;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ===== 记录入口 ===== */
|
||||
.record {
|
||||
margin-top: 12rpx;
|
||||
padding: 16rpx 8rpx 4rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
.record-icon { width: 28rpx; height: 28rpx; }
|
||||
.record-text { font-size: 26rpx; color: #1c2023; }
|
||||
|
||||
/* ===== 复用的工具类(与原项目兼容) ===== */
|
||||
.flex-col { display: flex; flex-direction: column; }
|
||||
.flex-row { display: flex; flex-direction: row; }
|
||||
.items-center { align-items: center; }
|
||||
.justify-between { justify-content: space-between; }
|
||||
.justify-center { justify-content: center; }
|
||||
.self-center { align-self: center; }
|
||||
.self-stretch { align-self: stretch; }
|
||||
.relative { position: relative; }
|
||||
.shrink-0 { flex-shrink: 0; }
|
||||
.mt-15 { margin-top: 30rpx; }
|
||||
.mt-21 { margin-top: 42rpx; }
|
||||
.mt-28 { margin-top: 56rpx; }
|
||||
.ml-16 { margin-left: 32rpx; }
|
BIN
pages/loginModule/employeeAccountApply/images/resume.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
pages/loginModule/employeeAccountApply/images/right.png
Normal file
After Width: | Height: | Size: 321 B |
@ -0,0 +1,84 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
import { decodeBase64 } from "../../../utils/decodebase64";
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
applyDesc: '',
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
getApplyDesc() {
|
||||
wx.request({
|
||||
url: baseUrl + '/userInfo/query/applyNotice',
|
||||
method: 'POST',
|
||||
success: res => {
|
||||
if (res.data.code === 1) {
|
||||
this.setData({ applyDesc: decodeBase64(res.data.data) })
|
||||
} else {
|
||||
wx.showToast({ title: res.data.message, icon: 'none' });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||||
}
|
||||
})
|
||||
},
|
||||
onLoad() {
|
||||
this.getApplyDesc()
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
|
||||
}
|
||||
})
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<!--pages/loginModule/employeeAccountNotice/employeeAccountNotice.wxml-->
|
||||
<view class="flex-col page">
|
||||
<text class="self-center text">员工账号申请须知</text>
|
||||
<rich-text nodes="{{ applyDesc }}" class="section view mt-20"></rich-text>
|
||||
</view>
|
@ -0,0 +1,27 @@
|
||||
/* pages/loginModule/employeeAccountNotice/employeeAccountNotice.wxss */
|
||||
.page {
|
||||
padding: 65.08rpx 42.19rpx 150rpx 44.06rpx;
|
||||
background-color: #ffffff;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
}
|
||||
.text {
|
||||
color: #000000;
|
||||
font-size: 33.75rpx;
|
||||
font-weight: bold;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 31.26rpx;
|
||||
}
|
||||
.section {
|
||||
align-self: stretch;
|
||||
}
|
||||
.view {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: transparent;
|
||||
}
|
146
pages/loginModule/employeeApplyQuery/employeeApplyQuery.js
Normal file
@ -0,0 +1,146 @@
|
||||
import { baseUrl } from "../../../request";
|
||||
|
||||
Page({
|
||||
data: {
|
||||
status: '', // 审核状态: 审核中、审核通过、审核失败
|
||||
result: {} // 查询结果数据
|
||||
},
|
||||
|
||||
// 输入框事件
|
||||
onInput(e) {
|
||||
this.setData({
|
||||
inputIdCard: e.detail.value // 获取身份证输入
|
||||
});
|
||||
},
|
||||
|
||||
// 查询操作
|
||||
onSearch() {
|
||||
const inputIdCard = this.data.inputIdCard;
|
||||
if (!inputIdCard) {
|
||||
wx.showToast({
|
||||
title: '请输入身份证',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询的接口
|
||||
wx.request({
|
||||
url: baseUrl + '/advancementApply/query/credential', // 替换为你的后端查询接口
|
||||
method: 'POST',
|
||||
data: { templateString: inputIdCard },
|
||||
success: (res) => {
|
||||
console.log('后端返回---->',res.data);
|
||||
if (res.data.code === 1) {
|
||||
// 假设返回的查询结果是以下格式
|
||||
const result = res.data.data; // 获取返回的数据
|
||||
|
||||
// 更新审核状态和查询结果
|
||||
this.setData({
|
||||
status: result.reviewStatus, // 审核状态
|
||||
result: {
|
||||
name: result.name, // 姓名
|
||||
phone: result.phone, // 手机号
|
||||
idCard: result.idCard, // 身份证号
|
||||
failureReason: result.rejectReason, // 失败原因
|
||||
password: result.userPassword, // 密码(如果有的话)
|
||||
userRole: result.userRole, // 用户级别
|
||||
id: result.id
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: res.data.message,
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '请求失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 重新申请操作
|
||||
onReapply() {
|
||||
wx.showToast({
|
||||
title: '重新申请中...',
|
||||
icon: 'none'
|
||||
});
|
||||
},
|
||||
|
||||
// 用户撤销申请
|
||||
revokeApplication() {
|
||||
const { id } = this.data.result
|
||||
console.log('id--->',id);
|
||||
wx.showModal({
|
||||
title: '确认',
|
||||
content: '是否撤销申请',
|
||||
complete: (res) => {
|
||||
if (res.cancel) {
|
||||
|
||||
}
|
||||
if (res.confirm) {
|
||||
wx.request({
|
||||
url: baseUrl + '/advancementApply/modify/status',
|
||||
method: 'POST',
|
||||
header: {
|
||||
Authorization: wx.getStorageSync('token')
|
||||
},
|
||||
data: {
|
||||
id: id
|
||||
},
|
||||
success: res => {
|
||||
console.log('后端返回11---->',res.data);
|
||||
if (res.data.code === 1 ) {
|
||||
this.setData({
|
||||
status: ''
|
||||
})
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '系统错误',
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 用户去登录
|
||||
gotoLogin() {
|
||||
wx.navigateBack({
|
||||
delta: 2
|
||||
})
|
||||
},
|
||||
|
||||
// 用户重新申请
|
||||
reapply() {
|
||||
wx.navigateBack({
|
||||
delta: 1
|
||||
})
|
||||
},
|
||||
|
||||
copyPassword() {
|
||||
const { password } = this.data.result
|
||||
wx.setClipboardData({
|
||||
data: password, // 要复制的内容
|
||||
success(res) {
|
||||
wx.showToast({
|
||||
title: '已复制到剪贴板',
|
||||
icon: 'success'
|
||||
});
|
||||
},
|
||||
fail() {
|
||||
wx.showToast({
|
||||
title: '复制失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
98
pages/loginModule/employeeApplyQuery/employeeApplyQuery.wxml
Normal file
@ -0,0 +1,98 @@
|
||||
<view class="flex-col page">
|
||||
<!-- 身份证输入框 -->
|
||||
<view class="flex-row items-center section">
|
||||
<image class="image" src="./images/find.png" />
|
||||
<input class="font text ml-5" maxlength="18" placeholder="请输入身份证查询凭证" bindinput="onInput" bindconfirm="onSearch" />
|
||||
</view>
|
||||
|
||||
<!-- 显示查询结果 -->
|
||||
<view class="flex-col mt-18">
|
||||
<!-- 审核失败 -->
|
||||
<view wx:if="{{status === '已拒绝'}}" class="flex-col section_2">
|
||||
<view class="flex-row justify-center self-start section_3">
|
||||
<image class="image_2" src="./images/flase.png" />
|
||||
<text class="font text_2 ml-8">审核失败</text>
|
||||
</view>
|
||||
<text class="self-start font_2 text_3">姓名</text>
|
||||
<text class="self-start font_3 text_4">{{result.name}}</text>
|
||||
<text class="self-start font_2 text_5">手机号</text>
|
||||
<text class="self-start font_4 text_6">{{result.phone}}</text>
|
||||
<view class="flex-col self-stretch relative group">
|
||||
<view class="self-start section_4"></view>
|
||||
<view class="flex-col justify-start items-center self-stretch text-wrapper" bind:tap="reapply">
|
||||
<text class="font text_9">重新申请</text>
|
||||
</view>
|
||||
<view class="flex-col items-start section_5 pos">
|
||||
<text class="font_5 text_7">原因:</text>
|
||||
<text class="font_5 text_8 mt-11">{{result.failureReason}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 审核通过 -->
|
||||
<view wx:if="{{status === '已通过'}}" class="flex-col section_6 mt-18">
|
||||
<view class="flex-col group_2">
|
||||
<view class="flex-row justify-between group_3">
|
||||
<view class="flex-row items-center section_7">
|
||||
<image class="shrink-0 image_3" src="./images/current.png" />
|
||||
<text class="font text_11 ml-6">审核通过</text>
|
||||
</view>
|
||||
<view class="flex-col justify-start items-center self-start text-wrapper_2">
|
||||
<text class="text_10">员工</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-col relative mt-21">
|
||||
<view class="flex-row self-stretch section_8">
|
||||
<text class="font_2 text_12">姓名</text>
|
||||
<text class="font_3 ml-39">{{result.name}}</text>
|
||||
</view>
|
||||
<view class="flex-row self-stretch section_9">
|
||||
<text class="font_2">手机号</text>
|
||||
<text class="font_4 text_13 ml-23">{{result.phone}}</text>
|
||||
</view>
|
||||
<view class="self-start section_10"></view>
|
||||
<view class="flex-row justify-between items-center section_11 pos_2">
|
||||
<view class="flex-row items-center">
|
||||
<text class="font_2 text_14">密码</text>
|
||||
<text class="font_3 text_15 ml-37">{{result.password}}</text>
|
||||
</view>
|
||||
<text class="font_2 text_16" bind:tap="copyPassword">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="group_4 mt-21">
|
||||
<text class="font_6 text_17">温馨提示:</text>
|
||||
<text class="font_6">恭喜成为本公司的推广员工,请保存以上账号密码,用于登录员工端小程序。</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-col justify-start items-center text-wrapper_3" bind:tap="gotoLogin"><text class="font text_18">去登录</text></view>
|
||||
</view>
|
||||
|
||||
<!-- 审核中 -->
|
||||
<view wx:if="{{status === '待审核'}}" class="flex-col section_12 mt-18">
|
||||
<view class="flex-row justify-center items-center self-start section_13">
|
||||
<image class="image" src="./images/wait.png" />
|
||||
<text class="font text_19 ml-6">审核中</text>
|
||||
</view>
|
||||
<text class="self-start font_2 text_20">姓名</text>
|
||||
<text class="self-start font_3 text_21">{{result.name}}</text>
|
||||
<text class="self-start font_2 text_22">手机号</text>
|
||||
<text class="self-start font_4 text_23">{{result.phone}}</text>
|
||||
<!-- <text class="self-start font_2 text_24">身份证号</text>
|
||||
<view class="flex-row self-stretch group_5">
|
||||
<view class="shrink-0 section_14"></view>
|
||||
<view class="flex-col justify-start items-start flex-1 text-wrapper_4">
|
||||
<text class="text_25">{{result.idCard}}</text>
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="flex-col self-stretch group_6">
|
||||
<view class="group_7">
|
||||
<text class="font_6 text_26">注:</text>
|
||||
<text class="font_6">每次必须通过身份证来查看申请状态。</text>
|
||||
</view>
|
||||
<view class="flex-col justify-start items-center text-wrapper_5 mt-14" bind:tap="revokeApplication">
|
||||
<text class="font text_27">撤销申请</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
330
pages/loginModule/employeeApplyQuery/employeeApplyQuery.wxss
Normal file
@ -0,0 +1,330 @@
|
||||
.ml-5 {
|
||||
margin-left: 9.38rpx;
|
||||
}
|
||||
.mt-11 {
|
||||
margin-top: 20.63rpx;
|
||||
}
|
||||
.ml-39 {
|
||||
margin-left: 73.13rpx;
|
||||
}
|
||||
.ml-23 {
|
||||
margin-left: 43.13rpx;
|
||||
}
|
||||
.ml-37 {
|
||||
margin-left: 69.38rpx;
|
||||
}
|
||||
.mt-21 {
|
||||
margin-top: 39.38rpx;
|
||||
}
|
||||
.page {
|
||||
padding: 45.94rpx 38.44rpx 140.91rpx;
|
||||
background-color: #fafafa;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
.section {
|
||||
padding: 15.81rpx 13.93rpx 14.19rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 93.75rpx;
|
||||
border: solid 1.88rpx #e0e0e0;
|
||||
}
|
||||
.image {
|
||||
width: 33.75rpx;
|
||||
height: 33.75rpx;
|
||||
}
|
||||
.font {
|
||||
font-size: 30rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 27.84rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
.text {
|
||||
color: #919191;
|
||||
line-height: 27.75rpx;
|
||||
width: 90%;
|
||||
}
|
||||
.section_2 {
|
||||
padding: 33.75rpx 28.13rpx 35.63rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 18.43rpx;
|
||||
box-shadow: 0rpx 3.75rpx 7.5rpx #00000040;
|
||||
}
|
||||
.section_3 {
|
||||
padding: 15rpx 0 13.13rpx;
|
||||
background-color: #e53935;
|
||||
border-radius: 18.75rpx;
|
||||
width: 211.88rpx;
|
||||
}
|
||||
.image_2 {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
}
|
||||
.text_2 {
|
||||
margin-right: 3.28rpx;
|
||||
line-height: 28.16rpx;
|
||||
}
|
||||
.font_2 {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 24.15rpx;
|
||||
color: #999999;
|
||||
}
|
||||
.text_3 {
|
||||
margin-left: 2.81rpx;
|
||||
margin-top: 39rpx;
|
||||
line-height: 24.21rpx;
|
||||
}
|
||||
.font_3 {
|
||||
font-size: 30rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 27.84rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.text_4 {
|
||||
margin-left: 4.24rpx;
|
||||
margin-top: 21rpx;
|
||||
}
|
||||
.text_5 {
|
||||
margin-left: 3.19rpx;
|
||||
margin-top: 41.4rpx;
|
||||
}
|
||||
.font_4 {
|
||||
font-size: 30rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 24.15rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.text_6 {
|
||||
margin-left: 4.52rpx;
|
||||
margin-top: 24.04rpx;
|
||||
line-height: 22.76rpx;
|
||||
}
|
||||
.group {
|
||||
margin-top: 43.73rpx;
|
||||
}
|
||||
.section_4 {
|
||||
background-color: #d32f2f;
|
||||
border-radius: 9.38rpx 0rpx 0rpx 9.38rpx;
|
||||
width: 13.13rpx;
|
||||
height: 120rpx;
|
||||
}
|
||||
.text-wrapper {
|
||||
margin-top: 35.63rpx;
|
||||
padding: 35.57rpx 0 30.49rpx;
|
||||
background-color: #e53935;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.text_9 {
|
||||
line-height: 27.69rpx;
|
||||
}
|
||||
.section_5 {
|
||||
padding: 27.81rpx 21.47rpx 24.26rpx;
|
||||
background-color: #fdecea;
|
||||
border-radius: 8.01rpx;
|
||||
}
|
||||
.pos {
|
||||
position: absolute;
|
||||
left: 7.5rpx;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
.font_5 {
|
||||
font-size: 26.25rpx;
|
||||
font-family: AlibabaPuHuiTi;
|
||||
line-height: 24.15rpx;
|
||||
}
|
||||
.text_7 {
|
||||
color: #d32f2f;
|
||||
line-height: 23.25rpx;
|
||||
}
|
||||
.text_8 {
|
||||
color: #555555;
|
||||
line-height: 24.26rpx;
|
||||
}
|
||||
.section_6 {
|
||||
padding: 0 28.13rpx 56.25rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 22.24rpx;
|
||||
box-shadow: 0rpx 3.75rpx 7.5rpx #00000040;
|
||||
}
|
||||
.group_2 {
|
||||
padding: 31.88rpx 0 54.17rpx;
|
||||
}
|
||||
.group_3 {
|
||||
padding-left: 7.5rpx;
|
||||
}
|
||||
.section_7 {
|
||||
padding: 11.25rpx 18.75rpx 9.38rpx;
|
||||
background-color: #66bb6a;
|
||||
border-radius: 18.75rpx;
|
||||
height: 58.13rpx;
|
||||
}
|
||||
.image_3 {
|
||||
width: 37.5rpx;
|
||||
height: 37.5rpx;
|
||||
}
|
||||
.text_11 {
|
||||
margin-right: 3.28rpx;
|
||||
line-height: 28.16rpx;
|
||||
}
|
||||
.text-wrapper_2 {
|
||||
padding: 11.47rpx 0 9.73rpx;
|
||||
background-color: #66bb6a;
|
||||
border-radius: 29.46rpx;
|
||||
width: 99.38rpx;
|
||||
height: 41.25rpx;
|
||||
}
|
||||
.text_10 {
|
||||
color: #ffffff;
|
||||
font-size: 22.5rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 20.04rpx;
|
||||
}
|
||||
.section_8 {
|
||||
padding: 33.58rpx 27.19rpx 30.45rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.text_12 {
|
||||
line-height: 24.21rpx;
|
||||
}
|
||||
.section_9 {
|
||||
margin-top: 28.74rpx;
|
||||
padding: 35.33rpx 27.56rpx 32.4rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.text_13 {
|
||||
line-height: 22.76rpx;
|
||||
}
|
||||
.section_10 {
|
||||
margin-top: 31.26rpx;
|
||||
background-color: #66bb6a;
|
||||
border-radius: 9.38rpx 0rpx 0rpx 9.38rpx;
|
||||
width: 13.13rpx;
|
||||
height: 91.88rpx;
|
||||
}
|
||||
.section_11 {
|
||||
padding: 34.74rpx 21.62rpx 25.59rpx;
|
||||
background-color: #e8f5e9;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.pos_2 {
|
||||
position: absolute;
|
||||
left: 5.63rpx;
|
||||
right: 0;
|
||||
top: 235.75rpx;
|
||||
}
|
||||
.text_14 {
|
||||
line-height: 24.36rpx;
|
||||
}
|
||||
.text_15 {
|
||||
line-height: 31.54rpx;
|
||||
}
|
||||
.text_16 {
|
||||
margin-right: 7.52rpx;
|
||||
color: #66bb6a;
|
||||
}
|
||||
.group_4 {
|
||||
line-height: 31.88rpx;
|
||||
}
|
||||
.font_6 {
|
||||
font-size: 26.25rpx;
|
||||
font-family: SourceHanSansCN;
|
||||
line-height: 31.88rpx;
|
||||
color: #999999;
|
||||
}
|
||||
.text_17 {
|
||||
color: #66bb6a;
|
||||
}
|
||||
.text-wrapper_3 {
|
||||
padding: 35.66rpx 0 30.39rpx;
|
||||
background-color: #66bb6a;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.text_18 {
|
||||
line-height: 27.69rpx;
|
||||
}
|
||||
.section_12 {
|
||||
padding: 33.75rpx 28.13rpx 54.38rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 22.24rpx;
|
||||
box-shadow: 0rpx 3.75rpx 7.5rpx #00000040;
|
||||
}
|
||||
.section_13 {
|
||||
margin-left: 7.5rpx;
|
||||
padding: 13.13rpx 0 11.25rpx;
|
||||
background-color: #ff8d1a;
|
||||
border-radius: 18.75rpx;
|
||||
width: 183.75rpx;
|
||||
}
|
||||
.text_19 {
|
||||
line-height: 28.16rpx;
|
||||
}
|
||||
.text_20 {
|
||||
margin-left: 2.81rpx;
|
||||
margin-top: 39rpx;
|
||||
line-height: 24.21rpx;
|
||||
}
|
||||
.text_21 {
|
||||
margin-left: 4.24rpx;
|
||||
margin-top: 21rpx;
|
||||
}
|
||||
.text_22 {
|
||||
margin-left: 3.19rpx;
|
||||
margin-top: 41.4rpx;
|
||||
}
|
||||
.text_23 {
|
||||
margin-left: 4.52rpx;
|
||||
margin-top: 24.04rpx;
|
||||
line-height: 22.76rpx;
|
||||
}
|
||||
.text_24 {
|
||||
margin-left: 2.98rpx;
|
||||
margin-top: 39.6rpx;
|
||||
line-height: 24.43rpx;
|
||||
}
|
||||
.group_5 {
|
||||
margin-top: 20.94rpx;
|
||||
}
|
||||
.section_14 {
|
||||
background-color: #ff8d1a;
|
||||
border-radius: 9.38rpx 0rpx 0rpx 9.38rpx;
|
||||
width: 13.13rpx;
|
||||
height: 91.88rpx;
|
||||
}
|
||||
.text-wrapper_4 {
|
||||
margin-left: -7.5rpx;
|
||||
padding: 38.04rpx 0 32.04rpx;
|
||||
background-color: #fff4e5;
|
||||
border-radius: 9.19rpx;
|
||||
height: 91.88rpx;
|
||||
}
|
||||
.text_25 {
|
||||
margin-left: 25.71rpx;
|
||||
color: #ff8d1a;
|
||||
font-size: 30rpx;
|
||||
font-family: AlimamaShuHeiTi;
|
||||
line-height: 21.79rpx;
|
||||
}
|
||||
.group_6 {
|
||||
margin-top: 40.97rpx;
|
||||
}
|
||||
.group_7 {
|
||||
margin-left: 2.74rpx;
|
||||
margin-right: 10.33rpx;
|
||||
line-height: 31.88rpx;
|
||||
}
|
||||
.text_26 {
|
||||
color: #ff8d1a;
|
||||
}
|
||||
.text-wrapper_5 {
|
||||
padding: 35.48rpx 0 30.41rpx;
|
||||
background-color: #ff8d1a;
|
||||
border-radius: 9.38rpx;
|
||||
}
|
||||
.text_27 {
|
||||
line-height: 27.86rpx;
|
||||
}
|
BIN
pages/loginModule/employeeApplyQuery/images/current.png
Normal file
After Width: | Height: | Size: 425 B |
BIN
pages/loginModule/employeeApplyQuery/images/find.png
Normal file
After Width: | Height: | Size: 820 B |