feat: add request.js utility, service page, and fix hospital image URLs
- Add request.js for unified API calls with loading/error handling - Add service page (service type listing) - Fix hospital list to load from API with proper image URL construction - Add service types dynamic loading on index page - Various mini program improvements (order, care, wallet pages) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/index/index",
|
||||
"pages/service/service",
|
||||
"pages/peihu/peihu",
|
||||
"pages/tuiguang/extensionInfor",
|
||||
"pages/my/my",
|
||||
@@ -48,6 +49,12 @@
|
||||
"iconPath": "pages/image/income.png",
|
||||
"selectedIconPath": "pages/image/income_a.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/service/service",
|
||||
"text": "服务",
|
||||
"iconPath": "pages/image/service.png",
|
||||
"selectedIconPath": "pages/image/service.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/order/order",
|
||||
"text": "订单",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 109 KiB |
@@ -1,83 +1,17 @@
|
||||
//获取应用实例
|
||||
var app = getApp();
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据00
|
||||
*/
|
||||
data: {
|
||||
order_list: [],
|
||||
hospitalData: [],
|
||||
bannerdata: [
|
||||
"home-banner",
|
||||
"home-banner",
|
||||
"home-banner"
|
||||
],
|
||||
itemView: [{
|
||||
icon: "全程陪诊",
|
||||
title: "全程陪诊",
|
||||
price: "200",
|
||||
describe: "服务内容:排队 预约 挂号 缴费 取药 记录医嘱",
|
||||
ordertype: "1"
|
||||
},
|
||||
{
|
||||
icon: "诊前约号",
|
||||
title: "诊前约号",
|
||||
price: "20",
|
||||
describe: "服务内容:协助办理完成挂号",
|
||||
ordertype: "2"
|
||||
},
|
||||
// {
|
||||
// icon: "代办买药",
|
||||
// title: "代办买药",
|
||||
// price:"30",
|
||||
// describe:"服务内容:协助代理买药"
|
||||
// },
|
||||
{
|
||||
icon: "代办问诊",
|
||||
title: "代办问诊",
|
||||
price: "100",
|
||||
describe: "服务内容:使用病人或者家属取检查报告化验单向医生问明情况",
|
||||
ordertype: "4"
|
||||
},
|
||||
{
|
||||
icon: "取送结果",
|
||||
title: "取送结果",
|
||||
price: "50",
|
||||
describe: "服务内容:包括给病人或者家属取检查报告化验单等",
|
||||
ordertype: "3"
|
||||
},
|
||||
// {
|
||||
// icon: "出入院办理",
|
||||
// title: "出入院办理",
|
||||
// price:"100",
|
||||
// describe:"协助办理出入院手续"
|
||||
// }
|
||||
],
|
||||
hospitalData: [{
|
||||
img: "https://bkimg.cdn.bcebos.com/pic/8326cffc1e178a828fa58d64f303738da877e85d?x-bce-process=image/resize,m_lfit,w_536,limit_1",
|
||||
name: "西安市高新医院",
|
||||
grade: "三甲",
|
||||
genre: "综合医院",
|
||||
skiled: "消化内科、心血管内科",
|
||||
address: "高新区高新六路",
|
||||
id: "1"
|
||||
}, {
|
||||
img: "https://bkimg.cdn.bcebos.com/pic/8326cffc1e178a828fa58d64f303738da877e85d?x-bce-process=image/resize,m_lfit,w_536,limit_1",
|
||||
name: "第四军医大学西京医院",
|
||||
grade: "三甲",
|
||||
genre: "综合医院",
|
||||
skiled: "消化内科、心血管内科",
|
||||
address: "莲湖区康复路",
|
||||
id: "2"
|
||||
}, {
|
||||
img: "https://bkimg.cdn.bcebos.com/pic/8326cffc1e178a828fa58d64f303738da877e85d?x-bce-process=image/resize,m_lfit,w_536,limit_1",
|
||||
name: "陕西省人民医院",
|
||||
grade: "三甲",
|
||||
genre: "综合医院",
|
||||
skiled: "消化内科、心血管内科",
|
||||
address: "碑林区友谊西路",
|
||||
id: "3"
|
||||
}]
|
||||
itemView: [],
|
||||
firstLoad: true
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -101,6 +35,10 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
goService() {
|
||||
wx.switchTab({ url: '/pages/service/service' })
|
||||
},
|
||||
|
||||
go_peizhen() {
|
||||
if (wx.getStorageSync('phone') == '') {
|
||||
wx.setStorageSync('uidFlag', false);
|
||||
@@ -124,33 +62,60 @@ Page({
|
||||
})
|
||||
}
|
||||
},
|
||||
//获取服务类型列表(从后台动态加载,最多显示8个热门推荐)
|
||||
getServiceTypes: function () {
|
||||
var that = this;
|
||||
request({
|
||||
url: '/system/serviceType/enabled',
|
||||
method: 'GET',
|
||||
data: { category: '2' },
|
||||
loading: false
|
||||
}).then(res => {
|
||||
var services = res.data || [];
|
||||
if (services.length) {
|
||||
var mapped = services.slice(0, 8).map(function (s) {
|
||||
return {
|
||||
icon: s.icon || s.name,
|
||||
title: s.name,
|
||||
price: s.price,
|
||||
describe: s.description || '',
|
||||
ordertype: s.typeCode
|
||||
}
|
||||
})
|
||||
that.setData({ itemView: mapped })
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
//获取医院列表
|
||||
getHospitalList: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/hospital/list',
|
||||
header: app.getRequestHeader(),
|
||||
request({
|
||||
url: '/system/hospital/list',
|
||||
method: 'GET',
|
||||
data: {},
|
||||
success: (res) => {
|
||||
var resp = res.data;
|
||||
console.log("resp==" + resp)
|
||||
if (res.data.code == 200) {
|
||||
if (this.data.pageNum == 1) {
|
||||
that.setData({
|
||||
order_list: resp.data,
|
||||
pageNum: this.data.pageNum + 1
|
||||
});
|
||||
|
||||
} else {
|
||||
that.setData({
|
||||
order_list: resp.data,
|
||||
|
||||
});
|
||||
loading: false
|
||||
}).then(res => {
|
||||
var hospitals = res.rows || res.data || [];
|
||||
if (hospitals.length) {
|
||||
var baseUrl = app.globalData.url;
|
||||
var mapped = hospitals.map(function (h) {
|
||||
var imgUrl = h.hospitalImage || '';
|
||||
if (imgUrl && imgUrl.indexOf('http') !== 0) {
|
||||
imgUrl = baseUrl + imgUrl;
|
||||
}
|
||||
return {
|
||||
id: h.id,
|
||||
name: h.hospitalname,
|
||||
grade: h.hospitalLevel || '三甲',
|
||||
genre: h.hospitalType || '综合医院',
|
||||
skiled: h.hospitalDesc || '',
|
||||
address: h.address || '',
|
||||
img: imgUrl
|
||||
}
|
||||
})
|
||||
that.setData({ hospitalData: mapped })
|
||||
}
|
||||
});
|
||||
}).catch(() => {})
|
||||
},
|
||||
/**
|
||||
* 医院列表
|
||||
@@ -205,28 +170,17 @@ Page({
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
if (this.data.firstLoad) {
|
||||
this.setData({ firstLoad: false })
|
||||
this.getServiceTypes()
|
||||
this.getHospitalList()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
|
||||
this.getServiceTypes()
|
||||
this.getHospitalList()
|
||||
wx.stopPullDownRefresh()
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,11 +12,15 @@
|
||||
</view>
|
||||
</swiper>
|
||||
</view>
|
||||
<view class="section-header">
|
||||
<view class="section-title">热门服务</view>
|
||||
<view class="section-more" bindtap="goService">查看更多 ></view>
|
||||
</view>
|
||||
<view class="item-view">
|
||||
<block wx:for="{{itemView}}" wx:key="id">
|
||||
<view class="item-list" bindtap="itemClick" data-id="{{item.title}}" data-item="{{item}}">
|
||||
<view class="item-image">
|
||||
<image src="../image/home/{{item.icon}}.png" mode="aspectFit"></image>
|
||||
<image src="{{item.icon.indexOf('http') === 0 ? item.icon : '../image/home/' + item.icon + '.png'}}" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="item-title">
|
||||
<text>{{item.title}}</text>
|
||||
@@ -52,7 +56,7 @@
|
||||
<block wx:for="{{hospitalData}}" wx:key="id">
|
||||
<view class="list-item" bindtap="listItemTap" data-id="{{item.id}}">
|
||||
<view class="img-back">
|
||||
<image src="{{item.img}}" mode="aspectFill"></image>
|
||||
<image src="{{item.img || '/pages/image/empty.png'}}" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="list-info">
|
||||
<view class="name"><text>{{item.name}}</text></view>
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
.item-view{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 30rpx 40rpx 0;
|
||||
flex-wrap: wrap;
|
||||
margin: 20rpx 30rpx 0;
|
||||
}
|
||||
|
||||
#block{
|
||||
@@ -50,8 +51,8 @@
|
||||
.item-list{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 10rpx;
|
||||
width: 160rpx;
|
||||
padding: 0 8rpx;
|
||||
width: calc(25% - 16rpx);
|
||||
height: 160rpx;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -208,3 +209,21 @@
|
||||
font-size: 30rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.section-header{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx 40rpx 0 40rpx;
|
||||
}
|
||||
|
||||
.section-title{
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.section-more{
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
@@ -1,207 +1,95 @@
|
||||
// pages/mechanism/mechanism.js
|
||||
//获取应用实例
|
||||
const app = getApp()
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
navHeight: '',
|
||||
menuButtonInfo: {},
|
||||
searchMarginTop: 0, // 搜索框上边距
|
||||
searchWidth: 0, // 搜索框宽度
|
||||
searchHeight: 0, // 搜索框高度
|
||||
page:1,
|
||||
search: ''
|
||||
searchMarginTop: 0,
|
||||
searchWidth: 0,
|
||||
searchHeight: 0,
|
||||
page: 1,
|
||||
search: '',
|
||||
lists: [],
|
||||
firstLoad: true
|
||||
},
|
||||
/**
|
||||
* 监听搜索内容
|
||||
*/
|
||||
changeSearch: function(e) {
|
||||
let that = this;
|
||||
var inputSearch = e.detail.value;
|
||||
that.setData({
|
||||
search: inputSearch
|
||||
})
|
||||
app.console(inputSearch+"================="+'22dddddddddddddddddddddd2')
|
||||
// this.dataRefresh()
|
||||
this.getMechanismList();
|
||||
|
||||
changeSearch: function (e) {
|
||||
this.setData({ search: e.detail.value })
|
||||
this.getMechanismList()
|
||||
},
|
||||
back(){
|
||||
|
||||
back() {
|
||||
wx.navigateBack()
|
||||
},
|
||||
//机构详情跳转
|
||||
mechanism(e){
|
||||
app.console("================="+'dddddddddddddddd')
|
||||
|
||||
mechanism(e) {
|
||||
wx.navigateTo({
|
||||
url: "/pages/institutions/institutions?id=" + e.currentTarget.dataset.id,
|
||||
})
|
||||
},
|
||||
Seemore(){
|
||||
console.log('点击了查看更多');
|
||||
|
||||
Seemore() {
|
||||
console.log('点击了查看更多')
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
|
||||
onLoad: function (options) {
|
||||
this.setData({
|
||||
menuButtonInfo: wx.getMenuButtonBoundingClientRect()
|
||||
})
|
||||
console.log(this.data.menuButtonInfo)
|
||||
this.setData({ menuButtonInfo: wx.getMenuButtonBoundingClientRect() })
|
||||
const { top, width, height, right } = this.data.menuButtonInfo
|
||||
wx.getSystemInfo({
|
||||
success: (res) => {
|
||||
const { statusBarHeight } = res
|
||||
const margin = top - statusBarHeight
|
||||
this.setData({
|
||||
navHeight: (height + statusBarHeight + (margin * 2) ),
|
||||
searchMarginTop: statusBarHeight + margin, // 状态栏 + 胶囊按钮边距
|
||||
searchHeight: height, // 与胶囊按钮同高
|
||||
searchWidth: right - width // 胶囊按钮右边坐标 - 胶囊按钮宽度 = 按钮左边可使用宽度
|
||||
navHeight: (height + statusBarHeight + (margin * 2)),
|
||||
searchMarginTop: statusBarHeight + margin,
|
||||
searchHeight: height,
|
||||
searchWidth: right - width
|
||||
})
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
this.getMechanismList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
},
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
//this.getOrderList();
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.buildUrl("/app/Goddesswechat/getOrderList"),
|
||||
header: app.getRequestHeader(),
|
||||
method:'POST',
|
||||
data: {
|
||||
version_number: app.globalData.version_number,
|
||||
uid:wx.getStorageSync('uid'),
|
||||
token:wx.getStorageSync('token'),
|
||||
page:1,
|
||||
page_size:10,
|
||||
style: that.data.status[ that.data.currentType ]
|
||||
|
||||
},
|
||||
success: (res)=> {
|
||||
var resp = res.data;
|
||||
|
||||
if(resp.erro==0){
|
||||
that.setData({
|
||||
page:1,
|
||||
order_list:resp.order,
|
||||
});
|
||||
wx.stopPullDownRefresh({
|
||||
success: (res) => {},
|
||||
})
|
||||
if (this.data.firstLoad) {
|
||||
this.setData({ firstLoad: false })
|
||||
this.getMechanismList()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
this.setData({ page: 1 })
|
||||
this.getMechanismList().finally(() => wx.stopPullDownRefresh())
|
||||
},
|
||||
|
||||
onReachBottom: function () {
|
||||
|
||||
this.getMechanismList();
|
||||
this.getMechanismList()
|
||||
},
|
||||
|
||||
//机构列表
|
||||
getMechanismList: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.buildUrl("/app/Goddesswechat/getMechanismList"),
|
||||
header: app.getRequestHeader(),
|
||||
method:'POST',
|
||||
var that = this
|
||||
return request({
|
||||
url: '/app/Goddesswechat/getMechanismList',
|
||||
method: 'POST',
|
||||
loading: true,
|
||||
data: {
|
||||
version_number: app.globalData.version_number,
|
||||
uid:wx.getStorageSync('uid'),
|
||||
token:wx.getStorageSync('token'),
|
||||
page:'1',
|
||||
page_size:500,
|
||||
city:'',
|
||||
style_id:'',
|
||||
serach_name:this.data.search,
|
||||
px_type:'',
|
||||
lng:'',
|
||||
lat:'',
|
||||
uid: wx.getStorageSync('uid'),
|
||||
token: wx.getStorageSync('token'),
|
||||
page: '1',
|
||||
page_size: 50,
|
||||
city: '',
|
||||
style_id: '',
|
||||
serach_name: this.data.search,
|
||||
px_type: '',
|
||||
lng: '',
|
||||
lat: '',
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.erro === 0) {
|
||||
that.setData({ lists: res.lists || [] })
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
success: function (res) {
|
||||
var resp = res.data;
|
||||
if(resp.erro==0){
|
||||
that.setData({
|
||||
lists:resp.lists
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
// if(that.data.page==1){
|
||||
// that.setData({
|
||||
// lists:resp.lists,
|
||||
// page:that.data.page+1
|
||||
// });
|
||||
|
||||
// }else{
|
||||
// that.setData({
|
||||
// lists:that.data.lists.concat(resp.lists),
|
||||
// page:that.data.page+1
|
||||
// });
|
||||
// }
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
})
|
||||
@@ -20,12 +20,9 @@
|
||||
|
||||
<view class="order-list" style="margin-top: 160rpx;" wx:if="{{lists.length}}">
|
||||
<view wx:for="{{lists}}" wx:key="{{index}}" wx:for-item="item">
|
||||
|
||||
<view class="recommend" bindtap="mechanism" data-id="{{item.id}}">
|
||||
<view class="red-image">
|
||||
<image
|
||||
src="{{item.wechat_logo}}">
|
||||
</image>
|
||||
<image src="{{item.wechat_logo}}"></image>
|
||||
</view>
|
||||
<view class="red-tit">
|
||||
<view style="font-size: 30rpx;color: #333333;font-weight:700">{{item.mechanism_name}}</view>
|
||||
@@ -40,25 +37,12 @@
|
||||
<text>已预约{{item.appointment}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<!-- <view style="margin-left:150rpx">
|
||||
<view class="headline">
|
||||
<text>抢</text>
|
||||
<text style="font-size: 18rpx;font-family: PingFang SC;margin-left:18rpx;">【除皱瘦脸】瘦脸针·国产瘦脸加强版80-正...</text>
|
||||
<text style="font-size: 18rpx;color:#FF4A4A;margin-left:117rpx;">¥99</text>
|
||||
</view>
|
||||
<view class="headline">
|
||||
<text>抢</text>
|
||||
<text style="font-size: 18rpx;font-family: PingFang SC;margin-left:18rpx;">【除皱瘦脸】瘦脸针·国产瘦脸加强版80-正...</text>
|
||||
<text style="font-size: 18rpx;color:#FF4A4A;margin-left:117rpx;">¥99</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="Residuals" bindtap="Seemore">
|
||||
查看其他3个相关产品
|
||||
<view class="jiantou"></view>
|
||||
</view> -->
|
||||
</view>
|
||||
<view wx:else style="display:flex;flex-direction:column;align-items:center;padding-top:300rpx;">
|
||||
<image style="width:200rpx;height:200rpx;" src="/pages/image/empty.png"></image>
|
||||
<view style="color:#999;font-size:28rpx;margin-top:20rpx;">暂无机构</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
@@ -1,47 +1,32 @@
|
||||
var Token = require('../../utils/util.js');
|
||||
|
||||
const app = getApp()
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName'),
|
||||
phone: wx.getStorageSync('phone'),
|
||||
uidFlag: wx.getStorageSync('uidFlag'),
|
||||
status: '',
|
||||
code: '',
|
||||
height: ''
|
||||
height: '',
|
||||
logging: false
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function (options) {
|
||||
var statusBarHeight = wx.getSystemInfoSync().statusBarHeight;
|
||||
app.console(statusBarHeight + "=================xxxxxxxxxxxxxxxxxxxxxxxx")
|
||||
this.setData({
|
||||
statusBarHeight: statusBarHeight,
|
||||
height: 46 + statusBarHeight,
|
||||
});
|
||||
app.console(this.data.height + "=================xxxxxxxxxxxxxxxxxxxxxxxx")
|
||||
//调试参数
|
||||
// wx.setStorageSync('phone', 18133922183);
|
||||
// wx.setStorageSync('uid', 'adfdffb45a364fc23162f1ebfe9dd66f');
|
||||
// wx.setStorageSync('token', '797d4q7XT8/PM9bU+T+CNpEpNfsWeVb5j+eXnrRXW0yq+wKXY9fBNSvb7qPiCRMlzZmwG3u1ods8R8Rh3gITxCkyiZGUtLZf');
|
||||
// wx.setStorageSync('uidFlag', true);
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
|
||||
onShow: function () {
|
||||
// 仅在未登录时获取 code
|
||||
if (!this.data.uidFlag) {
|
||||
this.getLogin()
|
||||
console.log("code==" + this.data.code)
|
||||
// if (wx.getStorageSync('phone') != '') {
|
||||
// this.getUserBaseInfo()
|
||||
// }
|
||||
}
|
||||
},
|
||||
|
||||
// 登录
|
||||
@@ -49,74 +34,62 @@ Page({
|
||||
var that = this;
|
||||
wx.login({
|
||||
success: res => {
|
||||
console.log(res)
|
||||
app.globalData.code = res.code
|
||||
that.setData({
|
||||
code: res.code
|
||||
})
|
||||
that.setData({ code: res.code })
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取电话号码
|
||||
getPhoneNumber(e) {
|
||||
|
||||
// 获取电话号码并登录
|
||||
async getPhoneNumber(e) {
|
||||
if (this.data.logging) return
|
||||
this.setData({ logging: true })
|
||||
|
||||
console.log("encryptedData==" + e.detail.encryptedData)
|
||||
console.log("iv==" + e.detail.iv)
|
||||
console.log("wxcode==" + app.globalData.code)
|
||||
|
||||
var _this = this;
|
||||
console.log(e)
|
||||
wx.request({
|
||||
url: app.globalData.url + '/weixinLogin',
|
||||
try {
|
||||
var res = await request({
|
||||
url: '/weixinLogin',
|
||||
method: 'POST',
|
||||
loading: true,
|
||||
loadingText: '登录中...',
|
||||
data: {
|
||||
encryptedData: e.detail.encryptedData,
|
||||
iv: e.detail.iv,
|
||||
wxcode: app.globalData.code
|
||||
},
|
||||
method: 'POST',
|
||||
header: {
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
success(res) {
|
||||
if (res.data.code == 200) {
|
||||
app.globalData.phone = res.data.phone;
|
||||
wx.setStorageSync('phone', res.data.data.phoneNumber);
|
||||
wx.setStorageSync('uid', res.data.data.userId);
|
||||
wx.setStorageSync('token', res.data.data.token);
|
||||
}
|
||||
})
|
||||
|
||||
app.globalData.phone = res.phone;
|
||||
wx.setStorageSync('phone', res.data.phoneNumber);
|
||||
wx.setStorageSync('uid', res.data.userId);
|
||||
wx.setStorageSync('token', res.data.token);
|
||||
wx.setStorageSync('uidFlag', true);
|
||||
_this.setData({
|
||||
|
||||
this.setData({
|
||||
uidFlag: true,
|
||||
phone: res.data.phone
|
||||
phone: res.phone
|
||||
})
|
||||
app.globalData.uid = res.data.uid;
|
||||
wx.switchTab({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
// Token.token()
|
||||
_this.getToken()
|
||||
app.globalData.uid = res.data.userId;
|
||||
|
||||
_this.ceshi()
|
||||
|
||||
wx.showToast({
|
||||
title: res.data.msg,
|
||||
icon: 'none'
|
||||
});
|
||||
wx.showToast({ title: '登录成功', icon: 'success' })
|
||||
|
||||
// 同步登录信息到服务端(失败不影响登录)
|
||||
this.syncLogin()
|
||||
|
||||
// 返回上一页,若无法返回则到首页
|
||||
var pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
wx.navigateBack()
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: res.data.msg,
|
||||
icon: 'none'
|
||||
});
|
||||
wx.switchTab({ url: '/pages/index/index' })
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
this.setData({ logging: false })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
//上传测试数据
|
||||
ceshi() {
|
||||
|
||||
// 同步登录信息
|
||||
syncLogin() {
|
||||
wx.request({
|
||||
url: app.buildUrltwo("/member/logintwo"),
|
||||
header: app.getRequestHeader(),
|
||||
@@ -125,49 +98,22 @@ Page({
|
||||
name: wx.getStorageSync('uid'),
|
||||
phone: wx.getStorageSync('phone'),
|
||||
storename: wx.getStorageSync('token')
|
||||
|
||||
},
|
||||
success: function (res) {
|
||||
var resp = res.data;
|
||||
if (resp.code != 200) {
|
||||
app.alert({
|
||||
"content": resp.msg
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 跳转
|
||||
wx.navigateBack({});
|
||||
}
|
||||
})
|
||||
},
|
||||
//获取token
|
||||
|
||||
getUserBaseInfo: function () {
|
||||
var that = this;
|
||||
//假数据
|
||||
// if (this.data.resp.erro == 0) {
|
||||
// that.setData({
|
||||
// infor: this.data.resp.infor
|
||||
// });
|
||||
// }
|
||||
wx.request({
|
||||
url: app.globalData.url + '/getUserToken',
|
||||
header: app.getRequestHeader(),
|
||||
request({
|
||||
url: '/getUserToken',
|
||||
method: 'GET',
|
||||
data: {
|
||||
phonenumber: '18133922183'
|
||||
},
|
||||
success: function (res) {
|
||||
var resp = res.data;
|
||||
console.log(resp + "=================dddddddddddddddddddddddddddddddddddddddddddd")
|
||||
console.log(resp.erro + "=================dddddddddddddddddddddddddddddddddddddddddddd")
|
||||
data: { phonenumber: this.data.phone },
|
||||
loading: false
|
||||
}).then(resp => {
|
||||
if (resp.erro == 0) {
|
||||
|
||||
that.setData({
|
||||
infor: resp.infor
|
||||
});
|
||||
that.setData({ infor: resp.infor })
|
||||
}
|
||||
}
|
||||
});
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,36 +1,37 @@
|
||||
//获取应用实例
|
||||
var app = getApp();
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
order_list: [],
|
||||
nav_type: 1,
|
||||
all: true,
|
||||
height: '',
|
||||
url: app.globalData.url,
|
||||
|
||||
statusType: ["全部", "待接单", "已接单", "服务中", "待支付", "已完成","已取消"],
|
||||
status: ["", "0", "1", "2", "3","4","-2"],
|
||||
currentType: 0,
|
||||
tabClass: ["", "", "", "", "", "", ""],
|
||||
pageNum: 1
|
||||
pageNum: 1,
|
||||
hasMore: true,
|
||||
firstLoad: true,
|
||||
loading: false
|
||||
},
|
||||
|
||||
statusTap: function (e) {
|
||||
var curType = e.currentTarget.dataset.index;
|
||||
this.setData({
|
||||
currentType: curType,
|
||||
pageNum: 1
|
||||
pageNum: 1,
|
||||
order_list: []
|
||||
});
|
||||
this.getOrderList();
|
||||
},
|
||||
|
||||
onClickLeft() {
|
||||
wx.navigateBack()
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
|
||||
onLoad: function (options) {
|
||||
var statusBarHeight = wx.getSystemInfoSync().statusBarHeight;
|
||||
this.setData({
|
||||
@@ -38,142 +39,98 @@ Page({
|
||||
height: 46 + statusBarHeight,
|
||||
});
|
||||
},
|
||||
//条目点击---订单状态:-2:已取消 -1:拒绝接单 0:待接单 1:已接单 2:服务中 3:待支付 4:已完成 5申请退款 6退款中 7已退款 8:已结算
|
||||
|
||||
|
||||
itemclick(e) {
|
||||
console.log("列表条目的index==" + e.currentTarget.dataset.index)
|
||||
//去订单详情页
|
||||
if (e.currentTarget.dataset.item != 0) {
|
||||
let item = JSON.stringify(e.currentTarget.dataset.item);
|
||||
//console.log("传递的item" + item);
|
||||
wx.navigateTo({
|
||||
url: "/pages/orderdetail/orderdetail?item=" + item,
|
||||
});
|
||||
}
|
||||
},
|
||||
//跳转订单详情(去付款)
|
||||
|
||||
go_pay(e) {
|
||||
console.log(e.currentTarget.dataset.id)
|
||||
// wx.navigateTo({
|
||||
// url: '/pages/orderdetail/orderdetail?' + "type=" + '2' + '&id=' + e.currentTarget.dataset.id,
|
||||
// })
|
||||
|
||||
if (e.currentTarget.dataset.item != 0) {
|
||||
let item = JSON.stringify(e.currentTarget.dataset.item);
|
||||
console.log("传递的item" + item);
|
||||
wx.navigateTo({
|
||||
url: "/pages/orderdetail/orderdetail?item=" + item,
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
this.setData({
|
||||
order_list: [],
|
||||
pageNum: 1
|
||||
})
|
||||
this.getOrderList();
|
||||
// 首次加载或从其他页返回刷新
|
||||
if (this.data.firstLoad) {
|
||||
this.setData({ firstLoad: false })
|
||||
this.getOrderList()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
//this.getOrderList();
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/view/list',
|
||||
header: app.getRequestHeader(),
|
||||
this.setData({ pageNum: 1 })
|
||||
this.refreshList().finally(() => wx.stopPullDownRefresh())
|
||||
},
|
||||
|
||||
onReachBottom: function () {
|
||||
if (this.data.hasMore && !this.data.loading) {
|
||||
this.getOrderList()
|
||||
}
|
||||
},
|
||||
|
||||
async refreshList() {
|
||||
this.setData({ loading: true })
|
||||
try {
|
||||
var res = await request({
|
||||
url: '/system/view/list',
|
||||
method: 'GET',
|
||||
loading: false,
|
||||
data: {
|
||||
pageNum: 1,
|
||||
pageSize: 30,
|
||||
status: that.data.status[that.data.currentType],
|
||||
status: this.data.status[this.data.currentType],
|
||||
usercId: wx.getStorageSync('uid')
|
||||
},
|
||||
success: (res) => {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
pageNum: 1,
|
||||
order_list: resp.rows || resp.data,
|
||||
});
|
||||
wx.stopPullDownRefresh({
|
||||
success: (res) => {},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
var list = res.rows || res.data || []
|
||||
this.setData({
|
||||
order_list: list,
|
||||
pageNum: 2,
|
||||
hasMore: list.length >= 30
|
||||
})
|
||||
} catch (e) {}
|
||||
this.setData({ loading: false })
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
console.log("==页面上拉触底事件的处理函数==")
|
||||
// this.getOrderList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
},
|
||||
//订单状态:-2:已取消 -1:拒绝接单 0:待接单 1:已接单 2:服务中 3:待支付 4:已完成 5申请退款 6退款中 7已退款 8:已结算
|
||||
getOrderList: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/view/list',
|
||||
header: app.getRequestHeader(),
|
||||
async getOrderList() {
|
||||
if (this.data.loading) return
|
||||
this.setData({ loading: true })
|
||||
try {
|
||||
var res = await request({
|
||||
url: '/system/view/list',
|
||||
method: 'GET',
|
||||
loading: this.data.pageNum === 1,
|
||||
data: {
|
||||
pageNum: this.data.pageNum,
|
||||
pageSize: 30,
|
||||
status: that.data.status[that.data.currentType],
|
||||
status: this.data.status[this.data.currentType],
|
||||
usercId: wx.getStorageSync('uid')
|
||||
},
|
||||
success: (res) => {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
if (this.data.pageNum == 1) {
|
||||
that.setData({
|
||||
order_list: resp.rows || resp.data,
|
||||
pageNum: this.data.pageNum + 1
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
var newList = res.rows || res.data || []
|
||||
if (this.data.pageNum === 1) {
|
||||
this.setData({
|
||||
order_list: newList,
|
||||
pageNum: 2,
|
||||
hasMore: newList.length >= 30
|
||||
})
|
||||
} else {
|
||||
that.setData({
|
||||
order_list: this.data.order_list.concat(resp.rows || resp.data),
|
||||
pageNum: this.data.pageNum + 1
|
||||
});
|
||||
this.setData({
|
||||
order_list: this.data.order_list.concat(newList),
|
||||
pageNum: this.data.pageNum + 1,
|
||||
hasMore: newList.length >= 30
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {}
|
||||
this.setData({ loading: false })
|
||||
},
|
||||
})
|
||||
@@ -35,7 +35,7 @@
|
||||
<view style="height: 1rpx;background: #ECECEC;"></view>
|
||||
<view class="details_box">
|
||||
|
||||
<image src="{{item.userbAvatar}}" class="Group-image"></image>
|
||||
<image src="{{item.userbAvatar || '/pages/image/userimg.png'}}" class="Group-image"></image>
|
||||
<view style="margin-left: 31rpx;margin-top: 40rpx;">
|
||||
<view class="title">{{item.userbName}}</view>
|
||||
<view class="detail_number">{{item.serviceTime}}天</view>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
//获取应用实例
|
||||
var app = getApp();
|
||||
// pages/peihu.js
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
dingdan_msg: false,
|
||||
ewm_msg: false,
|
||||
@@ -20,6 +18,8 @@ Page({
|
||||
refund: '',
|
||||
charge_phone: '',
|
||||
refund_box: false,
|
||||
paying: false,
|
||||
refund_reason: '',
|
||||
list: [{
|
||||
text: '不喜欢/不想要',
|
||||
},
|
||||
@@ -42,74 +42,50 @@ Page({
|
||||
show: false,
|
||||
height: ''
|
||||
},
|
||||
|
||||
// 确认支付
|
||||
confirm_pay: async function () {
|
||||
var that = this;
|
||||
if (!this.data.is_ok_click) {
|
||||
that.setData({
|
||||
is_ok_click: true
|
||||
})
|
||||
|
||||
|
||||
//你要执行的操作
|
||||
confirm_pay() {
|
||||
if (this.data.paying) return
|
||||
this.setData({ paying: true })
|
||||
this.godetail()
|
||||
setTimeout(function () {
|
||||
that.setData({
|
||||
is_ok_click: false
|
||||
})
|
||||
}, 10000) //阻止一秒点击多次
|
||||
} else {
|
||||
// wx.showToast({
|
||||
// title: '请勿重复操作!',
|
||||
// })
|
||||
}
|
||||
},
|
||||
|
||||
godetail() {
|
||||
console.log('点击了去付款');
|
||||
var _this = this;
|
||||
console.log(this.data.id + 'tttttttttttttttttttttttttttttttttt')
|
||||
wx.request({
|
||||
// url: app.globalData.url + '/system/weixinPayNew/12345666',
|
||||
//order_id为8位数字
|
||||
url: app.globalData.url + '/system/order/weixinPay/' + this.data.order_id,
|
||||
header: app.getRequestHeader(),
|
||||
async godetail() {
|
||||
var _this = this
|
||||
try {
|
||||
// 1. 获取支付参数
|
||||
var res = await request({
|
||||
url: '/system/order/weixinPay/' + _this.data.order_id,
|
||||
method: 'GET',
|
||||
data: {
|
||||
loading: true,
|
||||
loadingText: '加载支付信息...',
|
||||
showError: true
|
||||
})
|
||||
|
||||
},
|
||||
success(res) {
|
||||
if (res.data.code == 200) {
|
||||
console.log('timeStamp==' + res.data.data.timeStamp)
|
||||
console.log('nonceStr==' + res.data.data.nonceStr)
|
||||
console.log('package==' + res.data.data.package)
|
||||
console.log('signType==' + res.data.data.signType)
|
||||
console.log('paySign==' + res.data.data.paySign)
|
||||
// 2. 调起微信支付
|
||||
wx.requestPayment({
|
||||
timeStamp: res.data.data.timeStamp,
|
||||
nonceStr: res.data.data.nonceStr,
|
||||
package: res.data.data.package,
|
||||
signType: res.data.data.signType,
|
||||
paySign: res.data.data.paySign,
|
||||
success(res) {
|
||||
console.log('支付成功');
|
||||
wx.navigateTo({
|
||||
timeStamp: res.data.timeStamp,
|
||||
nonceStr: res.data.nonceStr,
|
||||
package: res.data.package,
|
||||
signType: res.data.signType,
|
||||
paySign: res.data.paySign,
|
||||
success() {
|
||||
wx.redirectTo({
|
||||
url: '/shopping/pages/paysuccess/paysuccess?order_id=' + _this.data.order_id + '&paid=1',
|
||||
})
|
||||
},
|
||||
fail(res) {
|
||||
console.log('支付失败');
|
||||
}
|
||||
})
|
||||
} else {
|
||||
fail(payErr) {
|
||||
wx.showToast({
|
||||
title: res.data.msg,
|
||||
icon: 'error',
|
||||
title: '支付取消或失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
// 错误提示已由 request 工具处理
|
||||
}
|
||||
_this.setData({ paying: false })
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -189,24 +165,18 @@ Page({
|
||||
|
||||
},
|
||||
//订单详情
|
||||
getOrderDetail: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/view/getInfo',
|
||||
header: app.getRequestHeader(),
|
||||
method: 'get',
|
||||
data: {
|
||||
orderId: this.data.order_id
|
||||
},
|
||||
success: function (res) {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
item: res.data.data
|
||||
});
|
||||
async getOrderDetail() {
|
||||
try {
|
||||
var res = await request({
|
||||
url: '/system/view/getInfo',
|
||||
method: 'GET',
|
||||
loading: true,
|
||||
data: { orderId: this.data.order_id }
|
||||
})
|
||||
if (res.data) {
|
||||
this.setData({ item: res.data })
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {}
|
||||
},
|
||||
/**
|
||||
* 订单状态:0:待接单 1:已接单 时候的取消订单
|
||||
@@ -357,6 +327,15 @@ Page({
|
||||
mengceng: true
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 已完成订单申请退款
|
||||
*/
|
||||
applyRefund() {
|
||||
this.setData({
|
||||
refund_box: true,
|
||||
mengceng: true
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 填写原因开始退款
|
||||
*/
|
||||
@@ -364,27 +343,36 @@ Page({
|
||||
this.refund()
|
||||
},
|
||||
/**
|
||||
* 退款
|
||||
* 退款申请
|
||||
*/
|
||||
refund() {
|
||||
var that = this;
|
||||
var reason = this.data.refund_reason || '';
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/order/refundOrder/' + this.data.order_id,
|
||||
header: app.getRequestHeader(),
|
||||
method: 'GET',
|
||||
url: app.globalData.url + '/system/order/applyRefund/' + this.data.order_id,
|
||||
header: {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer ' + app.getCache("token")
|
||||
},
|
||||
method: 'POST',
|
||||
data: {
|
||||
// id: this.data.item.orderId,
|
||||
remark: reason
|
||||
},
|
||||
success: (res) => {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
wx.showToast({
|
||||
title: '退款申请成功',
|
||||
title: resp.msg || '退款申请成功',
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(function () {
|
||||
//要延时执行的代码
|
||||
wx.navigateBack()
|
||||
}, 2000) //延迟时间 这里是2秒
|
||||
}, 2000)
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: resp.msg || '申请失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -394,6 +382,13 @@ Page({
|
||||
mengceng: false
|
||||
})
|
||||
},
|
||||
radioChange(e) {
|
||||
var idx = e.detail.value;
|
||||
var list = this.data.list;
|
||||
this.setData({
|
||||
refund_reason: list[idx] ? list[idx].text : ''
|
||||
})
|
||||
},
|
||||
nocancel() {
|
||||
this.setData({
|
||||
dingdan_msg: false,
|
||||
@@ -415,26 +410,6 @@ Page({
|
||||
phoneNumber: this.data.charge_phone,
|
||||
})
|
||||
},
|
||||
//订单详情
|
||||
getOrderDetail: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/view/getInfo/',
|
||||
header: app.getRequestHeader(),
|
||||
method: 'get',
|
||||
data: {
|
||||
orderId: this.data.order_id
|
||||
},
|
||||
success: function (res) {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
item: res.data.data
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
|
||||
@@ -59,6 +59,13 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单状态:4:已完成 -->
|
||||
<view wx:if="{{item.status==4}}" class="opt_view">
|
||||
<view class="detail_btn" bindtap="applyRefund">
|
||||
申请退款
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系信息 -->
|
||||
<view class="contact">
|
||||
<view class="contact_title">联系信息</view>
|
||||
@@ -153,7 +160,7 @@
|
||||
<view wx:for="{{list}}" class="list_box">
|
||||
<view>{{item.text}}</view>
|
||||
<view>
|
||||
<radio></radio>
|
||||
<radio value="{{index}}" />
|
||||
</view>
|
||||
</view>
|
||||
</radio-group>
|
||||
@@ -173,7 +180,7 @@
|
||||
<view wx:for="{{list}}" class="list_box">
|
||||
<view>{{item.text}}</view>
|
||||
<view>
|
||||
<radio></radio>
|
||||
<radio value="{{index}}" />
|
||||
</view>
|
||||
</view>
|
||||
</radio-group>
|
||||
|
||||
@@ -339,7 +339,12 @@ Page({
|
||||
})
|
||||
},
|
||||
fail(res) {
|
||||
console.log('支付失败');
|
||||
console.log('支付失败', res);
|
||||
wx.showToast({
|
||||
title: '支付取消或失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -1,70 +1,69 @@
|
||||
//获取应用实例
|
||||
var app = getApp();
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
option1: [{
|
||||
text: '切换医院',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
text: '西安市高新医院',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
text: '第四军医大学西京医院',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
text: '陕西省人民医院',
|
||||
value: 3
|
||||
},
|
||||
],
|
||||
option1: [{ text: '切换医院', value: 0 }],
|
||||
value1: 0,
|
||||
version_number: '1.0',
|
||||
height: '',
|
||||
url: app.globalData.url,
|
||||
hospitalId:''
|
||||
hospitalId: '',
|
||||
special_offer: [],
|
||||
firstLoad: true
|
||||
},
|
||||
|
||||
shuChange: function (e) {
|
||||
console.log(e.detail);
|
||||
|
||||
this.setData({
|
||||
hospitalId: e.detail
|
||||
})
|
||||
this.getBannerAndCat();
|
||||
this.setData({ hospitalId: e.detail })
|
||||
this.getCaregiverList();
|
||||
},
|
||||
|
||||
//生命周期回调——监听小程序启动或切前台。
|
||||
onShow: function () {
|
||||
this.getBannerAndCat();
|
||||
if (this.data.firstLoad) {
|
||||
this.setData({ firstLoad: false })
|
||||
this.getHospitals()
|
||||
this.getCaregiverList()
|
||||
}
|
||||
},
|
||||
//首页信息
|
||||
getBannerAndCat: function () {
|
||||
|
||||
// 加载医院列表
|
||||
getHospitals: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/hospitalUserView/list',
|
||||
header: app.getRequestHeader(),
|
||||
request({
|
||||
url: '/system/hospital/list',
|
||||
method: 'GET',
|
||||
data: {
|
||||
hospitalId:this.data.hospitalId
|
||||
loading: false
|
||||
}).then(res => {
|
||||
var hospitals = res.rows || res.data || [];
|
||||
var options = [{ text: '切换医院', value: 0 }];
|
||||
hospitals.forEach(function (h, i) {
|
||||
options.push({
|
||||
text: h.hospitalname,
|
||||
value: i + 1
|
||||
})
|
||||
})
|
||||
that.setData({ option1: options, hospitalData: hospitals })
|
||||
}).catch(() => {})
|
||||
},
|
||||
success: (res) => {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
special_offer: resp.data,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 加载陪护人员列表
|
||||
getCaregiverList: function () {
|
||||
var that = this;
|
||||
request({
|
||||
url: '/system/hospitalUserView/list',
|
||||
method: 'GET',
|
||||
loading: true,
|
||||
data: { hospitalId: this.data.hospitalId }
|
||||
}).then(res => {
|
||||
that.setData({ special_offer: res.data || [] })
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// 跳转详情
|
||||
details(e) {
|
||||
if (e.currentTarget.dataset.item != 0) {
|
||||
let item = JSON.stringify(e.currentTarget.dataset.item);
|
||||
console.log("传递的item" + item);
|
||||
wx.navigateTo({
|
||||
url: "/shopping/pages/goddess/goddess?item=" + item,
|
||||
});
|
||||
@@ -78,15 +77,10 @@ Page({
|
||||
this.setData({
|
||||
statusBarHeight: statusBarHeight,
|
||||
height: 46 + statusBarHeight,
|
||||
hospitalId: e.hospitalId || ''
|
||||
});
|
||||
console.log('e.hospitalId' + e.hospitalId);
|
||||
this.setData({
|
||||
hospitalId: e.hospitalId
|
||||
})
|
||||
},
|
||||
changeDateTime1(e) {
|
||||
this.setData({
|
||||
dateTime1: e.detail.value
|
||||
});
|
||||
this.setData({ dateTime1: e.detail.value });
|
||||
},
|
||||
})
|
||||
@@ -43,5 +43,9 @@
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<view wx:else style="display:flex;flex-direction:column;align-items:center;padding-top:160rpx;">
|
||||
<image style="width:200rpx;height:200rpx;" src="/pages/image/empty.png"></image>
|
||||
<view style="color:#999;font-size:28rpx;margin-top:20rpx;">暂无陪护人员</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,102 +1,77 @@
|
||||
//获取应用实例
|
||||
var app = getApp();
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
option1: [{
|
||||
text: '全部医院',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
text: '西京医院',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
text: '陕西省人民医院',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
text: '陕西省人民医院1',
|
||||
value: 5
|
||||
},
|
||||
],
|
||||
option1: [{ text: '全部医院', value: 0 }],
|
||||
value1: 0,
|
||||
version_number: '1.0',
|
||||
height: '',
|
||||
url: app.globalData.url,
|
||||
itemView: [
|
||||
{
|
||||
icon: "诊前约号",
|
||||
title: "全程陪诊",
|
||||
price:"200",
|
||||
describe:"服务内容:排队 预约 挂号 缴费 取药 记录医嘱"
|
||||
},
|
||||
{
|
||||
icon: "诊前约号",
|
||||
title: "诊前约号",
|
||||
price:"20",
|
||||
describe:"服务内容:协助办理完成挂号"
|
||||
},
|
||||
// {
|
||||
// icon: "代办买药",
|
||||
// title: "代办买药",
|
||||
// price:"30",
|
||||
// describe:"服务内容:协助代理买药"
|
||||
// },
|
||||
{
|
||||
icon: "取送结果",
|
||||
title: "代办问诊",
|
||||
price:"50",
|
||||
describe:"服务内容:使用病人或者家属取检查报告化验单向医生问明情况"
|
||||
},
|
||||
{
|
||||
icon: "取送结果",
|
||||
title: "取送结果",
|
||||
price:"50",
|
||||
describe:"服务内容:包括给病人或者家属取检查报告化验单等"
|
||||
},
|
||||
// {
|
||||
// icon: "出入院办理",
|
||||
// title: "出入院办理",
|
||||
// price:"100",
|
||||
// describe:"协助办理出入院手续"
|
||||
// }
|
||||
],
|
||||
itemView: [],
|
||||
firstLoad: true
|
||||
},
|
||||
onChange(e) {
|
||||
this.setData({
|
||||
timeData: e.detail,
|
||||
});
|
||||
this.setData({ timeData: e.detail });
|
||||
},
|
||||
//生命周期回调——监听小程序启动或切前台。
|
||||
onShow: function () {
|
||||
this.getBannerAndCat();
|
||||
},
|
||||
//首页信息
|
||||
getBannerAndCat: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/hospitalUserView/list',
|
||||
header: app.getRequestHeader(),
|
||||
method: 'GET',
|
||||
data: {
|
||||
|
||||
onShow: function () {
|
||||
if (this.data.firstLoad) {
|
||||
this.setData({ firstLoad: false })
|
||||
this.getHospitals()
|
||||
this.getServiceTypes()
|
||||
}
|
||||
},
|
||||
success: (res) => {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
special_offer: resp.data,
|
||||
});
|
||||
|
||||
// 加载医院列表(用于下拉选择)
|
||||
getHospitals: function () {
|
||||
var that = this;
|
||||
request({
|
||||
url: '/system/hospital/list',
|
||||
method: 'GET',
|
||||
loading: false
|
||||
}).then(res => {
|
||||
var hospitals = res.rows || res.data || [];
|
||||
var options = [{ text: '全部医院', value: 0 }];
|
||||
hospitals.forEach(function (h, i) {
|
||||
options.push({
|
||||
text: h.hospitalname,
|
||||
value: i + 1
|
||||
})
|
||||
})
|
||||
that.setData({ option1: options, hospitalData: hospitals })
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// 加载服务类型
|
||||
getServiceTypes: function () {
|
||||
var that = this;
|
||||
request({
|
||||
url: '/system/serviceType/enabled',
|
||||
method: 'GET',
|
||||
data: { category: '2' },
|
||||
loading: false
|
||||
}).then(res => {
|
||||
var services = res.data || [];
|
||||
if (services.length) {
|
||||
var mapped = services.map(function (s) {
|
||||
return {
|
||||
icon: s.icon || s.name,
|
||||
title: s.name,
|
||||
price: s.price,
|
||||
describe: s.description || ''
|
||||
}
|
||||
})
|
||||
that.setData({ itemView: mapped })
|
||||
}
|
||||
});
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// 跳转详情
|
||||
details(e) {
|
||||
if (e.currentTarget.dataset.item != 0) {
|
||||
let item = JSON.stringify(e.currentTarget.dataset.item);
|
||||
console.log("传递的item" + item);
|
||||
wx.navigateTo({
|
||||
url: "/pages/peizhen/peizhendetail?item=" + item,
|
||||
});
|
||||
@@ -113,8 +88,6 @@ Page({
|
||||
});
|
||||
},
|
||||
changeDateTime1(e) {
|
||||
this.setData({
|
||||
dateTime1: e.detail.value
|
||||
});
|
||||
this.setData({ dateTime1: e.detail.value });
|
||||
},
|
||||
})
|
||||
@@ -21,14 +21,12 @@
|
||||
<view class="contar">
|
||||
<view class="tejiashangpin">
|
||||
<view class="Discount" wx:if="{{itemView.length}}">
|
||||
|
||||
<view wx:for="{{itemView}}" wx:key="{{index}}" wx:for-item="item" class="flex-item bc_green" style='display:flex;background-color: white;margin-right: 10rpx;margin-bottom: 24rpx;'>
|
||||
<view class="Group" bindtap="details" data-item="{{item}}">
|
||||
<view class="Group-image">
|
||||
<image src="../image/abc.png"></image>
|
||||
</view>
|
||||
<view class="content">
|
||||
|
||||
<view style="display: flex; flex-direction:row;align-items : flex-end;">
|
||||
<view class="title1">{{item.title}}</view>
|
||||
<view class="title2"></view>
|
||||
@@ -42,18 +40,10 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
<view wx:else style="display:flex;flex-direction:column;align-items:center;padding-top:160rpx;">
|
||||
<image style="width:200rpx;height:200rpx;" src="/pages/image/empty.png"></image>
|
||||
<view style="color:#999;font-size:28rpx;margin-top:20rpx;">暂无服务</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
const app = getApp()
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
task: {
|
||||
phone: '',
|
||||
phonedisplay: false,
|
||||
placeholder: '请输入联系方式'
|
||||
},
|
||||
objectArray: [{ text: '加载中...', value: 0 }], // 医院列表(动态加载)
|
||||
objectIndex: 0, // 默认显示位置
|
||||
objectArray: [{ text: '请选择医院', value: 0 }],
|
||||
objectIndex: 0,
|
||||
show: true,
|
||||
height: '',
|
||||
seckill_start: '请输入开始日期',
|
||||
@@ -33,16 +31,17 @@ Page({
|
||||
id: 0,
|
||||
order_id: '',
|
||||
timeData: {},
|
||||
Height: "", //这是swiper要动态设置的高度属性
|
||||
Height: "",
|
||||
charge_phone: '',
|
||||
is_ok_click: false,
|
||||
submitting: false,
|
||||
clock: '',
|
||||
address: '',
|
||||
danjia: 0.01, //单位为元
|
||||
danjia: 0.01,
|
||||
beizhu: '',
|
||||
name: '',
|
||||
jzphone: '',
|
||||
idcard: '' // 患者身份证号(可选)
|
||||
idcard: '',
|
||||
hospitalsLoaded: false
|
||||
|
||||
},
|
||||
inputtaskphone(e) {
|
||||
@@ -85,58 +84,29 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 确认支付
|
||||
confirm_payy: async function () {
|
||||
// wx.showToast({
|
||||
// title: '点击了',
|
||||
// icon: 'none'
|
||||
// });
|
||||
var that = this;
|
||||
if (!this.data.is_ok_click) {
|
||||
that.setData({
|
||||
is_ok_click: true
|
||||
})
|
||||
//你要执行的操作
|
||||
// 提交订单
|
||||
confirm_payy() {
|
||||
if (this.data.submitting) return
|
||||
this.payment()
|
||||
setTimeout(function () {
|
||||
that.setData({
|
||||
is_ok_click: false
|
||||
})
|
||||
}, 10000) //阻止一秒点击多次
|
||||
} else {
|
||||
// wx.showToast({ title:'请勿重复操作!', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
//加载医院列表
|
||||
loadHospitals: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/hospital/list',
|
||||
header: app.getRequestHeader(),
|
||||
request({
|
||||
url: '/system/hospital/list',
|
||||
method: 'GET',
|
||||
data: {},
|
||||
success: (res) => {
|
||||
console.log('医院列表响应:', res.statusCode, JSON.stringify(res.data).substring(0, 200));
|
||||
if (res.data.code == 200) {
|
||||
var hospitals = res.data.rows || res.data.data || [];
|
||||
loading: false
|
||||
}).then(res => {
|
||||
var hospitals = res.rows || res.data || [];
|
||||
var list = [{ text: '请选择医院', value: 0 }];
|
||||
hospitals.forEach(function (h) {
|
||||
list.push({
|
||||
text: h.hospitalname,
|
||||
value: h.id
|
||||
list.push({ text: h.hospitalname, value: h.id });
|
||||
});
|
||||
});
|
||||
that.setData({ objectArray: list });
|
||||
} else {
|
||||
console.error('医院列表加载失败 code:', res.data.code, 'msg:', res.data.msg);
|
||||
that.setData({ objectArray: list, hospitalsLoaded: true });
|
||||
}).catch(() => {
|
||||
that.setData({ objectArray: [{ text: '加载失败,点击重试', value: 0 }] });
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('医院列表网络错误:', err);
|
||||
that.setData({ objectArray: [{ text: '网络错误,点击重试', value: 0 }] });
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
getprice: function () {
|
||||
var that = this;
|
||||
@@ -190,80 +160,54 @@ Page({
|
||||
return true
|
||||
}
|
||||
},
|
||||
payment() {
|
||||
|
||||
async payment() {
|
||||
// 表单校验
|
||||
if (this.data.objectIndex == 0) {
|
||||
wx.showToast({
|
||||
title: '请输选择医院',
|
||||
icon: 'none'
|
||||
});
|
||||
wx.showToast({ title: '请选择医院', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (this.data.jzphone == '') {
|
||||
wx.showToast({
|
||||
title: '请输入就诊人电话',
|
||||
icon: 'none'
|
||||
});
|
||||
if (!this.data.jzphone) {
|
||||
wx.showToast({ title: '请输入就诊人电话', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!/^1[3-9]\d{9}$/.test(this.data.jzphone)) {
|
||||
wx.showToast({ title: '手机号码格式不正确', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (this.data.seckill_start == '请输入开始日期') {
|
||||
wx.showToast({ title: '请选择开始日期', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var regtel = new RegExp('(^1[3|4|5|7|8][0-9]{9}$)', 'g');
|
||||
if (!regtel.exec(this.data.jzphone )) {
|
||||
wx.showToast({
|
||||
title: '手机号码格式不正确!',
|
||||
icon: 'none'
|
||||
});
|
||||
return
|
||||
}
|
||||
|
||||
if (this.data.seckill_start == "请输入开始日期") {
|
||||
wx.showToast({
|
||||
title: '请输入开始日期',
|
||||
icon: 'none'
|
||||
});
|
||||
return
|
||||
}
|
||||
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/order/insertOrderPz',
|
||||
this.setData({ submitting: true })
|
||||
try {
|
||||
var res = await request({
|
||||
url: '/system/order/insertOrderPz',
|
||||
method: 'POST',
|
||||
loading: true,
|
||||
loadingText: '提交订单中...',
|
||||
data: {
|
||||
cId: wx.getStorageSync('uid'), //患者id
|
||||
yuguMoney: this.data.item.price, //金额
|
||||
yuliu9: "2", //订单大类1-陪护 2-陪诊
|
||||
yuliu10: this.data.item.ordertype, //订单类型1-全程陪诊,2-诊前约号3-送取报告4-待办问诊
|
||||
cId: wx.getStorageSync('uid'),
|
||||
yuguMoney: this.data.item.price,
|
||||
yuliu9: "2",
|
||||
yuliu10: this.data.item.ordertype,
|
||||
hospitalId: this.data.objectArray[this.data.objectIndex].value,
|
||||
startTime: this.data.seckill_start,
|
||||
yuliu11: this.data.jzphone, //患者电话
|
||||
yuliu12: this.data.beizhu, //特殊要求
|
||||
yuliu13: this.data.address, //送达地址
|
||||
yuliu14: this.data.idcard //患者身份证号(可选)
|
||||
yuliu11: this.data.jzphone,
|
||||
yuliu12: this.data.beizhu,
|
||||
yuliu13: this.data.address,
|
||||
yuliu14: this.data.idcard
|
||||
},
|
||||
method: 'POST',
|
||||
header: {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer ' + app.getCache("token")
|
||||
},
|
||||
success(res) {
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
order_id: res.data.data.orderId,
|
||||
header: { 'content-type': 'application/json' }
|
||||
})
|
||||
console.log('order_id==' + res.data.data.orderId)
|
||||
app.console(that.data.order_id + "======要传的order_id")
|
||||
wx.navigateTo({
|
||||
url: '/shopping/pages/paysuccess/paysuccess?' + "order_id=" + that.data.order_id,
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: res.data.msg,
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
// redirectTo 防止返回重复下单
|
||||
wx.redirectTo({
|
||||
url: '/shopping/pages/paysuccess/paysuccess?order_id=' + res.data.orderId,
|
||||
})
|
||||
} catch (e) {
|
||||
// 错误提示已由 request 处理
|
||||
this.setData({ submitting: false })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
bindDateChange: function (e) {
|
||||
@@ -340,10 +284,9 @@ Page({
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
var that = this;
|
||||
this.loadHospitals();
|
||||
this.getprice();
|
||||
this.getpriceType();
|
||||
if (!this.data.hospitalsLoaded) {
|
||||
this.loadHospitals()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
87
coupon/pages/service/service.js
Normal file
87
coupon/pages/service/service.js
Normal file
@@ -0,0 +1,87 @@
|
||||
// 服务模块
|
||||
var app = getApp();
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
servicesPeizhen: [],
|
||||
servicesPeihu: [],
|
||||
activeTab: 0,
|
||||
firstLoad: true
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (this.data.firstLoad) {
|
||||
this.setData({ firstLoad: false })
|
||||
this.loadServices()
|
||||
}
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.loadServices().finally(() => wx.stopPullDownRefresh())
|
||||
},
|
||||
|
||||
async loadServices() {
|
||||
try {
|
||||
// 同时加载陪诊和陪护服务
|
||||
var [res1, res2] = await Promise.all([
|
||||
request({ url: '/system/serviceType/enabled', data: { category: '2' }, loading: true, loadingText: '加载服务...' }),
|
||||
request({ url: '/system/serviceType/enabled', data: { category: '1' }, loading: false })
|
||||
])
|
||||
this.setData({
|
||||
servicesPeizhen: (res1.data || []).map(function(s) {
|
||||
return {
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
title: s.name,
|
||||
price: s.price,
|
||||
desc: s.description,
|
||||
describe: s.description,
|
||||
icon: s.icon,
|
||||
ordertype: s.typeCode,
|
||||
typeCode: s.typeCode
|
||||
}
|
||||
}),
|
||||
servicesPeihu: (res2.data || []).map(function(s) {
|
||||
return {
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
title: s.name,
|
||||
price: s.price,
|
||||
desc: s.description,
|
||||
describe: s.description,
|
||||
icon: s.icon,
|
||||
ordertype: s.typeCode,
|
||||
typeCode: s.typeCode,
|
||||
nickName: s.name,
|
||||
introduce: s.description
|
||||
}
|
||||
})
|
||||
})
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
this.setData({ activeTab: e.currentTarget.dataset.index })
|
||||
},
|
||||
|
||||
// 点击服务-跳转下单页
|
||||
onServiceTap(e) {
|
||||
if (wx.getStorageSync('phone') == '') {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '请先登录',
|
||||
success(res) {
|
||||
if (res.confirm) wx.switchTab({ url: '/pages/my/my' })
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
var item = JSON.stringify(e.currentTarget.dataset.item)
|
||||
if (this.data.activeTab === 0) {
|
||||
wx.navigateTo({ url: '/pages/peizhen/peizhendetail?item=' + item })
|
||||
} else {
|
||||
wx.navigateTo({ url: '/shopping/pages/goddess/goddess?item=' + item })
|
||||
}
|
||||
}
|
||||
})
|
||||
4
coupon/pages/service/service.json
Normal file
4
coupon/pages/service/service.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "服务项目"
|
||||
}
|
||||
69
coupon/pages/service/service.wxml
Normal file
69
coupon/pages/service/service.wxml
Normal file
@@ -0,0 +1,69 @@
|
||||
<view class="page">
|
||||
<!-- 顶部标题 -->
|
||||
<view class="header">
|
||||
<view class="header-title">全部服务</view>
|
||||
<view class="header-sub">专业陪诊陪护,全程无忧</view>
|
||||
</view>
|
||||
|
||||
<!-- 分类切换 -->
|
||||
<view class="tab-bar">
|
||||
<view class="tab-item {{activeTab === 0 ? 'active' : ''}}" bindtap="switchTab" data-index="{{0}}">
|
||||
<text>就医陪诊</text>
|
||||
<view class="tab-line" wx:if="{{activeTab === 0}}"></view>
|
||||
</view>
|
||||
<view class="tab-item {{activeTab === 1 ? 'active' : ''}}" bindtap="switchTab" data-index="{{1}}">
|
||||
<text>院内陪护</text>
|
||||
<view class="tab-line" wx:if="{{activeTab === 1}}"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 陪诊服务 -->
|
||||
<view class="service-list" wx:if="{{activeTab === 0}}">
|
||||
<block wx:for="{{servicesPeizhen}}" wx:key="id">
|
||||
<view class="service-card" bindtap="onServiceTap" data-item="{{item}}">
|
||||
<view class="card-left">
|
||||
<view class="card-icon">
|
||||
<image src="{{item.icon || '/pages/image/empty.png'}}" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<view class="card-name">{{item.name}}</view>
|
||||
<view class="card-desc">{{item.desc}}</view>
|
||||
</view>
|
||||
<view class="card-right">
|
||||
<view class="card-price">¥{{item.price}}</view>
|
||||
<view class="card-btn">预约</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view wx:if="{{!servicesPeizhen.length}}" class="empty">
|
||||
<image src="/pages/image/empty.png" style="width:200rpx;height:200rpx;"></image>
|
||||
<text>暂无服务</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 陪护服务 -->
|
||||
<view class="service-list" wx:if="{{activeTab === 1}}">
|
||||
<block wx:for="{{servicesPeihu}}" wx:key="id">
|
||||
<view class="service-card" bindtap="onServiceTap" data-item="{{item}}">
|
||||
<view class="card-left">
|
||||
<view class="card-icon">
|
||||
<image src="{{item.icon || '/pages/image/empty.png'}}" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<view class="card-name">{{item.name}}</view>
|
||||
<view class="card-desc">{{item.desc}}</view>
|
||||
</view>
|
||||
<view class="card-right">
|
||||
<view class="card-price">¥{{item.price}}</view>
|
||||
<view class="card-btn">预约</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view wx:if="{{!servicesPeihu.length}}" class="empty">
|
||||
<image src="/pages/image/empty.png" style="width:200rpx;height:200rpx;"></image>
|
||||
<text>暂无服务</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
134
coupon/pages/service/service.wxss
Normal file
134
coupon/pages/service/service.wxss
Normal file
@@ -0,0 +1,134 @@
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: linear-gradient(135deg, #4A90D9, #357ABD);
|
||||
padding: 60rpx 40rpx 40rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header-sub {
|
||||
font-size: 24rpx;
|
||||
margin-top: 10rpx;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
padding: 0 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
color: #4A90D9;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tab-line {
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
background: #4A90D9;
|
||||
border-radius: 3rpx;
|
||||
margin: 8rpx auto 0;
|
||||
}
|
||||
|
||||
.service-list {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 28rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
.card-left {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #f0f4ff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-icon image {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.card-right {
|
||||
text-align: center;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.card-price {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #FF8F1F;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.card-btn {
|
||||
background: linear-gradient(135deg, #4A90D9, #357ABD);
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
padding: 8rpx 28rpx;
|
||||
border-radius: 30rpx;
|
||||
}
|
||||
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 160rpx;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
@@ -1,194 +1,62 @@
|
||||
//获取应用实例
|
||||
var app = getApp();
|
||||
const { request } = require('../../utils/request')
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
resp:{
|
||||
"currentPage": 1,
|
||||
"detail": [
|
||||
{
|
||||
"account_type_name": "微信提现",
|
||||
"money": "-5.79",
|
||||
"time": "2022-02-24 10:40:03",
|
||||
"type": "-1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "订单退款",
|
||||
"money": "0.01",
|
||||
"time": "2022-02-23 15:22:05",
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "购买商品",
|
||||
"money": "-0.01",
|
||||
"time": "2022-02-23 09:27:31",
|
||||
"type": "-1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "购买商品",
|
||||
"money": "-0.10",
|
||||
"time": "2022-02-22 11:48:20",
|
||||
"type": "-1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "订单退款",
|
||||
"money": "0.01",
|
||||
"time": "2022-02-18 16:31:09",
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "订单退款",
|
||||
"money": "0.01",
|
||||
"time": "2022-02-17 11:06:04",
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "订单退款",
|
||||
"money": "2.00",
|
||||
"time": "2022-02-17 10:59:13",
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "购买商品",
|
||||
"money": "-2.00",
|
||||
"time": "2022-02-16 10:31:46",
|
||||
"type": "-1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "订单退款",
|
||||
"money": "2.00",
|
||||
"time": "2022-02-16 10:25:33",
|
||||
"type": "1"
|
||||
},
|
||||
{
|
||||
"account_type_name": "购买商品",
|
||||
"money": "-2.00",
|
||||
"time": "2022-02-16 10:01:25",
|
||||
"type": "-1"
|
||||
}
|
||||
],
|
||||
"erro": 0,
|
||||
"lastPage": 6,
|
||||
"msg": "获取数据成功",
|
||||
"total": 52
|
||||
},
|
||||
order_list:[],
|
||||
order_list: [],
|
||||
navHeight: '',
|
||||
menuButtonInfo: {},
|
||||
searchMarginTop: 0, // 搜索框上边距
|
||||
searchWidth: 0, // 搜索框宽度
|
||||
searchHeight: 0 // 搜索框高度
|
||||
searchMarginTop: 0,
|
||||
searchWidth: 0,
|
||||
searchHeight: 0,
|
||||
firstLoad: true
|
||||
},
|
||||
back(){
|
||||
|
||||
back() {
|
||||
wx.navigateBack()
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
|
||||
onLoad: function (options) {
|
||||
wx.setNavigationBarTitle({
|
||||
title: '我的钱包'
|
||||
})
|
||||
|
||||
wx.setNavigationBarTitle({ title: '我的钱包' })
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
this.getGoodsList();
|
||||
if (this.data.firstLoad) {
|
||||
this.setData({ firstLoad: false })
|
||||
this.getGoodsList()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
this.getGoodsList().finally(() => wx.stopPullDownRefresh())
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
},
|
||||
// 跳转详情
|
||||
activity(e){
|
||||
|
||||
activity(e) {
|
||||
if (e.currentTarget.dataset.id != 0) {
|
||||
console.log("你选择的课程id是"+e.currentTarget.dataset.id);
|
||||
wx.navigateTo({
|
||||
url: "/shopping/pages/goddess/goddess?id=" + e.currentTarget.dataset.id,
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
//商品列表
|
||||
|
||||
// 交易明细列表
|
||||
getGoodsList: function () {
|
||||
var that = this;
|
||||
|
||||
|
||||
//假数据
|
||||
if(this.data.resp.erro==0){
|
||||
that.setData({
|
||||
order_list:this.data.resp.detail
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
wx.request({
|
||||
url: app.buildUrl("/app/Goddesswechat/getCapitalDetails"),
|
||||
header: app.getRequestHeader(),
|
||||
method:'POST',
|
||||
return request({
|
||||
url: '/app/Goddesswechat/getCapitalDetails',
|
||||
method: 'POST',
|
||||
loading: true,
|
||||
data: {
|
||||
version_number: this.data.version_number,
|
||||
uid:wx.getStorageSync('uid'),
|
||||
token:wx.getStorageSync('token'),
|
||||
page:'1',
|
||||
page_size:10,
|
||||
},
|
||||
success: function (res) {
|
||||
var resp = res.data;
|
||||
console.log(resp+"=================dddddddddddddddddddddddddddddddddddddddddddd")
|
||||
console.log(resp.erro+"=================dddddddddddddddddddddddddddddddddddddddddddd")
|
||||
if(resp.erro==0){
|
||||
that.setData({
|
||||
order_list:resp.detail
|
||||
});
|
||||
uid: wx.getStorageSync('uid'),
|
||||
token: wx.getStorageSync('token'),
|
||||
page: '1',
|
||||
page_size: 10,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.erro === 0) {
|
||||
that.setData({ order_list: res.detail || [] })
|
||||
}
|
||||
});
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
})
|
||||
@@ -2,19 +2,19 @@
|
||||
<view class="order-list" wx:if="{{order_list.length}}">
|
||||
<view wx:for="{{order_list}}" wx:key="{{index}}" wx:for-item="item">
|
||||
<view class="Group" bindtap="activity" data-id="{{item.id}}">
|
||||
|
||||
|
||||
<view style="margin-left: 34rpx;">
|
||||
<view wx:if="{{item.type==1}}" class="title1">退款到账</view>
|
||||
<view wx:if="{{item.type==-1}}" class="title1">提现</view>
|
||||
<view class="title2">{{item.time}}</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view style="position: absolute;right: 24rpx;">
|
||||
<view class="Price1">¥{{item.money}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:else class="no-order" style="display:flex;flex-direction:column;align-items:center;padding-top:200rpx;">
|
||||
<image style="width:200rpx;height:200rpx;" src="/pages/image/empty.png"></image>
|
||||
<view style="color:#999;font-size:28rpx;margin-top:20rpx;">暂无交易记录</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,10 +1,8 @@
|
||||
const app = getApp()
|
||||
const { request } = require('../../../utils/request')
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
height: '',
|
||||
seckill_start: '请输入开始日期',
|
||||
@@ -26,175 +24,81 @@ Page({
|
||||
id: 0,
|
||||
order_id: '',
|
||||
timeData: {},
|
||||
Height: "", //这是swiper要动态设置的高度属性
|
||||
Height: "",
|
||||
charge_phone: '',
|
||||
is_ok_click: false,
|
||||
submitting: false,
|
||||
clock: '',
|
||||
address: '',
|
||||
danjia: 0.01,//单位为元
|
||||
danjia: 0.01,
|
||||
beizhu: '',
|
||||
},
|
||||
|
||||
|
||||
// 确认支付
|
||||
confirm_pay: async function () {
|
||||
var that = this;
|
||||
if (!this.data.is_ok_click) {
|
||||
that.setData({
|
||||
is_ok_click: true
|
||||
})
|
||||
//你要执行的操作
|
||||
confirm_pay() {
|
||||
if (this.data.submitting) return
|
||||
this.payment()
|
||||
setTimeout(function () {
|
||||
that.setData({
|
||||
is_ok_click: false
|
||||
})
|
||||
}, 10000) //阻止一秒点击多次
|
||||
} else {
|
||||
// wx.showToast({ title:'请勿重复操作!', icon: 'none' });
|
||||
}
|
||||
},
|
||||
//获取单价
|
||||
getprice: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/config/configKey/price',
|
||||
header: app.getRequestHeader(),
|
||||
method: 'GET',
|
||||
data: {},
|
||||
success: (res) => {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
special_offer: resp.data,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取类型
|
||||
getpriceType: function () {
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/config/configKey/priceType',
|
||||
header: app.getRequestHeader(),
|
||||
method: 'GET',
|
||||
data: {},
|
||||
success: (res) => {
|
||||
var resp = res.data;
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
special_offer: resp.data,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
payment() {
|
||||
|
||||
async payment() {
|
||||
if (this.data.seckill_start == "请输入开始日期") {
|
||||
wx.showToast({
|
||||
title: '请输入开始日期',
|
||||
icon: 'none'
|
||||
});
|
||||
wx.showToast({ title: '请选择开始日期', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (this.data.seckill_endx == "请输入结束日期") {
|
||||
wx.showToast({
|
||||
title: '请输入结束日期',
|
||||
icon: 'none'
|
||||
});
|
||||
wx.showToast({ title: '请选择结束日期', icon: 'none' })
|
||||
return
|
||||
}
|
||||
var that = this;
|
||||
wx.request({
|
||||
url: app.globalData.url + '/system/order',
|
||||
// 校验日期先后
|
||||
var start = new Date(this.data.seckill_start.replace(/-/g, "/"))
|
||||
var end = new Date(this.data.seckill_endx.replace(/-/g, "/"))
|
||||
if (end < start) {
|
||||
wx.showToast({ title: '结束日期不能早于开始日期', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({ submitting: true })
|
||||
try {
|
||||
var res = await request({
|
||||
url: '/system/order',
|
||||
method: 'POST',
|
||||
loading: true,
|
||||
loadingText: '提交订单中...',
|
||||
data: {
|
||||
startTime: this.data.seckill_start,
|
||||
endTime: this.data.seckill_endx,
|
||||
bId: this.data.item.userId,
|
||||
yuguMoney: this.data.paymoney,
|
||||
price: this.data.danjia,//
|
||||
priceType: "1",//1是按天
|
||||
price: this.data.danjia,
|
||||
priceType: "1",
|
||||
hospitalId: this.data.item.hospitalId,
|
||||
cId: wx.getStorageSync('uid'),
|
||||
remark: this.data.beizhu,
|
||||
},
|
||||
method: 'POST',
|
||||
header: {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer ' + app.getCache("token")
|
||||
},
|
||||
success(res) {
|
||||
if (res.data.code == 200) {
|
||||
that.setData({
|
||||
order_id: res.data.data.orderId,
|
||||
header: { 'content-type': 'application/json' }
|
||||
})
|
||||
console.log('order_id==' + res.data.data.orderId)
|
||||
app.console(that.data.order_id + "======要传的order_id")
|
||||
wx.navigateTo({
|
||||
url: '/shopping/pages/paysuccess/paysuccess?' + "order_id=" + that.data.order_id,
|
||||
});
|
||||
// console.log('timeStamp==' + res.data.data.timeStamp)
|
||||
// console.log('nonceStr==' + res.data.data.nonceStr)
|
||||
// console.log('package==' + res.data.data.package)
|
||||
// console.log('signType==' + res.data.data.signType)
|
||||
// console.log('paySign==' + res.data.data.paySign)
|
||||
// wx.requestPayment({
|
||||
// timeStamp: res.data.data.timeStamp,
|
||||
// nonceStr: res.data.data.nonceStr,
|
||||
// package: res.data.data.package,
|
||||
// signType: res.data.data.signType,
|
||||
// paySign: res.data.data.paySign,
|
||||
// success(res) {
|
||||
// console.log('支付成功');
|
||||
// app.console(that.data.order_id + "======要传的order_id")
|
||||
// wx.navigateTo({
|
||||
// url: '/shopping/pages/paysuccess/paysuccess?' + "order_id=" + that.data.order_id,
|
||||
// });
|
||||
// },
|
||||
// fail(res) {
|
||||
// console.log('支付失败');
|
||||
// }
|
||||
// })
|
||||
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: res.data.msg,
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
wx.redirectTo({
|
||||
url: '/shopping/pages/paysuccess/paysuccess?order_id=' + res.data.orderId,
|
||||
})
|
||||
} catch (e) {
|
||||
this.setData({ submitting: false })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
bindDateChange: function (e) {
|
||||
this.setData({
|
||||
seckill_start: e.detail.value
|
||||
})
|
||||
this.setData({ seckill_start: e.detail.value })
|
||||
},
|
||||
bindDateChangetwo: function (e) {
|
||||
this.setData({
|
||||
seckill_endx: e.detail.value,
|
||||
})
|
||||
this.setData({ seckill_endx: e.detail.value })
|
||||
var day = this.checkDate()
|
||||
var totalmoney = this.data.danjia* day;
|
||||
var money = totalmoney.toFixed(2)
|
||||
this.setData({
|
||||
paymoney: money
|
||||
})
|
||||
var money = (this.data.danjia * day).toFixed(2)
|
||||
this.setData({ paymoney: money })
|
||||
},
|
||||
checkDate: function () {
|
||||
//日期格式化
|
||||
var start_date = new Date(this.data.seckill_start.replace(/-/g, "/"));
|
||||
var end_date = new Date(this.data.seckill_endx.replace(/-/g, "/"));
|
||||
//转成毫秒数,两个日期相减
|
||||
var ms = end_date.getTime() - start_date.getTime();
|
||||
//转换成天数
|
||||
var day = parseInt(ms / (1000 * 60 * 60 * 24));
|
||||
//do something
|
||||
console.log("day = ", day);
|
||||
return day + 1
|
||||
return Math.max(day + 1, 0)
|
||||
},
|
||||
onClickLeft() {
|
||||
wx.navigateBack()
|
||||
@@ -242,9 +146,6 @@ Page({
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
var that = this;
|
||||
this.getprice();
|
||||
this.getpriceType();
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
const config = {
|
||||
// 开发环境(本地后端,需改为本机IP)
|
||||
// baseUrl: 'http://192.168.1.100:8039',
|
||||
// 生产环境
|
||||
baseUrl: 'http://101.43.95.130:8039',
|
||||
// 生产环境(通过 nginx 代理,HTTPS + 域名)
|
||||
baseUrl: 'https://ruilaizipj.com/prod-api',
|
||||
}
|
||||
|
||||
module.exports = config
|
||||
|
||||
89
coupon/utils/request.js
Normal file
89
coupon/utils/request.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 通用网络请求工具
|
||||
* - 自动 loading / hideLoading
|
||||
* - 自动 fail 错误提示
|
||||
* - Promise 风格,支持 async/await
|
||||
* - code != 200 自动 toast 并 reject
|
||||
*/
|
||||
const app = getApp()
|
||||
|
||||
// 请求计数,支持并发 loading
|
||||
let requestCount = 0
|
||||
|
||||
/**
|
||||
* @param {object} opts
|
||||
* @param {string} opts.url - API 路径(不含 baseUrl)
|
||||
* @param {string} opts.method - GET/POST,默认 GET
|
||||
* @param {object} opts.data - 请求参数
|
||||
* @param {boolean} opts.loading - 是否显示 loading,默认 true
|
||||
* @param {string} opts.loadingText - loading 文案,默认 "加载中..."
|
||||
* @param {boolean} opts.showError - 失败时是否自动 toast,默认 true
|
||||
* @param {object} opts.header - 自定义 header(会合并默认 header)
|
||||
* @returns {Promise<object>} res.data - 响应体 { code, msg, data }
|
||||
*/
|
||||
function request(opts) {
|
||||
const {
|
||||
url,
|
||||
method = 'GET',
|
||||
data = {},
|
||||
loading = true,
|
||||
loadingText = '加载中...',
|
||||
showError = true,
|
||||
header = {}
|
||||
} = opts
|
||||
|
||||
if (loading) {
|
||||
if (requestCount === 0) {
|
||||
wx.showLoading({ title: loadingText, mask: true })
|
||||
}
|
||||
requestCount++
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: app.globalData.url + url,
|
||||
method,
|
||||
data,
|
||||
header: {
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
'Authorization': 'Bearer ' + app.getCache('token'),
|
||||
...header
|
||||
},
|
||||
success(res) {
|
||||
if (res.data.code === 200) {
|
||||
resolve(res.data)
|
||||
} else {
|
||||
if (showError) {
|
||||
wx.showToast({
|
||||
title: res.data.msg || '请求失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
reject(res.data)
|
||||
}
|
||||
},
|
||||
fail(err) {
|
||||
if (showError) {
|
||||
wx.showToast({
|
||||
title: '网络异常,请稍后重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
reject(err)
|
||||
},
|
||||
complete() {
|
||||
if (loading) {
|
||||
requestCount--
|
||||
if (requestCount <= 0) {
|
||||
requestCount = 0
|
||||
wx.hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { request }
|
||||
68
docs/SpringSecurity权限配置踩坑记录.md
Normal file
68
docs/SpringSecurity权限配置踩坑记录.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Spring Security anonymous() vs permitAll() 踩坑记录
|
||||
|
||||
## 现象
|
||||
|
||||
后台管理系统登录后,访问 `业务管理 > 医院管理` 页面提示"系统接口异常",后端返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-05-25T03:08:28.944+08:00",
|
||||
"status": 403,
|
||||
"error": "Forbidden",
|
||||
"path": "/system/hospital/list"
|
||||
}
|
||||
```
|
||||
|
||||
直接用 curl 不带 token 调用接口正常返回 200,但带上 JWT token 就返回 403。
|
||||
|
||||
## 根因
|
||||
|
||||
`SecurityConfig.java` 中 `/system/hospital/list` 被配置为 `.anonymous()`:
|
||||
|
||||
```java
|
||||
.antMatchers("/login", ..., "/system/hospital/list", ...).anonymous()
|
||||
```
|
||||
|
||||
**Spring Security 中两种访问控制的区别:**
|
||||
|
||||
| 配置 | 含义 | 匿名用户 | 已认证用户 |
|
||||
|------|------|----------|------------|
|
||||
| `.permitAll()` | 所有用户均可访问 | 允许 | 允许 |
|
||||
| `.anonymous()` | 仅匿名用户可访问 | 允许 | **拒绝(403)** |
|
||||
|
||||
当后台管理员登录后,JWT 过滤器为请求注入了认证信息(不再是匿名用户),Spring Security 判定已认证用户无权访问 `.anonymous()` 资源,返回 403。
|
||||
|
||||
而小程序端调用该接口时不带 token(匿名),所以一直正常。
|
||||
|
||||
## 修复
|
||||
|
||||
将需要同时被"小程序(匿名)"和"后台(已认证)"访问的接口,从 `.anonymous()` 移至 `.permitAll()`:
|
||||
|
||||
```java
|
||||
// 仅匿名用户 —— 登录、注册、验证码等
|
||||
.antMatchers("/login","/appLogin","/system/msm","/smsLogin",
|
||||
"/register","/captchaImage","/weixinLogin","/getUserToken",
|
||||
"/system/weixin/wxPayNotify","/system/weixin/wxRefundNotify")
|
||||
.anonymous()
|
||||
|
||||
// 所有用户均可访问 —— 被小程序和后台共同使用的数据接口
|
||||
.antMatchers("/system/user/getAppIndexInfo","/system/hospital/list",
|
||||
"/system/config/configKey/**","/system/nursing/published",
|
||||
"/system/nursing/view/**","/system/serviceType/enabled")
|
||||
.permitAll()
|
||||
```
|
||||
|
||||
## 经验总结
|
||||
|
||||
1. **`.anonymous()` 是排他性的** —— 已登录用户访问会直接 403,不要用于需要同时支持前台和后台的 API
|
||||
2. **`.permitAll()` vs `.anonymous()`** 选择标准:
|
||||
- 登录/注册页面等"仅限未登录用户" → `.anonymous()`
|
||||
- 公开数据接口(小程序+后台共用) → `.permitAll()`
|
||||
3. **排查 403 时先看 SecurityConfig** —— 即使 API 直接 curl 正常,带 token 就可能因认证状态不同而变化
|
||||
4. **排查思路**:逐层验证 API → 数据库 → 菜单路由 → Nginx 代理 → Security 权限配置
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `rlz/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java`
|
||||
- `rlz-ui/src/views/system/hospital/index.vue`
|
||||
- `rlz-ui/src/utils/request.js` (前端错误拦截器)
|
||||
19
docs/service_type_migration.sql
Normal file
19
docs/service_type_migration.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- 服务类型表增加 icon 字段
|
||||
ALTER TABLE rlz_service_type ADD COLUMN IF NOT EXISTS icon VARCHAR(255) DEFAULT '' COMMENT '服务图标URL';
|
||||
|
||||
-- 插入默认服务数据(如无数据)
|
||||
INSERT INTO rlz_service_type (name, category, type_code, price, description, status, sort_order)
|
||||
SELECT '全程陪诊', '2', '1', 200.00, '服务内容:排队 预约 挂号 缴费 取药 记录医嘱', '0', 1
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rlz_service_type WHERE type_code = '1');
|
||||
|
||||
INSERT INTO rlz_service_type (name, category, type_code, price, description, status, sort_order)
|
||||
SELECT '诊前约号', '2', '2', 20.00, '服务内容:协助办理完成挂号', '0', 2
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rlz_service_type WHERE type_code = '2');
|
||||
|
||||
INSERT INTO rlz_service_type (name, category, type_code, price, description, status, sort_order)
|
||||
SELECT '取送结果', '2', '3', 50.00, '服务内容:包括给病人或者家属取检查报告化验单等', '0', 3
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rlz_service_type WHERE type_code = '3');
|
||||
|
||||
INSERT INTO rlz_service_type (name, category, type_code, price, description, status, sort_order)
|
||||
SELECT '代办问诊', '2', '4', 100.00, '服务内容:使用病人或者家属取检查报告化验单向医生问明情况', '0', 4
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rlz_service_type WHERE type_code = '4');
|
||||
195
docs/商业化评估报告.md
Normal file
195
docs/商业化评估报告.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# 瑞来健康陪诊平台 — 商业化评估报告
|
||||
|
||||
> 评估日期:2026-05-25
|
||||
> 评估范围:后端(Spring Boot)、管理后台(Vue2)、Android App、微信小程序
|
||||
|
||||
---
|
||||
|
||||
## 一、项目现状总览
|
||||
|
||||
| 维度 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 技术栈 | 可维护 | Java 8 / Spring Boot 2.5.14 / Vue 2.6 / MyBatis / MySQL / 微信原生小程序 / Android Java |
|
||||
| 部署 | 已跑通 | Tencent Cloud CVM + CynosDB + Docker Compose + Nginx |
|
||||
| 后台管理 | 较完整 | RuoYi-Vue 框架,含医院/订单/财务/服务类型/护理资讯管理 |
|
||||
| 微信小程序 | 部分完成 | 14 页面 + 3 Tab,核心流程可走,但存在假数据和空壳页面 |
|
||||
| Android App | 需重构 | 从家装项目改造而来,遗留大量无关代码 |
|
||||
| 安全性 | **不达标** | 支付密钥硬编码、JWT 弱密钥、手机号明文存储等多项致命问题 |
|
||||
|
||||
---
|
||||
|
||||
## 二、安全问题(P0 — 商用前必须解决)
|
||||
|
||||
### 2.1 致命级
|
||||
|
||||
| # | 问题 | 位置 | 风险 |
|
||||
|---|------|------|------|
|
||||
| 1 | 微信支付 RSA 私钥 + APIv3 Key 硬编码在源码中 | `WXPayConstantsAAA.java:23-50`、`PaySign.java:25-52`、`SysWeixinPayControllerNewBBBBB.java:34-42` | 源码泄露 = 资金被盗 |
|
||||
| 2 | JWT 签名密钥 `abcdefghijklmnopqrstuvwxyz` | `application.yml:96` | 可暴力破解,伪造任意用户 Token |
|
||||
| 3 | 短信接口无限流保护 | `MsmController.java` — 全平台零限流 | 可被刷短信,造成资损 |
|
||||
|
||||
### 2.2 高级
|
||||
|
||||
| # | 问题 | 位置 | 风险 |
|
||||
|---|------|------|------|
|
||||
| 4 | 手机号明文存储 + API 返回明文 + `System.out.print` 打印 | `sys_user.phonenumber`、`SysLoginController.java:76,123`、`MsmController.java:34` | 用户隐私泄露 |
|
||||
| 5 | SMS 验证码明文打印到控制台 | `MsmController.java:46` | 验证码泄露 |
|
||||
| 6 | 操作日志表 `sys_oper_log` 记录完整请求体(含密码、手机号) | `LogAspect.java:142-154` | 日志库成为敏感数据泄露源 |
|
||||
| 7 | WeChat AppSecret 硬编码在 URL 参数中 | `SysLoginController.java:178,226` | AppSecret 泄露 |
|
||||
| 8 | Android WeChat AppSecret 硬编码 | `WXEntryActivity.java:46` | AppSecret 泄露 |
|
||||
|
||||
### 2.3 中级
|
||||
|
||||
| # | 问题 | 位置 | 风险 |
|
||||
|---|------|------|------|
|
||||
| 9 | Druid 监控面板生产环境公开可访问(无 IP 白名单) | `SecurityConfig.java:116`、`application-docker.yml:53` | 数据库连接池信息暴露 |
|
||||
| 10 | Swagger API 文档生产环境公开 | `application.yml:118`、`SecurityConfig.java:116` | API 结构暴露 |
|
||||
| 11 | CSRF 全局关闭 + `X-Frame-Options` 关闭 | `SecurityConfig.java:104,120` | CSRF / 点击劫持风险 |
|
||||
| 12 | ~95% 接口 `@PreAuthorize` 被注释 | 全平台 Controller | 任意认证用户可调用任意接口,无细粒度权限控制 |
|
||||
|
||||
---
|
||||
|
||||
## 三、小程序功能缺陷(P1)
|
||||
|
||||
| # | 页面 | 问题 | 影响 |
|
||||
|---|------|------|------|
|
||||
| 1 | `reforderdetail` 退款订单详情 | **全假数据**,真实 API 调用被整段注释 | 退款流程完全不可用 |
|
||||
| 2 | `tuiguang/extensionInfor` 推广页 | **完全空壳**,所有生命周期函数为空 | 推广模块不存在 |
|
||||
| 3 | `guanyu/guanyu` 关于/反馈页 | 表单提交调用不存在的函数 `this.payment()` | 反馈功能不可用 |
|
||||
| 4 | `mechanism/mechanism` 机构页 | 机构详情跳转到不存在的 `pages/institutions/institutions` | 机构详情 404 |
|
||||
| 5 | `peizhen/peizhen` + `peihu/peihu` | 医院选择器数据硬编码(不从后台接口读取) | 数据不实时 |
|
||||
| 6 | `index/index` | 服务价格硬编码(200/20/100/50) | 调价需改代码发版 |
|
||||
| 7 | `myshoucang/myshoucang_index` | 收藏列表全假数据 | 收藏功能不可用 |
|
||||
| 8 | `my/my` | 砍价功能写死"暂无开放" | 营销功能缺失 |
|
||||
| 9 | `orderdetail/orderdetail` | 客服电话硬编码 `18133233292` | 换号需改代码 |
|
||||
| 10 | 全页面 | 错误处理均为 `.catch(() => {})` 静默吞错 | 用户无错误反馈 |
|
||||
|
||||
---
|
||||
|
||||
## 四、Android App 问题(P2)
|
||||
|
||||
| # | 问题 |
|
||||
|---|------|
|
||||
| 1 | 含大量原家装项目遗留代码(`DesignActivity`、`StyleActivity`、`Douyin` 接口等) |
|
||||
| 2 | 两套并行网络层:Retrofit(`MyApi.java`)+ OkHttp(`NetApi.java`),架构混乱 |
|
||||
| 3 | `API.java` 引用已废弃的 Bmob 云后端,含硬编码测试密钥 |
|
||||
| 4 | 引用 `/device/AppCustomer/*`、`/device/AppDouyin/*` 等可能不存在的接口 |
|
||||
| 5 | 包名和类名仍保留原产品命名(`kehu`、`find`、`goddess` 等) |
|
||||
|
||||
---
|
||||
|
||||
## 五、基础设施缺失(P3)
|
||||
|
||||
| # | 问题 |
|
||||
|---|------|
|
||||
| 1 | 无自动化数据库备份策略 |
|
||||
| 2 | 无日志聚合 / 监控告警系统 |
|
||||
| 3 | 自定义建表 SQL(`rlz_order`、`sys_hospital` 等)未入仓 |
|
||||
| 4 | 无 Staging 测试环境 |
|
||||
| 5 | CI/CD 仅覆盖后端 Docker 构建,小程序和 Android 无自动化 |
|
||||
| 6 | 数据库 `rlz_order` 表使用 20 个通用字段 `yuliu1~20`,Schema 不透明 |
|
||||
|
||||
---
|
||||
|
||||
## 六、数据库问题
|
||||
|
||||
| # | 表 | 问题 |
|
||||
|---|------|------|
|
||||
| 1 | `rlz_order` | 20 个 `yuliu1`~`yuliu20` 通用 varchar 列,无文档说明 |
|
||||
| 2 | `rlz_order` / `sys_hospital` / `rlz_service_type` 等 | 建表 DDL 未入仓(仅 `ry_20220625.sql` + `nursing_article.sql` 在 repo 中) |
|
||||
| 3 | `order_view` / `hospital_user_view` / `user_hospital_view` | 视图 DDL 未入仓 |
|
||||
| 4 | `sys_user.phonenumber` | 手机号明文存储,无加密 |
|
||||
| 5 | `sys_oper_log` | 存储完整请求/响应 JSON,含密码和手机号 |
|
||||
|
||||
---
|
||||
|
||||
## 七、开发工作量估算
|
||||
|
||||
### 方案 A:最小可用方案(安全整改 + 关键缺陷修复)— 3~4 个月
|
||||
|
||||
| 阶段 | 工作内容 | 人月 |
|
||||
|------|----------|------|
|
||||
| 安全整改 | 密钥迁移环境变量、JWT 加固、全接口限流、日志脱敏、Druid/Swagger 生产关闭 | 1.5 |
|
||||
| 小程序修复 | 退款页/推广页/关于页/机构页修复、硬编码改为接口调用、错误状态完善 | 1.5 |
|
||||
| 基础设施 | 备份策略、基础监控告警 | 0.5 |
|
||||
| 全流程测试 | 回归测试 | 0.5 |
|
||||
| **合计** | | **4 人月** |
|
||||
|
||||
> 2 人团队 × 2 个月,费用约 **8~15 万 RMB**
|
||||
|
||||
---
|
||||
|
||||
### 方案 B:完整商用方案 — 6~8 个月
|
||||
|
||||
| 阶段 | 工作内容 | 人月 |
|
||||
|------|----------|------|
|
||||
| 安全整改 | 同上 + 敏感数据加密存储 + 渗透测试 + 等保咨询 | 2 |
|
||||
| 小程序完整修复 | 全部页面真实接口、通知推送、图文混排优化 | 2 |
|
||||
| 功能补全 | 营销模块(砍价/拼团)、收藏、反馈系统、CMS 完善 | 1.5 |
|
||||
| Android 重构 | 移除遗留代码、统一网络层、端到端测试 | 2 |
|
||||
| 基础设施 | CI/CD 全流程、监控告警、日志平台、多环境管理、灾备方案 | 1 |
|
||||
| 合规 + 文档 | 隐私政策、用户协议、数据删除/导出、运维文档 | 1 |
|
||||
| 测试 | 全平台回归 + 性能压测 | 1 |
|
||||
| **合计** | | **10.5 人月** |
|
||||
|
||||
> 2~3 人团队 × 4~6 个月,费用约 **25~50 万 RMB**
|
||||
|
||||
---
|
||||
|
||||
## 八、运维费用估算(月度)
|
||||
|
||||
| 项目 | 规格 | 费用(元/月) |
|
||||
|------|------|---------------|
|
||||
| 腾讯云 CVM | 4C8G | 300 ~ 600 |
|
||||
| CynosDB MySQL | 按量 | 500 ~ 2,000 |
|
||||
| 带宽 + CDN | 按量 | 200 ~ 800 |
|
||||
| 域名 | ruilaizipj.com | ~10 |
|
||||
| 微信小程序认证 | 年付 300 | 25 |
|
||||
| 微信商户手续费 | 0.6% 交易额 | 按交易量 |
|
||||
| 短信服务 | 验证码 + 通知 | 100 ~ 500 |
|
||||
| SSL 证书 | Let's Encrypt | 0 |
|
||||
| 云监控基础版 | - | 200 ~ 500 |
|
||||
| 对象存储 COS | 图片/文件 | 50 ~ 300 |
|
||||
| **月度合计** | | **约 1,500 ~ 5,000** |
|
||||
|
||||
---
|
||||
|
||||
## 九、数据合规要求(中国法律)
|
||||
|
||||
陪诊平台属于医疗健康相关服务,涉及用户敏感个人信息,需关注:
|
||||
|
||||
| 法规 | 要求 | 当前状态 |
|
||||
|------|------|----------|
|
||||
| 《个人信息保护法》 | 收集用户信息需明确告知 + 获取同意 | 小程序无隐私弹窗 |
|
||||
| 《个人信息保护法》 | 敏感个人信息(医疗健康、行踪轨迹)需单独同意 | 未实现 |
|
||||
| 《个人信息保护法》 | 用户有权查阅/更正/删除/导出其个人信息 | 未实现 |
|
||||
| 《网络安全法》 | 网络运营者应采取技术措施保障信息安全 | 多项安全问题未解决 |
|
||||
| 《数据安全法》 | 重要数据处理者需定期风险评估 | 无 |
|
||||
| 等保 2.0 | 医疗健康类系统至少等保二级 | 未做 |
|
||||
| 微信小程序运营规范 | 涉及医疗健康需提供相关资质 | 需确认 |
|
||||
|
||||
---
|
||||
|
||||
## 十、建议实施路径
|
||||
|
||||
```
|
||||
第 1 个月 ─── 安全整改(密钥管理 + 限流 + 日志脱敏 + 生产配置加固)
|
||||
第 2 个月 ─── 小程序缺陷修复(假数据 → 真接口 + 空壳页面补全)
|
||||
第 3 个月 ─── 基础设施(备份 + 监控 + CI/CD)+ 全流程测试
|
||||
第 4 个月 ─── 上线试运营,收集用户反馈
|
||||
第 5-6 个月 ─ 功能增强(营销模块、通知推送、数据看板)
|
||||
第 7-8 个月 ─ Android 重构 + 合规材料准备
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十一、总结
|
||||
|
||||
| | 方案 A(最小可用) | 方案 B(完整商用) |
|
||||
|------|------|------|
|
||||
| 开发周期 | 3 ~ 4 个月 | 6 ~ 8 个月 |
|
||||
| 开发费用 | 8 ~ 15 万 | 25 ~ 50 万 |
|
||||
| 月度运维 | 1,500 ~ 5,000 元 | 1,500 ~ 5,000 元 |
|
||||
| 交付水平 | 核心业务流程可运转 | 具备完整 SaaS 商业化能力 |
|
||||
|
||||
**最紧迫事项**:安全漏洞修复(支付密钥、JWT、限流)必须在任何商用推广前完成。源码一旦泄露,攻击者可直接操作微信支付。
|
||||
201
docs/域名与nginx配置方案.md
Normal file
201
docs/域名与nginx配置方案.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# 瑞来健康 — 域名与 Nginx 配置方案
|
||||
|
||||
> 日期:2026-05-24
|
||||
> 服务器:101.43.95.130
|
||||
> 现状:与"生长激素预测模型"项目共用服务器和域名 ruilaizipj.com
|
||||
|
||||
---
|
||||
|
||||
## 一、现状分析
|
||||
|
||||
### 1.1 域名占用
|
||||
|
||||
```
|
||||
ruilaizipj.com / www.ruilaizipj.com (80/443)
|
||||
└── host nginx (/etc/nginx/conf.d/default.conf)
|
||||
├── / → /www/wwwroot/code/public (ThinkPHP - 生长激素项目)
|
||||
└── /adminghd/ → ThinkPHP 后台管理
|
||||
```
|
||||
|
||||
### 1.2 RLZ 服务(Docker 内部)
|
||||
|
||||
| 服务 | 容器 | 内部端口 | 外部访问 |
|
||||
|------|------|---------|---------|
|
||||
| 后端 API | rlz-backend | 8039 | `http://101.43.95.130:8039` |
|
||||
| 管理后台 | rlz-ui-server | 80 | `http://101.43.95.130:8050` |
|
||||
| Redis | rlz-redis | 6379 | 127.0.0.1:6379 |
|
||||
|
||||
### 1.3 微信小程序约束
|
||||
|
||||
微信小程序已在微信后台登记 `https://ruilaizipj.com` 作为合法 API 域名,不能更改。
|
||||
|
||||
### 1.4 RLZ API 路径前缀
|
||||
|
||||
- 后台管理:`/dev-api/`(由前端 `VUE_APP_BASE_API` 控制)
|
||||
- 微信小程序/Android:`/prod-api/`(直接请求后端路径)
|
||||
|
||||
---
|
||||
|
||||
## 二、方案设计
|
||||
|
||||
### 2.1 核心思路
|
||||
|
||||
**API 走主域名路径代理,管理后台走子域名。**
|
||||
|
||||
- 小程序 API → 主域名路径 `/prod-api/*`(不改微信登记,与 ThinkPHP 无冲突)
|
||||
- 管理后台 → 子域名 `admin.ruilaizipj.com`(SPA 路由清爽,独立 server 块)
|
||||
|
||||
### 2.2 目标架构
|
||||
|
||||
```
|
||||
101.43.95.130 (host nginx 80/443)
|
||||
│
|
||||
┌─────────────────────────┼─────────────────────────┐
|
||||
│ │ │
|
||||
ruilaizipj.com ruilaizipj.com admin.ruilaizipj.com
|
||||
(生长激素) (RLZ API) (RLZ 管理后台)
|
||||
│ │ │
|
||||
/ → code/public /prod-api/* / → rlz-ui-server
|
||||
/adminghd/ /dev-api/* (127.0.0.1:8050)
|
||||
│ (127.0.0.1:8039)
|
||||
▼ │
|
||||
ThinkPHP 5.0 ▼
|
||||
(PHP-FPM) rlz-backend
|
||||
(Spring Boot)
|
||||
```
|
||||
|
||||
### 2.3 SSL 证书
|
||||
|
||||
当前 Let's Encrypt 证书覆盖 `ruilaizipj.com` + `www.ruilaizipj.com`。
|
||||
|
||||
需要新增 `admin.ruilaizipj.com` 的 SAN 覆盖。两种方式:
|
||||
- **方式 A**:宝塔面板 → 网站 → SSL → 重新签发(添加子域名)
|
||||
- **方式 B**:手动 certbot 扩展
|
||||
|
||||
推荐方式 A,宝塔自动续期。
|
||||
|
||||
---
|
||||
|
||||
## 三、实施步骤
|
||||
|
||||
### Step 1:DNS 添加子域名
|
||||
|
||||
在域名 DNS 管理后台添加记录:
|
||||
```
|
||||
admin.ruilaizipj.com → A → 101.43.95.130
|
||||
```
|
||||
|
||||
### Step 2:扩展 SSL 证书
|
||||
|
||||
通过宝塔面板重新签发证书,添加 `admin.ruilaizipj.com` 到域名列表。
|
||||
|
||||
### Step 3:修改 host nginx 配置
|
||||
|
||||
编辑 `/etc/nginx/conf.d/default.conf`,在现有 server 块中新增:
|
||||
|
||||
```nginx
|
||||
# === 现有 ThinkPHP 配置保持不变 ===
|
||||
|
||||
# 新增:RLZ 后端 API 代理
|
||||
location /prod-api/ {
|
||||
proxy_pass http://127.0.0.1:8039/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
location /dev-api/ {
|
||||
proxy_pass http://127.0.0.1:8039/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
```
|
||||
|
||||
新建 `/etc/nginx/conf.d/rlz-admin.conf`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name admin.ruilaizipj.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name admin.ruilaizipj.com;
|
||||
|
||||
ssl_certificate /www/server/panel/vhost/cert/101.43.95.130/fullchain.pem;
|
||||
ssl_certificate_key /www/server/panel/vhost/cert/101.43.95.130/privkey.pem;
|
||||
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8050;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
location /prod-api/ {
|
||||
proxy_pass http://127.0.0.1:8039/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4:验证
|
||||
|
||||
```bash
|
||||
# 重载 nginx
|
||||
nginx -t && nginx -s reload
|
||||
|
||||
# 测试 API
|
||||
curl -s https://ruilaizipj.com/prod-api/captchaImage
|
||||
|
||||
# 测试管理后台
|
||||
curl -s -o /dev/null -w "%{http_code}" https://admin.ruilaizipj.com/
|
||||
```
|
||||
|
||||
### Step 5:更新前端配置
|
||||
|
||||
- `rlz-ui/.env.production`:`VUE_APP_BASE_API` 改为 `/prod-api`
|
||||
- 微信小程序 `config.js`:`baseUrl` 改为 `https://ruilaizipj.com/prod-api`
|
||||
- Android `BuildConfig`:Release 的 `API_BASE_URL` 改为 `https://ruilaizipj.com/prod-api`
|
||||
|
||||
---
|
||||
|
||||
## 四、访问地址总览(实施后)
|
||||
|
||||
| 端 | 地址 |
|
||||
|------|------|
|
||||
| 管理后台 | `https://admin.ruilaizipj.com` |
|
||||
| 后端 API | `https://ruilaizipj.com/prod-api/` |
|
||||
| 微信小程序 API | `https://ruilaizipj.com/prod-api/` |
|
||||
| 生长激素项目(不变) | `https://www.ruilaizipj.com` |
|
||||
| 生长激素后台(不变) | `https://www.ruilaizipj.com/adminghd/` |
|
||||
|
||||
---
|
||||
|
||||
## 五、注意事项
|
||||
|
||||
1. **不要改 `server_name` 的 ThinkPHP 部分**,否则影响生长激素项目正常运行
|
||||
2. **nginx 修改前备份**:`cp /etc/nginx/conf.d/default.conf /tmp/default.conf.bak`
|
||||
3. **宝塔可能覆盖 nginx 配置**,修改后注意观察
|
||||
4. **API 路径冲突检查**:确认 ThinkPHP 项目没有 `/prod-api/` 或 `/dev-api/` 路由
|
||||
5. **RLZ 前端的 `VUE_APP_BASE_API` 需要同步更新**为 `/prod-api` 并重新构建部署
|
||||
235
docs/服务项目管理动态化方案.md
Normal file
235
docs/服务项目管理动态化方案.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# 服务项目管理动态化方案
|
||||
|
||||
> 日期:2026-05-25
|
||||
> 目标:将小程序端硬编码的服务项目改为后台动态配置,支持上架/下架/调价/排序
|
||||
|
||||
---
|
||||
|
||||
## 一、现状分析
|
||||
|
||||
### 1.1 现有基础设施(已存在,可直接使用)
|
||||
|
||||
| 组件 | 状态 | 位置 |
|
||||
|------|------|------|
|
||||
| 数据库表 `rlz_service_type` | 已有 | MySQL |
|
||||
| 实体类 `RlzServiceType` | 已有 | `ruoyi-system/.../domain/RlzServiceType.java` |
|
||||
| Mapper / Service / Controller | 已有 | CRUD + 分页 + Excel 导出 |
|
||||
| 价格变更历史 `rlz_price_history` | 已有 | 调价自动记录操作人/时间/原因 |
|
||||
| 管理后台 Vue 页面 | 已有 | `rlz-ui/src/views/system/serviceType/index.vue` |
|
||||
|
||||
### 1.2 现有字段
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | Long | 主键 |
|
||||
| name | String | 服务名称 |
|
||||
| category | String | 类别: 1=陪护, 2=陪诊 |
|
||||
| typeCode | String | 类型编码 |
|
||||
| price | BigDecimal | 价格 |
|
||||
| description | String | 服务内容描述 |
|
||||
| status | String | 0=启用, 1=停用 |
|
||||
| sortOrder | Integer | 排序(越小越靠前) |
|
||||
| createBy/createTime | - | 创建信息 |
|
||||
| updateBy/updateTime | - | 更新信息 |
|
||||
| remark | String | 备注 |
|
||||
|
||||
### 1.3 当前问题
|
||||
|
||||
小程序端服务项目全部硬编码:
|
||||
|
||||
- `pages/index/index.js:13-41` — 4 个服务项,价格写死(200/20/100/50)
|
||||
- `pages/peizhen/peizhen.js:26-56` — 陪诊服务列表写死
|
||||
- `pages/peihu/peihu.js` — 陪护服务列表写死
|
||||
- 图标通过 `../image/home/{{item.icon}}.png` 本地引用,无法动态配置
|
||||
|
||||
---
|
||||
|
||||
## 二、改造方案
|
||||
|
||||
### 2.1 数据库变更
|
||||
|
||||
`rlz_service_type` 表新增 `icon` 字段:
|
||||
|
||||
```sql
|
||||
ALTER TABLE rlz_service_type ADD COLUMN icon VARCHAR(255) DEFAULT '' COMMENT '服务图标URL';
|
||||
```
|
||||
|
||||
### 2.2 后端变更
|
||||
|
||||
#### a) 实体新增 icon 字段
|
||||
|
||||
`RlzServiceType.java` 增加 `private String icon;` 及 getter/setter。
|
||||
|
||||
#### b) Mapper XML 更新
|
||||
|
||||
`RlzServiceTypeMapper.xml` 的 resultMap / SQL / insert / update 中增加 icon 字段。
|
||||
|
||||
#### c) 新增小程序公开接口
|
||||
|
||||
```java
|
||||
// 无需登录,返回所有启用状态的服务
|
||||
@GetMapping("/enabled")
|
||||
public AjaxResult enabled(RlzServiceType rlzServiceType)
|
||||
{
|
||||
rlzServiceType.setStatus("0"); // 只查启用的
|
||||
List<RlzServiceType> list = rlzServiceTypeService
|
||||
.selectRlzServiceTypeList(rlzServiceType);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
```
|
||||
|
||||
#### d) SecurityConfig 白名单
|
||||
|
||||
```java
|
||||
.antMatchers("/system/serviceType/enabled").permitAll()
|
||||
```
|
||||
|
||||
### 2.3 管理后台变更
|
||||
|
||||
`rlz-ui/src/views/system/serviceType/index.vue`:
|
||||
|
||||
- 表格增加"图标"列(显示缩略图)
|
||||
- 新增/编辑表单增加图标上传组件
|
||||
- 增加"上架/下架"快捷操作按钮
|
||||
|
||||
### 2.4 小程序变更
|
||||
|
||||
#### index.js(首页 4 个服务卡片)
|
||||
|
||||
```
|
||||
修改前:data.itemView = [{ icon: "全程陪诊", title: "全程陪诊", price: "200", ... }]
|
||||
修改后:onShow 调用 /system/serviceType/enabled?category=2 获取陪诊服务列表
|
||||
```
|
||||
|
||||
#### peizhen.js(陪诊页)
|
||||
|
||||
```
|
||||
修改前:services = [{ name: "全程陪诊", price: "200" }, ...]
|
||||
修改后:调用 /system/serviceType/enabled?category=2 动态加载
|
||||
```
|
||||
|
||||
#### peihu.js(陪护页)
|
||||
|
||||
```
|
||||
修改前:services 硬编码
|
||||
修改后:调用 /system/serviceType/enabled?category=1 动态加载
|
||||
```
|
||||
|
||||
#### WXML 图标引用
|
||||
|
||||
```xml
|
||||
<!-- 修改前(本地图片) -->
|
||||
<image src="../image/home/{{item.icon}}.png" mode="aspectFit"></image>
|
||||
|
||||
<!-- 修改后(远程URL) -->
|
||||
<image src="{{item.icon}}" mode="aspectFit"></image>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、数据流
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 管理后台 (Vue Admin) │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 服务类型管理 │ │
|
||||
│ │ [新增] [编辑] [删除] [调价] [上架/下架] │ │
|
||||
│ │ ┌──────┬──────┬──────┬──────┬──────┐ │ │
|
||||
│ │ │ 图标 │ 名称 │ 类别 │ 价格 │ 状态 │ │ │
|
||||
│ │ ├──────┼──────┼──────┼──────┼──────┤ │ │
|
||||
│ │ │ 🏥 │全程陪诊│陪诊 │ 200 │ 启用 │ │ │
|
||||
│ │ │ 📋 │诊前约号│陪诊 │ 20 │ 启用 │ │ │
|
||||
│ │ │ 💊 │代办买药│陪诊 │ 80 │ 停用 │ │ │
|
||||
│ │ └──────┴──────┴──────┴──────┴──────┘ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │ POST/PUT/DELETE │
|
||||
│ ▼ (需登录 + 权限) │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 后端 Controller: /system/serviceType/* │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 微信小程序 │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ /system/serviceType/enabled?category=2 │ │
|
||||
│ │ [公开接口,无需登录] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │ GET │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 返回: [{ name:"全程陪诊", price:200, icon:"...", │ │
|
||||
│ │ description:"排队预约挂号...", status:"0" │ │
|
||||
│ │ sortOrder:1 }, ...] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 首页服务卡片区域 动态渲染 │ │
|
||||
│ │ [全程陪诊] [诊前约号] [代办买药] [取送结果] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、实现步骤
|
||||
|
||||
| 步骤 | 内容 | 涉及文件 |
|
||||
|------|------|----------|
|
||||
| 1 | 数据库加 `icon` 字段 | DDL |
|
||||
| 2 | 实体 + Mapper 更新 | `RlzServiceType.java`, `RlzServiceTypeMapper.xml` |
|
||||
| 3 | Controller 增加 `/enabled` 公开接口 | `RlzServiceTypeController.java` |
|
||||
| 4 | SecurityConfig 加白名单 | `SecurityConfig.java` |
|
||||
| 5 | 管理后台增加图标字段 | `serviceType/index.vue` |
|
||||
| 6 | 小程序首页改为 API 加载 | `index.js`, `index.wxml` |
|
||||
| 7 | 小程序陪诊页改为 API 加载 | `peizhen.js`, `peizhen.wxml` |
|
||||
| 8 | 小程序陪护页改为 API 加载 | `peihu.js`, `peihu.wxml` |
|
||||
| 9 | 部署后端 + 测试 | Docker 构建部署 |
|
||||
|
||||
---
|
||||
|
||||
## 五、接口设计
|
||||
|
||||
### GET /system/serviceType/enabled
|
||||
|
||||
无需登录,根据 category 返回已启用的服务列表。
|
||||
|
||||
**请求参数:**
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| category | String | 否 | 1=陪护, 2=陪诊,不传则返回全部 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "全程陪诊",
|
||||
"category": "2",
|
||||
"typeCode": "1",
|
||||
"price": 200.00,
|
||||
"description": "排队预约挂号缴费取药记录医嘱",
|
||||
"icon": "https://ruilaizipj.com/profile/upload/icon_peizhen.png",
|
||||
"status": "0",
|
||||
"sortOrder": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "诊前约号",
|
||||
"category": "2",
|
||||
"typeCode": "2",
|
||||
"price": 20.00,
|
||||
"description": "协助办理完成挂号",
|
||||
"icon": "https://ruilaizipj.com/profile/upload/icon_yuehao.png",
|
||||
"status": "0",
|
||||
"sortOrder": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
256
docs/陪诊员服务费分账方案.md
Normal file
256
docs/陪诊员服务费分账方案.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# 陪诊员服务费分账方案(A+B 结合)
|
||||
|
||||
## 一、需求概述
|
||||
|
||||
订单完成后,将服务费按比例分配给平台和陪诊员,实现自动计算 + 人工审核确认的结算流程。
|
||||
|
||||
## 二、业务流程
|
||||
|
||||
```
|
||||
订单完成(status=3,待支付)
|
||||
→ 患者微信支付
|
||||
→ 支付成功(status=4,已完成)
|
||||
→ 系统自动计算分账金额(根据配置的抽成比例)
|
||||
→ 写入结算金额到订单字段
|
||||
→ 管理员后台审核确认
|
||||
→ 陪诊员余额增加(yue)、累计收益更新(leijijine)
|
||||
→ 生成交易记录(jiaoyi_detail)
|
||||
→ 订单标记为已结算(status=8)
|
||||
```
|
||||
|
||||
## 三、数据库改动
|
||||
|
||||
### 3.1 新增平台配置表 `rlz_platform_config`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | bigint | PK |
|
||||
| `config_key` | varchar(50) | 配置键 |
|
||||
| `config_value` | varchar(255) | 配置值 |
|
||||
| `description` | varchar(200) | 描述 |
|
||||
| `create_time` | datetime | 创建时间 |
|
||||
| `update_time` | datetime | 更新时间 |
|
||||
|
||||
初始化数据:
|
||||
```sql
|
||||
INSERT INTO rlz_platform_config (config_key, config_value, description) VALUES
|
||||
('commission_rate', '20', '平台抽成比例(%)'),
|
||||
('auto_settle', 'false', '是否自动结算(true/false)');
|
||||
```
|
||||
|
||||
### 3.2 现有表字段利用
|
||||
|
||||
`rlz_order` 表已有字段(无需改动):
|
||||
- `jiesuan_money` — 结算金额(订单总金额)
|
||||
- `kouchu_money` — 平台抽成金额
|
||||
- `fanxian_money` — 陪诊员所得金额
|
||||
- `fanxian_tax` — 抽成比例(%)
|
||||
- `is_zhifu` — 打款状态(0=未打款, 1=已打款)
|
||||
|
||||
`sys_user` 表已有字段(无需改动):
|
||||
- `yue` — 余额(陪诊员可用余额)
|
||||
- `leijijine` — 累计收益
|
||||
|
||||
`jiaoyi_detail` 表已有字段(无需改动):
|
||||
- `type` — 1=收入, 2=支出
|
||||
- `jine` — 金额
|
||||
- `name` — 交易名称
|
||||
- `yue` — 交易后余额
|
||||
- `user_id` — 用户ID
|
||||
|
||||
## 四、后端实现
|
||||
|
||||
### 4.1 新增类文件
|
||||
|
||||
| 类 | 路径 | 职责 |
|
||||
|----|------|------|
|
||||
| `RlzPlatformConfig.java` | `domain/` | 平台配置实体 |
|
||||
| `RlzPlatformConfigMapper.java` | `mapper/` | 配置 Mapper |
|
||||
| `RlzPlatformConfigMapper.xml` | `mapper/system/` | 配置 SQL |
|
||||
| `IRlzPlatformConfigService.java` | `service/` | 配置服务接口 |
|
||||
| `RlzPlatformConfigServiceImpl.java` | `service/impl/` | 配置服务实现 |
|
||||
| `RlzSettlementService.java` | `service/` | 结算服务(核心逻辑) |
|
||||
| `RlzSettlementController.java` | `controller/` | 结算接口 |
|
||||
| `RlzTransactionController.java` | `controller/` | 交易记录查询接口 |
|
||||
|
||||
### 4.2 核心服务 RlzSettlementService
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class RlzSettlementService {
|
||||
|
||||
// 获取抽成比例(默认20%)
|
||||
public BigDecimal getCommissionRate() {
|
||||
String rate = platformConfigService.getConfigValue("commission_rate", "20");
|
||||
return new BigDecimal(rate);
|
||||
}
|
||||
|
||||
// 订单支付成功后自动计算分账
|
||||
public void calculateOrderFee(RlzOrder order) {
|
||||
BigDecimal totalAmount = new BigDecimal(order.getYuguMoney());
|
||||
BigDecimal rate = getCommissionRate(); // 20%
|
||||
BigDecimal kouchu = totalAmount.multiply(rate).divide(new BigDecimal("100")); // 平台抽成
|
||||
BigDecimal fanxian = totalAmount.subtract(kouchu); // 陪诊员所得
|
||||
|
||||
order.setJiesuanMoney(order.getYuguMoney()); // 结算金额=订单金额
|
||||
order.setKouchuMoney(kouchu.toString()); // 平台抽成
|
||||
order.setFanxianMoney(fanxian.toString()); // 陪诊员所得
|
||||
order.setFanxianTax(rate.toString()); // 抽成比例
|
||||
order.setIsZhifu("0"); // 未打款
|
||||
rlzOrderService.updateOrder(order);
|
||||
}
|
||||
|
||||
// 管理员确认结算(打款给陪诊员)
|
||||
@Transactional
|
||||
public void settleOrder(Long orderId) {
|
||||
RlzOrder order = rlzOrderService.selectRlzOrderById(orderId);
|
||||
if (!"4".equals(order.getStatus())) {
|
||||
throw new BusinessException("订单未支付,无法结算");
|
||||
}
|
||||
if ("1".equals(order.getIsZhifu())) {
|
||||
throw new BusinessException("已打款,请勿重复操作");
|
||||
}
|
||||
|
||||
Long caregiverId = order.getBId(); // 陪诊员ID
|
||||
BigDecimal fanxianMoney = new BigDecimal(order.getFanxianMoney());
|
||||
|
||||
// 1. 更新订单打款状态
|
||||
order.setIsZhifu("1");
|
||||
order.setStatus("8"); // 已结算
|
||||
rlzOrderService.updateOrder(order);
|
||||
|
||||
// 2. 更新陪诊员余额和累计收益
|
||||
SysUser caregiver = sysUserService.selectUserById(caregiverId);
|
||||
BigDecimal oldBalance = new BigDecimal(caregiver.getYue() != null ? caregiver.getYue() : "0");
|
||||
BigDecimal newBalance = oldBalance.add(fanxianMoney);
|
||||
caregiver.setYue(newBalance.toString());
|
||||
|
||||
BigDecimal oldTotal = new BigDecimal(caregiver.getLeijijine() != null ? caregiver.getLeijijine() : "0");
|
||||
caregiver.setLeijijine(oldTotal.add(fanxianMoney).toString());
|
||||
sysUserService.updateUser(caregiver);
|
||||
|
||||
// 3. 生成交易记录
|
||||
insertTransaction(caregiverId, fanxianMoney, newBalance, order.getYuliu1());
|
||||
}
|
||||
|
||||
private void insertTransaction(Long userId, BigDecimal jine, BigDecimal newBalance, String orderNo) {
|
||||
JiaoyiDetail detail = new JiaoyiDetail();
|
||||
detail.setUserId(userId);
|
||||
detail.setType("1"); // 收入
|
||||
detail.setJine(jine.toString());
|
||||
detail.setYue(newBalance.toString());
|
||||
detail.setName("订单结算 - " + orderNo);
|
||||
jiaoyiDetailService.insertJiaoyiDetail(detail);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 结算接口 RlzSettlementController
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/system/settlement")
|
||||
public class RlzSettlementController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private RlzSettlementService settlementService;
|
||||
|
||||
// 支付回调中自动触发计算(在 WxPayNotify 中调用)
|
||||
// 此处提供手动重新计算的接口
|
||||
|
||||
// 管理员确认结算
|
||||
@PostMapping("/settle/{orderId}")
|
||||
public AjaxResult settle(@PathVariable Long orderId) {
|
||||
settlementService.settleOrder(orderId);
|
||||
return AjaxResult.success("结算完成");
|
||||
}
|
||||
|
||||
// 批量结算
|
||||
@PostMapping("/batchSettle")
|
||||
public AjaxResult batchSettle(@RequestBody Long[] orderIds) {
|
||||
for (Long id : orderIds) {
|
||||
settlementService.settleOrder(id);
|
||||
}
|
||||
return AjaxResult.success("批量结算完成");
|
||||
}
|
||||
|
||||
// 查询待结算订单列表(status=4 已支付但未打款)
|
||||
@GetMapping("/pending")
|
||||
public TableDataInfo pending() {
|
||||
// 查询 status=4 AND is_zhifu='0' 的订单
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 支付回调中自动触发计算
|
||||
|
||||
在 `WxPayNotify` 处理中增加一行调用:
|
||||
|
||||
```java
|
||||
// 支付成功,更新 status=4
|
||||
order.setStatus("4");
|
||||
// ... 存储微信交易号 ...
|
||||
rlzOrderService.updateOrder(order);
|
||||
|
||||
// === 新增:自动计算分账金额 ===
|
||||
settlementService.calculateOrderFee(order);
|
||||
```
|
||||
|
||||
## 五、后台管理面板改动
|
||||
|
||||
### 5.1 新增菜单
|
||||
|
||||
| 父菜单 | 菜单名称 | 路径 | 组件 |
|
||||
|--------|----------|------|------|
|
||||
| 财务管理(3000) | 结算管理 | `settlement` | `finance/settlement/index` |
|
||||
| 财务管理(3000) | 交易明细 | `transaction` | `finance/transaction/index` |
|
||||
| 财务管理(3000) | 平台配置 | `platformConfig` | `finance/platformConfig/index` |
|
||||
|
||||
### 5.2 结算管理页面 `finance/settlement/index.vue`
|
||||
|
||||
功能:
|
||||
- 列表展示已支付待结算订单
|
||||
- 搜索:订单号、陪诊员姓名、日期范围
|
||||
- 列:订单号、陪诊员、订单金额、平台抽成、应发金额、支付时间、状态
|
||||
- 操作:单个结算 / 批量结算
|
||||
- 点击结算弹出确认框,显示分账明细预览
|
||||
|
||||
### 5.3 平台配置页面 `finance/platformConfig/index.vue`
|
||||
|
||||
功能:
|
||||
- 平台抽成比例设置(默认20%)
|
||||
- 自动结算开关(暂不启用)
|
||||
|
||||
## 六、SecurityConfig 更新
|
||||
|
||||
```java
|
||||
// 新增匿名访问(若小程序也需要查询余额/交易记录)
|
||||
// 结算接口需要认证(仅后台管理员操作)
|
||||
.antMatchers("/system/settlement/**", "/system/transaction/**").authenticated()
|
||||
```
|
||||
|
||||
## 七、实施步骤
|
||||
|
||||
| 步骤 | 内容 | 预估 |
|
||||
|------|------|------|
|
||||
| 1 | 创建 `rlz_platform_config` 表 + 初始化数据 | 10min |
|
||||
| 2 | 创建配置管理后端代码(CRUD) | 20min |
|
||||
| 3 | 实现 `RlzSettlementService` 核心分账逻辑 | 30min |
|
||||
| 4 | 在支付回调中集成自动计算 | 10min |
|
||||
| 5 | 创建结算管理后台页面 | 30min |
|
||||
| 6 | 创建平台配置后台页面 | 20min |
|
||||
| 7 | 部署、测试完整流程 | 20min |
|
||||
|
||||
## 八、分账示例
|
||||
|
||||
假设平台抽成比例 20%,订单金额 500 元:
|
||||
|
||||
| 项目 | 金额 | 计算 |
|
||||
|------|------|------|
|
||||
| 订单金额 | 500.00 | 患者支付 |
|
||||
| 平台抽成(20%) | 100.00 | 500 × 20% |
|
||||
| 陪诊员所得 | 400.00 | 500 × 80% |
|
||||
| 陪诊员余额变化 | +400.00 | yue += 400 |
|
||||
|
||||
管理员可在后台"平台配置"中调整抽成比例,新比例对后续订单生效。
|
||||
@@ -14,14 +14,6 @@ android {
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true //突破应用方法数65535的一个限制
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file('july.jks')
|
||||
storePassword "july"
|
||||
keyAlias "123456"
|
||||
keyPassword "123456"
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file('ruilaizi.jks')
|
||||
@@ -39,7 +31,7 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
release {
|
||||
// 生产环境 —— 连接公网服务器
|
||||
// 生产环境 —— 通过域名访问
|
||||
buildConfigField "String", "API_BASE_URL", '"http://101.43.95.130:8039"'
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
|
||||
<application
|
||||
android:name=".BaseApplication"
|
||||
@@ -45,6 +46,13 @@
|
||||
android:roundIcon="@mipmap/fw_logo"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<!-- 微信支付回调Activity -->
|
||||
<activity
|
||||
android:name=".wxapi.WXPayEntryActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||||
|
||||
<activity android:name=".main.my.activity.ShimingActivity"
|
||||
android:windowSoftInputMode="adjustPan"
|
||||
>
|
||||
|
||||
@@ -116,14 +116,14 @@ public class BaseApplication extends Application {
|
||||
|
||||
//https相关设置,以下几种方案根据需要自己设置
|
||||
//方法一:信任所有证书,不安全有风险
|
||||
HttpsUtils.SSLParams sslParams1 = HttpsUtils.getSslSocketFactory();
|
||||
//HttpsUtils.SSLParams sslParams1 = HttpsUtils.getSslSocketFactory();
|
||||
//方法二:自定义信任规则,校验服务端证书
|
||||
HttpsUtils.SSLParams sslParams2 = HttpsUtils.getSslSocketFactory(new SafeTrustManager());
|
||||
//方法三:使用预埋证书,校验服务端证书(自签名证书)
|
||||
//HttpsUtils.SSLParams sslParams3 = HttpsUtils.getSslSocketFactory(getAssets().open("srca.cer"));
|
||||
//方法四:使用bks证书和密码管理客户端证书(双向认证),使用预埋证书,校验服务端证书(自签名证书)
|
||||
//HttpsUtils.SSLParams sslParams4 = HttpsUtils.getSslSocketFactory(getAssets().open("xxx.bks"), "123456", getAssets().open("yyy.cer"));
|
||||
builder.sslSocketFactory(sslParams1.sSLSocketFactory, sslParams1.trustManager);
|
||||
builder.sslSocketFactory(sslParams2.sSLSocketFactory, sslParams2.trustManager);
|
||||
//配置https的域名匹配规则,详细看demo的初始化介绍,不需要就不要加入,使用不当会导致https握手失败
|
||||
builder.hostnameVerifier(new SafeHostnameVerifier());
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.view.WindowManager;
|
||||
|
||||
import com.ruilaizi.service.base.BaseActivity;
|
||||
import com.ruilaizi.service.utils.ToastUtils;
|
||||
import com.ruilaizi.service.utils.checkVersionsUtils.ProfileSpUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
@@ -69,13 +70,11 @@ public class SplashActivity extends BaseActivity implements EasyPermissions.Perm
|
||||
|
||||
|
||||
private void startActivity() {
|
||||
if (ProfileSpUtils.getInstance().isLogin()) {
|
||||
startActivity(MainActivity.class);
|
||||
//此类逻辑有是否登录,没有登录则跳验证码登录
|
||||
// if (ProfileSpUtils.getInstance().isLogin()) {
|
||||
// startActivity(MainActivity.class);
|
||||
// } else {
|
||||
// startActivity(LoginPasswordActivity.class);
|
||||
// }
|
||||
} else {
|
||||
startActivity(LoginPasswordActivity.class);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
@@ -88,9 +87,13 @@ public class SplashActivity extends BaseActivity implements EasyPermissions.Perm
|
||||
|
||||
@AfterPermissionGranted(RC_CAMERA_AND_LOCATION)
|
||||
private void methodRequiresTwoPermission() {
|
||||
String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
, Manifest.permission.CAMERA
|
||||
};
|
||||
String[] perms;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||
// Android 13+: WRITE_EXTERNAL_STORAGE 已废弃
|
||||
perms = new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES};
|
||||
} else {
|
||||
perms = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
|
||||
}
|
||||
if (EasyPermissions.hasPermissions(this, perms)) {
|
||||
|
||||
handler.sendEmptyMessageDelayed(0, 2000);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruilaizi.service.main.activity.mvp.presenterImpl;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.lzy.okgo.OkGo;
|
||||
import com.lzy.okgo.model.HttpParams;
|
||||
import com.lzy.okgo.model.Response;
|
||||
import com.ruilaizi.service.main.activity.MainActivity;
|
||||
@@ -77,9 +78,14 @@ public class LoginPasswordPresenterImpl extends MvpBasePresenter<LoginPasswordCo
|
||||
}
|
||||
|
||||
getView().showProgressDialog("登录中...");
|
||||
// 清除旧的全局 Authorization header,否则 Spring Security 会拒绝登录请求
|
||||
com.lzy.okgo.model.HttpHeaders commonHeaders = OkGo.getInstance().getCommonHeaders();
|
||||
if (commonHeaders != null) {
|
||||
commonHeaders.remove("Authorization");
|
||||
}
|
||||
final HttpParams paramsPost = new HttpParams();
|
||||
paramsPost.put("username", "admin");
|
||||
paramsPost.put("password", "123456");
|
||||
paramsPost.put("username", mobile);
|
||||
paramsPost.put("password", passWord);
|
||||
new NetApi().getPostData(paramsPost, HttpConstants.URi_appLogin).subscribe(new Observer<Response>() {
|
||||
@Override
|
||||
public void onNext(Response response) {
|
||||
|
||||
@@ -13,6 +13,7 @@ public class kehuListBean extends BaseModel {
|
||||
private int code;
|
||||
private String msg;
|
||||
private List<KehuinfoBean> data;
|
||||
private List<KehuinfoBean> rows;
|
||||
|
||||
public int getTotal() {
|
||||
return total;
|
||||
@@ -39,13 +40,21 @@ public class kehuListBean extends BaseModel {
|
||||
}
|
||||
|
||||
public List<KehuinfoBean> getData() {
|
||||
return data;
|
||||
return rows != null ? rows : data;
|
||||
}
|
||||
|
||||
public void setData(List<KehuinfoBean> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public List<KehuinfoBean> getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void setRows(List<KehuinfoBean> rows) {
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
// public static class DataBean extends BaseObservable implements Serializable {
|
||||
// private Object searchValue;
|
||||
// private Object createBy;
|
||||
|
||||
@@ -231,7 +231,7 @@ public class CanFragment extends MobanFragment {
|
||||
public void onNext(Response response) {
|
||||
String body = (String) response.body();
|
||||
kehuListBean data = JsonUtils.fromJson(body, kehuListBean.class);
|
||||
if (data.getCode() == 200) {
|
||||
if (data.getCode() == 200 || data.getCode() == 0) {
|
||||
List<KehuinfoBean> data1 = data.getData();
|
||||
mSwl.setRefreshing(false);
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ public class ComFragment extends MobanFragment {
|
||||
public void onNext(Response response) {
|
||||
String body = (String) response.body();
|
||||
kehuListBean data = JsonUtils.fromJson(body, kehuListBean.class);
|
||||
if (data.getCode() == 200) {
|
||||
if (data.getCode() == 200 || data.getCode() == 0) {
|
||||
List<KehuinfoBean> data1 = data.getData();
|
||||
mSwl.setRefreshing(false);
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ public class CustomerFragment extends MobanFragment {
|
||||
public void onNext(Response response) {
|
||||
String body = (String) response.body();
|
||||
kehuListBean data = JsonUtils.fromJson(body, kehuListBean.class);
|
||||
if (data.getCode() == 200) {
|
||||
if (data.getCode() == 200 || data.getCode() == 0) {
|
||||
List<KehuinfoBean> data1 = data.getData();
|
||||
mSwl.setRefreshing(false);
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ public class SerFragment extends MobanFragment {
|
||||
public void onNext(Response response) {
|
||||
String body = (String) response.body();
|
||||
kehuListBean data = JsonUtils.fromJson(body, kehuListBean.class);
|
||||
if (data.getCode() == 200) {
|
||||
if (data.getCode() == 200 || data.getCode() == 0) {
|
||||
List<KehuinfoBean> data1 = data.getData();
|
||||
mSwl.setRefreshing(false);
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ public class TobeSerFragment extends MobanFragment {
|
||||
public void onNext(Response response) {
|
||||
String body = (String) response.body();
|
||||
kehuListBean data = JsonUtils.fromJson(body, kehuListBean.class);
|
||||
if (data.getCode() == 200) {
|
||||
if (data.getCode() == 200 || data.getCode() == 0) {
|
||||
List<KehuinfoBean> data1 = data.getData();
|
||||
mSwl.setRefreshing(false);
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ import com.zhihu.matisse.MimeType;
|
||||
import com.zhihu.matisse.engine.impl.PicassoEngine;
|
||||
import com.zhihu.matisse.internal.entity.CaptureStrategy;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -123,7 +127,7 @@ public class ShimingActivity extends BaseActivity {
|
||||
toast("请输入姓名");
|
||||
return;
|
||||
}
|
||||
if("".equals(recFollowBean.getRealName())){
|
||||
if("".equals(recFollowBean.getIdentityNo())){
|
||||
toast("请输入身份证号");
|
||||
return;
|
||||
}
|
||||
@@ -197,10 +201,43 @@ public class ShimingActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将图片文件压缩后转为 base64,限制最大宽度并控制 JPEG 质量
|
||||
*/
|
||||
private String compressAndToBase64(File file, int maxWidth) {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
|
||||
int sampleSize = 1;
|
||||
int width = options.outWidth;
|
||||
if (width > 0) {
|
||||
while (width / sampleSize > maxWidth) {
|
||||
sampleSize *= 2;
|
||||
}
|
||||
}
|
||||
options.inJustDecodeBounds = false;
|
||||
options.inSampleSize = sampleSize;
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
|
||||
if (bitmap == null) {
|
||||
return "";
|
||||
}
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);
|
||||
bitmap.recycle();
|
||||
return "data:image/jpg;base64," + android.util.Base64.encodeToString(baos.toByteArray(), android.util.Base64.NO_WRAP);
|
||||
}
|
||||
|
||||
private void getPermissions() {
|
||||
|
||||
RxPermissions rxPermissions = new RxPermissions(this);
|
||||
rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
|
||||
String[] permissions;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||
// Android 13+: WRITE_EXTERNAL_STORAGE 已废弃,需用 READ_MEDIA_IMAGES
|
||||
permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES};
|
||||
} else {
|
||||
permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE};
|
||||
}
|
||||
rxPermissions.request(permissions)
|
||||
.subscribe(new io.reactivex.Observer<Boolean>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
@@ -287,10 +324,9 @@ public class ShimingActivity extends BaseActivity {
|
||||
|
||||
@Override
|
||||
public void onSuccess(File file) {
|
||||
//转换成功后的文件
|
||||
String resultt = AbImageUtil.bitmapToBase64(ImageUtils.getBitmap(file));
|
||||
uploadPic(resultt,0);
|
||||
|
||||
showProgressDialog("上传中...", ShimingActivity.this);
|
||||
String resultt = compressAndToBase64(file, 600);
|
||||
uploadPic(resultt, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -327,10 +363,9 @@ public class ShimingActivity extends BaseActivity {
|
||||
|
||||
@Override
|
||||
public void onSuccess(File file) {
|
||||
//转换成功后的文件
|
||||
String resultt = AbImageUtil.bitmapToBase64(ImageUtils.getBitmap(file));
|
||||
|
||||
uploadPic(resultt,1);
|
||||
showProgressDialog("上传中...", ShimingActivity.this);
|
||||
String resultt = compressAndToBase64(file, 1200);
|
||||
uploadPic(resultt, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -367,9 +402,9 @@ public class ShimingActivity extends BaseActivity {
|
||||
|
||||
@Override
|
||||
public void onSuccess(File file) {
|
||||
//转换成功后的文件
|
||||
String resultt = AbImageUtil.bitmapToBase64(ImageUtils.getBitmap(file));
|
||||
uploadPic(resultt,2);
|
||||
showProgressDialog("上传中...", ShimingActivity.this);
|
||||
String resultt = compressAndToBase64(file, 1200);
|
||||
uploadPic(resultt, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -105,6 +105,8 @@ public class loginBean implements Serializable {
|
||||
private String leijijine;
|
||||
private String yue;
|
||||
private String token;
|
||||
private String monthIncome;
|
||||
private String monthOrderCount;
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
@@ -169,5 +171,21 @@ public class loginBean implements Serializable {
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getMonthIncome() {
|
||||
return monthIncome;
|
||||
}
|
||||
|
||||
public void setMonthIncome(String monthIncome) {
|
||||
this.monthIncome = monthIncome;
|
||||
}
|
||||
|
||||
public String getMonthOrderCount() {
|
||||
return monthOrderCount;
|
||||
}
|
||||
|
||||
public void setMonthOrderCount(String monthOrderCount) {
|
||||
this.monthOrderCount = monthOrderCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ public class ViewHolderOne extends AbstractViewTypeHolder {
|
||||
@Override
|
||||
public void bindHolder(robCustomerInfoBean dataBean, int position, Context mContext, MarKQuestionItemviewOnClickListener mviewListener) {
|
||||
super.bindHolder(dataBean, position, mContext, mviewListener);
|
||||
WidgetTools.setTextsev(my_shouru, "", ProfileSpUtils.getInstance().getUserProfie().getData().getYue());
|
||||
WidgetTools.setTextsev(my_dingdan_num, "", ProfileSpUtils.getInstance().getUserProfie().getData().getYue());
|
||||
WidgetTools.setTextsev(my_shouru, "", ProfileSpUtils.getInstance().getUserProfie().getData().getMonthIncome());
|
||||
WidgetTools.setTextsev(my_dingdan_num, "", ProfileSpUtils.getInstance().getUserProfie().getData().getMonthOrderCount());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.tencent.mm.opensdk.modelbase.BaseReq;
|
||||
import com.tencent.mm.opensdk.modelbase.BaseResp;
|
||||
import com.tencent.mm.opensdk.openapi.IWXAPI;
|
||||
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
|
||||
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -57,11 +58,10 @@ public class WXPayEntryActivity extends BaseActivity implements IWXAPIEventHandl
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
initData();
|
||||
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
// api = WXAPIFactory.createWXAPI(this, PayUtils.APP_ID);
|
||||
api = WXAPIFactory.createWXAPI(this, WXEntryActivity.WEIXIN_APP_ID, true);
|
||||
api.handleIntent(getIntent(), this);
|
||||
}
|
||||
|
||||
|
||||
BIN
rlz-ui-dist-new.tar.gz
Normal file
BIN
rlz-ui-dist-new.tar.gz
Normal file
Binary file not shown.
70
rlz-ui/src/api/finance/settlement.js
Normal file
70
rlz-ui/src/api/finance/settlement.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询待结算订单列表
|
||||
export function listPendingSettlement(query) {
|
||||
return request({
|
||||
url: '/system/settlement/pending',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 单个结算
|
||||
export function settleOrder(orderId) {
|
||||
return request({
|
||||
url: '/system/settlement/settle/' + orderId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 批量结算
|
||||
export function batchSettleOrder(orderIds) {
|
||||
return request({
|
||||
url: '/system/settlement/batchSettle',
|
||||
method: 'post',
|
||||
data: orderIds
|
||||
})
|
||||
}
|
||||
|
||||
// 查询平台配置列表
|
||||
export function listPlatformConfig(query) {
|
||||
return request({
|
||||
url: '/system/platformConfig/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取平台配置详情
|
||||
export function getPlatformConfig(id) {
|
||||
return request({
|
||||
url: '/system/platformConfig/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增平台配置
|
||||
export function addPlatformConfig(data) {
|
||||
return request({
|
||||
url: '/system/platformConfig',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改平台配置
|
||||
export function updatePlatformConfig(data) {
|
||||
return request({
|
||||
url: '/system/platformConfig',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除平台配置
|
||||
export function delPlatformConfig(id) {
|
||||
return request({
|
||||
url: '/system/platformConfig/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
146
rlz-ui/src/views/finance/platformConfig/index.vue
Normal file
146
rlz-ui/src/views/finance/platformConfig/index.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">删除</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="配置键" align="center" prop="configKey" width="180" />
|
||||
<el-table-column label="配置值" align="center" prop="configValue" width="180">
|
||||
<template slot-scope="scope">
|
||||
<el-tag type="warning" size="small">{{ scope.row.configValue }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" align="center" prop="description" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="更新时间" align="center" prop="updateTime" width="160">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.updateTime || scope.row.createTime || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog :title="dialogTitle" :visible.sync="dialogOpen" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="配置键" prop="configKey">
|
||||
<el-input v-model="form.configKey" placeholder="请输入配置键" :disabled="isEdit" />
|
||||
</el-form-item>
|
||||
<el-form-item label="配置值" prop="configValue">
|
||||
<el-input v-model="form.configValue" placeholder="请输入配置值" />
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" prop="description">
|
||||
<el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入描述" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="dialogOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listPlatformConfig, getPlatformConfig, addPlatformConfig, updatePlatformConfig, delPlatformConfig } from "@/api/finance/settlement";
|
||||
|
||||
export default {
|
||||
name: "PlatformConfig",
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
ids: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
showSearch: true,
|
||||
configList: [],
|
||||
dialogOpen: false,
|
||||
dialogTitle: "",
|
||||
isEdit: false,
|
||||
form: {},
|
||||
rules: {
|
||||
configKey: [{ required: true, message: "配置键不能为空", trigger: "blur" }],
|
||||
configValue: [{ required: true, message: "配置值不能为空", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listPlatformConfig({}).then(response => {
|
||||
this.configList = response.rows || response.data || [];
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id);
|
||||
this.single = selection.length !== 1;
|
||||
this.multiple = !selection.length;
|
||||
},
|
||||
reset() {
|
||||
this.form = {};
|
||||
},
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.dialogTitle = "新增配置";
|
||||
this.isEdit = false;
|
||||
this.dialogOpen = true;
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
this.dialogTitle = "修改配置";
|
||||
this.isEdit = true;
|
||||
getPlatformConfig(row.id).then(response => {
|
||||
this.form = response.data;
|
||||
this.dialogOpen = true;
|
||||
});
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.isEdit) {
|
||||
updatePlatformConfig(this.form).then(() => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.dialogOpen = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addPlatformConfig(this.form).then(() => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.dialogOpen = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
handleDelete(row) {
|
||||
const id = row.id || this.ids[0];
|
||||
if (!id) {
|
||||
this.$modal.msgWarning("请选择要删除的配置");
|
||||
return;
|
||||
}
|
||||
this.$modal.confirm('确认删除该配置?').then(() => {
|
||||
return delPlatformConfig(id);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,18 +1,8 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
||||
<el-form-item label="订单编号" prop="orderNumber">
|
||||
<el-input v-model="queryParams.orderNumber" placeholder="请输入订单编号" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="陪护姓名" prop="userbName">
|
||||
<el-input v-model="queryParams.userbName" placeholder="请输入陪护姓名" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结算状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="全部" :value="null" />
|
||||
<el-option label="待结算" value="4" />
|
||||
<el-option label="已结算" value="8" />
|
||||
</el-select>
|
||||
<el-form-item label="订单编号" prop="yuliu1">
|
||||
<el-input v-model="queryParams.yuliu1" placeholder="请输入订单编号" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
@@ -22,87 +12,56 @@
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
|
||||
<el-button type="warning" plain icon="el-icon-money" size="mini" :disabled="multiple" @click="handleBatchSettle">批量结算</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="orderList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="订单编号" align="center" prop="orderNumber" min-width="160" />
|
||||
<el-table-column label="患者" align="center" prop="usercName" width="100" />
|
||||
<el-table-column label="陪护" align="center" prop="userbName" width="100" />
|
||||
<el-table-column label="医院" align="center" prop="hospitalName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="结算金额" align="center" prop="jiesuanMoney" width="110">
|
||||
<el-table-column label="订单编号" align="center" prop="yuliu1" width="180" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="支付时间" align="center" prop="updateTime" width="160" />
|
||||
<el-table-column label="订单金额" align="center" width="120">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.jiesuanMoney || scope.row.yuguMoney || '-' }}
|
||||
<span style="color: #E6A23C; font-weight: bold;">¥{{ scope.row.jiesuanMoney || scope.row.yuguMoney || '0' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status" width="90">
|
||||
<el-table-column label="平台抽成" align="center" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="statusTagType(scope.row.status)" size="small">
|
||||
{{ statusMap[scope.row.status] || scope.row.status }}
|
||||
</el-tag>
|
||||
<span v-if="scope.row.kouchuMoney" style="color: #F56C6C;">¥{{ scope.row.kouchuMoney }}</span>
|
||||
<span v-else style="color: #C0C4CC;">待计算</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="完成时间" align="center" prop="endTime" width="160" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
|
||||
<el-table-column label="抽成比例" align="center" prop="fanxianTax" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="primary" icon="el-icon-bank-card" @click="handleSettle(scope.row)"
|
||||
v-if="scope.row.status == '4'">结算</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleDetail(scope.row)">详情</el-button>
|
||||
{{ scope.row.fanxianTax ? scope.row.fanxianTax + '%' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="应发金额" align="center" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span style="color: #67C23A; font-weight: bold;">¥{{ scope.row.fanxianMoney || '0' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="支付状态" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.isZhifu === '1'" type="success" size="small">已结算</el-tag>
|
||||
<el-tag v-else type="warning" size="small">待结算</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="scope.row.isZhifu !== '1'" size="mini" type="primary" @click="handleSettle(scope.row)">结算</el-button>
|
||||
<span v-else style="color: #67C23A;">已打款</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList" />
|
||||
|
||||
<!-- 结算对话框 -->
|
||||
<el-dialog title="订单结算" :visible.sync="dialogOpen" width="450px" append-to-body>
|
||||
<el-form ref="settleForm" :model="settleForm" :rules="settleRules" label-width="100px">
|
||||
<el-form-item label="订单编号">
|
||||
<span>{{ settleForm.orderNumber }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="陪护姓名">
|
||||
<span>{{ settleForm.userbName }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="结算金额" prop="jiesuanMoney">
|
||||
<el-input v-model="settleForm.jiesuanMoney" placeholder="请输入结算金额">
|
||||
<template slot="append">元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitSettle">确认结算</el-button>
|
||||
<el-button @click="dialogOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 详情对话框 -->
|
||||
<el-dialog title="订单详情" :visible.sync="detailOpen" width="650px" append-to-body>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="订单编号">{{ detail.orderNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="statusTagType(detail.status)" size="small">
|
||||
{{ statusMap[detail.status] || detail.status }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="患者">{{ detail.usercName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="陪护">{{ detail.userbName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="医院">{{ detail.hospitalName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="结算金额">{{ detail.jiesuanMoney || detail.yuguMoney || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="扣费">{{ detail.kouchuMoney || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="返现">{{ detail.fanxianMoney || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间" :span="2">{{ detail.createTime }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSettlementOrders, settleOrder } from "@/api/system/finance";
|
||||
import { getOrderInfo } from "@/api/system/order";
|
||||
import { listPendingSettlement, settleOrder, batchSettleOrder } from "@/api/finance/settlement";
|
||||
|
||||
export default {
|
||||
name: "Settlement",
|
||||
@@ -110,34 +69,25 @@ export default {
|
||||
return {
|
||||
loading: true,
|
||||
ids: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
showSearch: true,
|
||||
total: 0,
|
||||
orderList: [],
|
||||
dialogOpen: false,
|
||||
detailOpen: false,
|
||||
detail: {},
|
||||
settleForm: { orderId: null, orderNumber: '', userbName: '', jiesuanMoney: '' },
|
||||
settleRules: {
|
||||
jiesuanMoney: [{ required: true, message: '请输入结算金额', trigger: 'blur' }]
|
||||
},
|
||||
statusMap: { '4': '已完成', '8': '已结算' },
|
||||
queryParams: {
|
||||
pageNum: 1, pageSize: 10,
|
||||
orderNumber: null, userbName: null, status: null,
|
||||
}
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
yuliu1: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
statusTagType(status) {
|
||||
const map = { '4': 'success', '8': 'info' };
|
||||
return map[status] || '';
|
||||
},
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listSettlementOrders(this.queryParams).then(response => {
|
||||
listPendingSettlement(this.queryParams).then(response => {
|
||||
this.orderList = response.data;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
@@ -149,42 +99,34 @@ export default {
|
||||
},
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.orderId);
|
||||
this.single = selection.length !== 1;
|
||||
this.multiple = !selection.length;
|
||||
},
|
||||
handleSettle(row) {
|
||||
this.settleForm = {
|
||||
orderId: row.orderId,
|
||||
orderNumber: row.orderNumber,
|
||||
userbName: row.userbName,
|
||||
jiesuanMoney: row.jiesuanMoney || row.yuguMoney || ''
|
||||
};
|
||||
this.dialogOpen = true;
|
||||
},
|
||||
submitSettle() {
|
||||
this.$refs["settleForm"].validate(valid => {
|
||||
if (valid) {
|
||||
settleOrder(this.settleForm.orderId, {
|
||||
jiesuanMoney: this.settleForm.jiesuanMoney
|
||||
const orderId = row.orderId;
|
||||
this.$modal.confirm('确认结算该订单?将向陪诊员打款 ¥' + (row.fanxianMoney || '0')).then(() => {
|
||||
return settleOrder(orderId);
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess("结算成功");
|
||||
this.dialogOpen = false;
|
||||
this.getList();
|
||||
});
|
||||
this.$modal.msgSuccess("结算完成");
|
||||
}).catch(() => {});
|
||||
},
|
||||
handleBatchSettle() {
|
||||
if (this.ids.length === 0) {
|
||||
this.$modal.msgWarning("请选择订单");
|
||||
return;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleDetail(row) {
|
||||
getOrderInfo(row.orderId).then(response => {
|
||||
this.detail = response.data;
|
||||
this.detailOpen = true;
|
||||
});
|
||||
},
|
||||
handleExport() {
|
||||
this.download('system/view/export', { ...this.queryParams },
|
||||
`settlement_${new Date().getTime()}.xlsx`)
|
||||
this.$modal.confirm('确认批量结算 ' + this.ids.length + ' 个订单?').then(() => {
|
||||
return batchSettleOrder(this.ids);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("批量结算完成");
|
||||
}).catch(() => {});
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -94,6 +94,12 @@
|
||||
<span style="color: #f56c6c; font-weight: bold;">{{ scope.row.price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="图标" align="center" prop="icon" width="80">
|
||||
<template slot-scope="scope">
|
||||
<img v-if="scope.row.icon" :src="scope.row.icon" style="width:40px;height:40px;border-radius:4px;" />
|
||||
<span v-else style="color:#ccc;">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="服务描述" align="center" prop="description" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" align="center" prop="status" width="80">
|
||||
<template slot-scope="scope">
|
||||
@@ -170,6 +176,9 @@
|
||||
<el-form-item label="服务描述" prop="description">
|
||||
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入服务内容描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="图标URL" prop="icon">
|
||||
<el-input v-model="form.icon" placeholder="请输入图标URL地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sortOrder">
|
||||
<el-input-number v-model="form.sortOrder" :min="0" style="width: 100%" placeholder="请输入排序号" />
|
||||
</el-form-item>
|
||||
@@ -315,6 +324,7 @@ export default {
|
||||
typeCode: null,
|
||||
price: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
status: '0',
|
||||
sortOrder: 0,
|
||||
remark: null,
|
||||
|
||||
@@ -46,6 +46,8 @@ public class SysLoginController
|
||||
private ISysUserService userService;
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private com.ruoyi.system.service.IRlzOrderService rlzOrderService;
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
@@ -67,18 +69,33 @@ public class SysLoginController
|
||||
public AjaxResult appLogin(LoginBody loginBody)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
// 生成令牌
|
||||
String token = loginService.appLogin(loginBody.getUsername(), loginBody.getPassword());
|
||||
JSONObject data=new JSONObject();
|
||||
data.put ("userId","1");
|
||||
data.put ("userName","admin");
|
||||
data.put ("nickName","管理员");
|
||||
data.put ("phonenumber","13333333333");
|
||||
data.put("headimage","/profile/avatar/2022/07/08/blob_20220708142648A004.jpeg");
|
||||
data.put ("leijijine",52345.20);//累计收益
|
||||
data.put ("yue",3223.00);
|
||||
data.put (Constants.TOKEN,token);
|
||||
ajax.put(Constants.REQUST_DATA,data);
|
||||
// 生成令牌并获取真实用户信息
|
||||
com.ruoyi.common.core.domain.model.LoginUser loginUser = loginService.appLoginWithUser(loginBody.getUsername(), loginBody.getPassword());
|
||||
SysUser user = loginUser.getUser();
|
||||
String token = loginUser.getToken();
|
||||
JSONObject data = new JSONObject();
|
||||
if (user != null) {
|
||||
data.put("userId", user.getUserId());
|
||||
data.put("userName", user.getUserName());
|
||||
data.put("nickName", user.getNickName() != null ? user.getNickName() : "");
|
||||
data.put("phonenumber", user.getPhonenumber() != null ? user.getPhonenumber() : "");
|
||||
data.put("headimage", user.getAvatar() != null ? user.getAvatar() : "");
|
||||
data.put("leijijine", user.getLeijijine() != null ? user.getLeijijine() : "0");
|
||||
data.put("yue", user.getYue() != null ? user.getYue() : "0");
|
||||
// 查询本月收入和本月接单
|
||||
try {
|
||||
java.util.Map<String, Object> stats = rlzOrderService.getCaregiverMonthlyStats(user.getUserId());
|
||||
Object income = stats.get("income");
|
||||
Object orderCount = stats.get("orderCount");
|
||||
data.put("monthIncome", income != null ? income.toString() : "0");
|
||||
data.put("monthOrderCount", orderCount != null ? orderCount.toString() : "0");
|
||||
} catch (Exception e) {
|
||||
data.put("monthIncome", "0");
|
||||
data.put("monthOrderCount", "0");
|
||||
}
|
||||
}
|
||||
data.put(Constants.TOKEN, token);
|
||||
ajax.put(Constants.REQUST_DATA, data);
|
||||
return ajax;
|
||||
}
|
||||
@PostMapping("/smsLogin")
|
||||
@@ -103,7 +120,7 @@ public class SysLoginController
|
||||
u.setUserName(phoneNumber);
|
||||
u.setPassword(SecurityUtils.encryptPassword("123456"));
|
||||
u.setNickName("游客");
|
||||
u.setAvatar("http://81.68.125.247:9000/rlz/2023-05-28/aa17ed44-8fc9-4e00-a419-862b18bc74b2.jpg");
|
||||
u.setAvatar("http://101.43.95.130:9000/rlz/2023-05-28/aa17ed44-8fc9-4e00-a419-862b18bc74b2.jpg");
|
||||
userService.insertUser(u);
|
||||
}
|
||||
// 生成令牌
|
||||
|
||||
@@ -376,8 +376,9 @@ public class SysUserController extends BaseController
|
||||
public AjaxResult getAppIndexInfo(){
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
//app获取个人信息
|
||||
// LoginUser loginUser = getLoginUser();
|
||||
// SysUser user= loginUser.getUser();
|
||||
LoginUser loginUser = getLoginUser();
|
||||
SysUser user = loginUser.getUser();
|
||||
Long userId = user.getUserId();
|
||||
JSONObject data=new JSONObject();
|
||||
JSONObject receiveOrder=new JSONObject();//新消息, 新订单是orderId和orderCreteTime,服务中 name,phonenumber,headimage
|
||||
JSONArray realTimeInfoList= new JSONArray(); //护理咨询
|
||||
@@ -392,13 +393,17 @@ public class SysUserController extends BaseController
|
||||
realTimeInfoList.add(item);
|
||||
}
|
||||
}
|
||||
data.put("monthOrderCount",21);//本月接单数量
|
||||
// 查询本月收入和本月接单
|
||||
java.util.Map<String, Object> stats = rlzOrderService.getCaregiverMonthlyStats(userId);
|
||||
Object monthIncome = stats.get("income");
|
||||
Object monthOrderCount = stats.get("orderCount");
|
||||
data.put("monthOrderCount", monthOrderCount != null ? monthOrderCount : 0);
|
||||
data.put("liaojiepeizhen","http://ruilaizipj.com/ljpz.html");//了解陪诊
|
||||
data.put("fuwubiaozhun","http://ruilaizipj.com/fwbz.html");//服务标准
|
||||
data.put("feiyongbiaozhun","http://ruilaizipj.com/fybz.html");//费用标准
|
||||
data.put("yinsizhengce","http://ruilaizipj.com/yszc.html");//费用标准
|
||||
|
||||
data.put("monthincome",9400);//本月收入
|
||||
data.put("monthincome", monthIncome != null ? monthIncome : 0);//本月收入
|
||||
data.put("realTimeInfoList",realTimeInfoList);//护理咨询
|
||||
ajax.put(Constants.REQUST_DATA,data);
|
||||
return ajax;
|
||||
|
||||
@@ -109,8 +109,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
|
||||
// 过滤请求
|
||||
.authorizeRequests()
|
||||
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
|
||||
.antMatchers("/login","/appLogin","/system/msm","/smsLogin", "/register", "/captchaImage","/weixinLogin","/getUserToken","/system/weixin/wxPayNotify","/system/weixin/wxRefundNotify","/system/user/getAppIndexInfo").anonymous()
|
||||
.antMatchers("/system/nursing/published","/system/nursing/view/**").permitAll()
|
||||
.antMatchers("/login","/appLogin","/system/msm","/smsLogin", "/register", "/captchaImage","/weixinLogin","/getUserToken","/system/weixin/wxPayNotify","/system/weixin/wxRefundNotify").anonymous()
|
||||
.antMatchers("/system/user/getAppIndexInfo","/system/hospital/list","/system/config/configKey/**","/system/nursing/published","/system/nursing/view/**","/system/serviceType/enabled").permitAll()
|
||||
// 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||
|
||||
@@ -126,6 +126,39 @@ public class SysLoginService
|
||||
return tokenService.createToken(loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* APP登录并返回LoginUser对象
|
||||
*/
|
||||
public LoginUser appLoginWithUser(String username, String password)
|
||||
{
|
||||
Authentication authentication = null;
|
||||
try
|
||||
{
|
||||
authentication = authenticationManager
|
||||
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e instanceof BadCredentialsException)
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
|
||||
throw new UserPasswordNotMatchException();
|
||||
}
|
||||
else
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
|
||||
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
||||
recordLoginInfo(loginUser.getUserId());
|
||||
// createToken sets UUID on loginUser and returns JWT, we need JWT for client
|
||||
String jwtToken = tokenService.createToken(loginUser);
|
||||
loginUser.setToken(jwtToken);
|
||||
return loginUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
*
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.system.domain.RlzOrder;
|
||||
@@ -31,6 +33,9 @@ import com.ruoyi.system.domain.OrderView;
|
||||
import com.ruoyi.system.service.IOrderViewService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.system.util.WXPayConstants;
|
||||
import com.wechat.pay.java.service.refund.model.AmountReq;
|
||||
import com.wechat.pay.java.service.refund.model.CreateRequest;
|
||||
|
||||
/**
|
||||
* VIEWController
|
||||
@@ -42,6 +47,8 @@ import com.ruoyi.common.core.page.TableDataInfo;
|
||||
@RequestMapping("/system/view")
|
||||
public class OrderViewController extends BaseController
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(OrderViewController.class);
|
||||
|
||||
@Autowired
|
||||
private IOrderViewService orderViewService;
|
||||
@Autowired
|
||||
@@ -272,6 +279,24 @@ public class OrderViewController extends BaseController
|
||||
Boolean approved = (Boolean) params.get("approved");
|
||||
String reason = params.get("reason") != null ? params.get("reason").toString() : "";
|
||||
if (approved != null && approved) {
|
||||
// 调用微信退款接口
|
||||
try {
|
||||
CreateRequest request = new CreateRequest();
|
||||
request.setOutRefundNo(order.getYuliu5());
|
||||
request.setOutTradeNo(order.getYuliu5());
|
||||
request.setTransactionId(order.getYuliu6());
|
||||
request.setNotifyUrl(WXPayConstants.REFUND_NOTIFY_URL);
|
||||
AmountReq amount = new AmountReq();
|
||||
long total = (long) (100 * Double.parseDouble(order.getYuguMoney()));
|
||||
amount.setTotal(total);
|
||||
amount.setRefund(total);
|
||||
amount.setCurrency("CNY");
|
||||
request.setAmount(amount);
|
||||
iRlzOrderService.refundOrder(request);
|
||||
} catch (Exception e) {
|
||||
log.error("微信退款调用失败", e);
|
||||
return AjaxResult.error("微信退款调用失败: " + e.getMessage());
|
||||
}
|
||||
order.setStatus("7"); // 已退款
|
||||
order.setRemark((order.getRemark() != null ? order.getRemark() : "") + " [退款审核通过:" + reason + "]");
|
||||
} else {
|
||||
|
||||
@@ -204,15 +204,28 @@ public AjaxResult completeOrder(@PathVariable("orderId") Long orderId)
|
||||
try {
|
||||
Long userId=this.getLoginUser().getUserId();
|
||||
SysUser sysUser = iSysUserService.selectUserById(userId);
|
||||
if(StringUtils.isEmpty(sysUser.getOpenid())){
|
||||
return a.error("用户未绑定微信openid,无法发起支付");
|
||||
}
|
||||
String money=order.getYuguMoney();
|
||||
int total= (int) (100*Double.parseDouble(order.getYuguMoney()));
|
||||
a= AjaxResult.success(V3WXPayUtil.createOrder(String.valueOf(orderId), sysUser.getOpenid(), "订单支付",total));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return a.error("支付请求失败: " + e.getMessage());
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户申请退款 (status 4/8 -> 5)
|
||||
*/
|
||||
@PostMapping(value = "/applyRefund/{orderId}")
|
||||
public AjaxResult applyRefund(@PathVariable Long orderId, @RequestBody(required = false) RlzOrder req) {
|
||||
String reason = req != null ? req.getRemark() : null;
|
||||
return AjaxResult.success(rlzOrderService.applyRefundByOrderId(orderId, reason));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/refundOrder/{orderId}")
|
||||
public AjaxResult refundOrder(@PathVariable Long orderId) throws GeneralSecurityException, UnsupportedEncodingException {
|
||||
AjaxResult a=new AjaxResult();
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.ruoyi.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.system.domain.RlzPlatformConfig;
|
||||
import com.ruoyi.system.service.IRlzPlatformConfigService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/system/platformConfig")
|
||||
public class RlzPlatformConfigController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private IRlzPlatformConfigService platformConfigService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(RlzPlatformConfig config) {
|
||||
startPage();
|
||||
List<RlzPlatformConfig> list = platformConfigService.selectRlzPlatformConfigList(config);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable Long id) {
|
||||
return AjaxResult.success(platformConfigService.selectRlzPlatformConfigById(id));
|
||||
}
|
||||
|
||||
@GetMapping("/getValue/{configKey}")
|
||||
public AjaxResult getValue(@PathVariable String configKey) {
|
||||
String value = platformConfigService.getConfigValue(configKey, "");
|
||||
return AjaxResult.success("ok", value);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody RlzPlatformConfig config) {
|
||||
return toAjax(platformConfigService.insertRlzPlatformConfig(config));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody RlzPlatformConfig config) {
|
||||
return toAjax(platformConfigService.updateRlzPlatformConfig(config));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(platformConfigService.deleteRlzPlatformConfigByIds(ids));
|
||||
}
|
||||
}
|
||||
@@ -130,4 +130,15 @@ public class RlzServiceTypeController extends BaseController
|
||||
List<RlzPriceHistory> list = rlzServiceTypeService.selectPriceHistoryByServiceTypeId(serviceTypeId);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序端获取启用的服务列表(无需登录)
|
||||
*/
|
||||
@GetMapping("/enabled")
|
||||
public AjaxResult enabled(RlzServiceType rlzServiceType)
|
||||
{
|
||||
rlzServiceType.setStatus("0");
|
||||
List<RlzServiceType> list = rlzServiceTypeService.selectRlzServiceTypeList(rlzServiceType);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.ruoyi.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.system.domain.RlzOrder;
|
||||
import com.ruoyi.system.mapper.RlzOrderMapper;
|
||||
import com.ruoyi.system.service.IRlzSettlementService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/system/settlement")
|
||||
public class RlzSettlementController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private IRlzSettlementService settlementService;
|
||||
|
||||
@Autowired
|
||||
private RlzOrderMapper orderMapper;
|
||||
|
||||
// 待结算订单列表 (status=4 已支付 AND is_zhifu != '1' 未打款)
|
||||
@GetMapping("/pending")
|
||||
public TableDataInfo pending(RlzOrder order) {
|
||||
startPage();
|
||||
order.setStatus("4");
|
||||
order.setIsZhifu("0");
|
||||
List<RlzOrder> list = orderMapper.selectRlzOrderList(order);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PostMapping("/settle/{orderId}")
|
||||
public AjaxResult settle(@PathVariable Long orderId) {
|
||||
settlementService.settleOrder(orderId);
|
||||
return AjaxResult.success("结算完成");
|
||||
}
|
||||
|
||||
@PostMapping("/batchSettle")
|
||||
public AjaxResult batchSettle(@RequestBody Long[] orderIds) {
|
||||
settlementService.batchSettleOrder(orderIds);
|
||||
return AjaxResult.success("批量结算完成");
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class SysOssController extends BaseController
|
||||
private ISysOssService sysOssService;
|
||||
@Autowired
|
||||
private ISysOssConfigService sysOssConfigService;
|
||||
final String endpoint="http://81.68.125.247:9000";
|
||||
final String endpoint="http://101.43.95.130:9000";
|
||||
final String bucketName="rlz";
|
||||
|
||||
/** 自定义上传Minio服务器方法*/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.ruoyi.system.domain;
|
||||
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
public class RlzPlatformConfig extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
@Excel(name = "配置键")
|
||||
private String configKey;
|
||||
|
||||
@Excel(name = "配置值")
|
||||
private String configValue;
|
||||
|
||||
@Excel(name = "描述")
|
||||
private String description;
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getConfigKey() { return configKey; }
|
||||
public void setConfigKey(String configKey) { this.configKey = configKey; }
|
||||
public String getConfigValue() { return configValue; }
|
||||
public void setConfigValue(String configValue) { this.configValue = configValue; }
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RlzPlatformConfig{id=" + id + ", configKey='" + configKey + "', configValue='" + configValue + "'}";
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,9 @@ public class RlzServiceType extends BaseEntity
|
||||
@Excel(name = "状态", readConverterExp = "0=启用,1=停用")
|
||||
private String status;
|
||||
|
||||
/** 图标URL */
|
||||
private String icon;
|
||||
|
||||
/** 排序 */
|
||||
private Integer sortOrder;
|
||||
|
||||
@@ -116,6 +119,16 @@ public class RlzServiceType extends BaseEntity
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setIcon(String icon)
|
||||
{
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public String getIcon()
|
||||
{
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void setSortOrder(Integer sortOrder)
|
||||
{
|
||||
this.sortOrder = sortOrder;
|
||||
@@ -136,6 +149,7 @@ public class RlzServiceType extends BaseEntity
|
||||
.append("price", getPrice())
|
||||
.append("description", getDescription())
|
||||
.append("status", getStatus())
|
||||
.append("icon", getIcon())
|
||||
.append("sortOrder", getSortOrder())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
|
||||
@@ -93,4 +93,9 @@ public interface RlzOrderMapper
|
||||
* 仪表盘-陪护服务排名
|
||||
*/
|
||||
public List<java.util.Map<String, Object>> getCaregiverRanking();
|
||||
|
||||
/**
|
||||
* 陪护员本月统计(收入+接单数)
|
||||
*/
|
||||
public java.util.Map<String, Object> getCaregiverMonthlyStats(Long bId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.system.domain.RlzPlatformConfig;
|
||||
|
||||
public interface RlzPlatformConfigMapper
|
||||
{
|
||||
List<RlzPlatformConfig> selectRlzPlatformConfigList(RlzPlatformConfig config);
|
||||
RlzPlatformConfig selectRlzPlatformConfigById(Long id);
|
||||
RlzPlatformConfig selectRlzPlatformConfigByKey(String configKey);
|
||||
int insertRlzPlatformConfig(RlzPlatformConfig config);
|
||||
int updateRlzPlatformConfig(RlzPlatformConfig config);
|
||||
int deleteRlzPlatformConfigById(Long id);
|
||||
int deleteRlzPlatformConfigByIds(Long[] ids);
|
||||
}
|
||||
@@ -77,6 +77,11 @@ public interface IRlzOrderService
|
||||
|
||||
Long insertOrderPz(RlzOrder rlzOrder);
|
||||
|
||||
/**
|
||||
* 客户申请退款 (status 4/8 -> 5)
|
||||
*/
|
||||
String applyRefundByOrderId(Long orderId, String reason);
|
||||
|
||||
List<java.util.Map<String, Object>> getIncomeStats(java.util.Map<String, Object> params);
|
||||
|
||||
/**
|
||||
@@ -108,4 +113,9 @@ public interface IRlzOrderService
|
||||
* 仪表盘-陪护服务排名
|
||||
*/
|
||||
List<java.util.Map<String, Object>> getCaregiverRanking();
|
||||
|
||||
/**
|
||||
* 陪护员本月统计(收入+接单数)
|
||||
*/
|
||||
java.util.Map<String, Object> getCaregiverMonthlyStats(Long bId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ruoyi.system.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.system.domain.RlzPlatformConfig;
|
||||
|
||||
public interface IRlzPlatformConfigService
|
||||
{
|
||||
List<RlzPlatformConfig> selectRlzPlatformConfigList(RlzPlatformConfig config);
|
||||
RlzPlatformConfig selectRlzPlatformConfigById(Long id);
|
||||
String getConfigValue(String configKey, String defaultValue);
|
||||
int insertRlzPlatformConfig(RlzPlatformConfig config);
|
||||
int updateRlzPlatformConfig(RlzPlatformConfig config);
|
||||
int deleteRlzPlatformConfigByIds(Long[] ids);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.ruoyi.system.service;
|
||||
|
||||
import com.ruoyi.system.domain.RlzOrder;
|
||||
|
||||
public interface IRlzSettlementService
|
||||
{
|
||||
void calculateOrderFee(RlzOrder order);
|
||||
void settleOrder(Long orderId);
|
||||
void batchSettleOrder(Long[] orderIds);
|
||||
}
|
||||
@@ -48,6 +48,7 @@ import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.system.mapper.RlzOrderMapper;
|
||||
import com.ruoyi.system.domain.RlzOrder;
|
||||
import com.ruoyi.system.service.IRlzOrderService;
|
||||
import com.ruoyi.system.service.IRlzSettlementService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static com.wechat.pay.java.core.util.GsonUtil.toJson;
|
||||
@@ -66,6 +67,8 @@ public class RlzOrderServiceImpl implements IRlzOrderService
|
||||
private RlzOrderMapper rlzOrderMapper;
|
||||
@Autowired
|
||||
private ISysWeixinPayService iSysWeixinPayService;
|
||||
@Autowired
|
||||
private IRlzSettlementService settlementService;
|
||||
/**
|
||||
* 查询【请填写功能名称】
|
||||
*
|
||||
@@ -226,6 +229,8 @@ public String weixinPayOrderNext(String decryptOrder) {
|
||||
rlzOrder.setStatus("4");//已完成(已支付)
|
||||
int i = rlzOrderMapper.updateRlzOrder(rlzOrder);
|
||||
if(i>0){
|
||||
// 自动计算分账金额
|
||||
settlementService.calculateOrderFee(rlzOrder);
|
||||
return "SUCCESS";
|
||||
}else {
|
||||
return "FAIL" +
|
||||
@@ -379,4 +384,37 @@ public String weixinPayOrderNext(String decryptOrder) {
|
||||
public List<java.util.Map<String, Object>> getCaregiverRanking() {
|
||||
return rlzOrderMapper.getCaregiverRanking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String applyRefundByOrderId(Long orderId, String reason) {
|
||||
RlzOrder order = this.selectRlzOrderByOrderId(orderId);
|
||||
if (order == null) {
|
||||
return "订单不存在!";
|
||||
}
|
||||
String status = order.getStatus();
|
||||
if (!"4".equals(status) && !"8".equals(status)) {
|
||||
return "当前订单状态不允许申请退款!";
|
||||
}
|
||||
order.setStatus("5");
|
||||
if (reason != null && !reason.isEmpty()) {
|
||||
order.setRemark((order.getRemark() != null ? order.getRemark() : "") + " [退款原因:" + reason + "]");
|
||||
}
|
||||
int i = this.updateRlzOrder(order);
|
||||
if (i > 0) {
|
||||
return "退款申请提交成功!";
|
||||
} else {
|
||||
return "退款申请提交失败!";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.Map<String, Object> getCaregiverMonthlyStats(Long bId) {
|
||||
java.util.Map<String, Object> result = rlzOrderMapper.getCaregiverMonthlyStats(bId);
|
||||
if (result == null) {
|
||||
result = new HashMap<>();
|
||||
result.put("income", 0);
|
||||
result.put("orderCount", 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.ruoyi.system.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.system.domain.RlzPlatformConfig;
|
||||
import com.ruoyi.system.mapper.RlzPlatformConfigMapper;
|
||||
import com.ruoyi.system.service.IRlzPlatformConfigService;
|
||||
|
||||
@Service
|
||||
public class RlzPlatformConfigServiceImpl implements IRlzPlatformConfigService
|
||||
{
|
||||
@Autowired
|
||||
private RlzPlatformConfigMapper platformConfigMapper;
|
||||
|
||||
@Override
|
||||
public List<RlzPlatformConfig> selectRlzPlatformConfigList(RlzPlatformConfig config) {
|
||||
return platformConfigMapper.selectRlzPlatformConfigList(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RlzPlatformConfig selectRlzPlatformConfigById(Long id) {
|
||||
return platformConfigMapper.selectRlzPlatformConfigById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigValue(String configKey, String defaultValue) {
|
||||
RlzPlatformConfig config = platformConfigMapper.selectRlzPlatformConfigByKey(configKey);
|
||||
return (config != null && config.getConfigValue() != null) ? config.getConfigValue() : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertRlzPlatformConfig(RlzPlatformConfig config) {
|
||||
return platformConfigMapper.insertRlzPlatformConfig(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateRlzPlatformConfig(RlzPlatformConfig config) {
|
||||
return platformConfigMapper.updateRlzPlatformConfig(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteRlzPlatformConfigByIds(Long[] ids) {
|
||||
return platformConfigMapper.deleteRlzPlatformConfigByIds(ids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.ruoyi.system.service.impl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Date;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.system.domain.JiaoyiDetail;
|
||||
import com.ruoyi.system.domain.RlzOrder;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.system.mapper.JiaoyiDetailMapper;
|
||||
import com.ruoyi.system.mapper.RlzOrderMapper;
|
||||
import com.ruoyi.system.mapper.SysUserMapper;
|
||||
import com.ruoyi.system.service.IRlzPlatformConfigService;
|
||||
import com.ruoyi.system.service.IRlzSettlementService;
|
||||
|
||||
@Service
|
||||
public class RlzSettlementServiceImpl implements IRlzSettlementService
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(RlzSettlementServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private IRlzPlatformConfigService platformConfigService;
|
||||
|
||||
@Autowired
|
||||
private RlzOrderMapper orderMapper;
|
||||
|
||||
@Autowired
|
||||
private SysUserMapper userMapper;
|
||||
|
||||
@Autowired
|
||||
private JiaoyiDetailMapper jiaoyiDetailMapper;
|
||||
|
||||
@Override
|
||||
public void calculateOrderFee(RlzOrder order) {
|
||||
String yuguMoney = order.getYuguMoney();
|
||||
if (yuguMoney == null || yuguMoney.isEmpty()) {
|
||||
log.warn("Order {} has no yuguMoney, skip calculation", order.getOrderId());
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取抽成比例,默认20%
|
||||
String rateStr = platformConfigService.getConfigValue("commission_rate", "20");
|
||||
BigDecimal rate = new BigDecimal(rateStr);
|
||||
BigDecimal total = new BigDecimal(yuguMoney);
|
||||
BigDecimal kouchu = total.multiply(rate).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
|
||||
BigDecimal fanxian = total.subtract(kouchu);
|
||||
|
||||
order.setJiesuanMoney(yuguMoney);
|
||||
order.setKouchuMoney(kouchu.toString());
|
||||
order.setFanxianMoney(fanxian.toString());
|
||||
order.setFanxianTax(rateStr);
|
||||
order.setIsZhifu("0");
|
||||
|
||||
RlzOrder update = new RlzOrder();
|
||||
update.setOrderId(order.getOrderId());
|
||||
update.setJiesuanMoney(yuguMoney);
|
||||
update.setKouchuMoney(kouchu.toString());
|
||||
update.setFanxianMoney(fanxian.toString());
|
||||
update.setFanxianTax(rateStr);
|
||||
update.setIsZhifu("0");
|
||||
orderMapper.updateRlzOrder(update);
|
||||
|
||||
log.info("Order {} fee calculated: total={}, kouchu={}, fanxian={}", order.getOrderId(), total, kouchu, fanxian);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void settleOrder(Long orderId) {
|
||||
RlzOrder order = orderMapper.selectRlzOrderByOrderId(orderId);
|
||||
if (order == null) {
|
||||
throw new ServiceException("订单不存在");
|
||||
}
|
||||
if (!"4".equals(order.getStatus())) {
|
||||
throw new ServiceException("订单未支付,无法结算");
|
||||
}
|
||||
if ("1".equals(order.getIsZhifu())) {
|
||||
throw new ServiceException("已打款,请勿重复操作");
|
||||
}
|
||||
|
||||
// 如果还没计算分账,先计算
|
||||
if (order.getFanxianMoney() == null || order.getFanxianMoney().isEmpty()) {
|
||||
calculateOrderFee(order);
|
||||
order = orderMapper.selectRlzOrderByOrderId(orderId); // 重新获取
|
||||
}
|
||||
|
||||
Long caregiverId = order.getbId();
|
||||
BigDecimal fanxianMoney = new BigDecimal(order.getFanxianMoney());
|
||||
|
||||
// 更新订单状态
|
||||
RlzOrder update = new RlzOrder();
|
||||
update.setOrderId(orderId);
|
||||
update.setIsZhifu("1");
|
||||
update.setStatus("8");
|
||||
orderMapper.updateRlzOrder(update);
|
||||
|
||||
// 更新陪诊员余额
|
||||
SysUser caregiver = userMapper.selectUserById(caregiverId);
|
||||
if (caregiver != null) {
|
||||
BigDecimal oldBalance = new BigDecimal(caregiver.getYue() != null && !caregiver.getYue().isEmpty() ? caregiver.getYue() : "0");
|
||||
BigDecimal newBalance = oldBalance.add(fanxianMoney);
|
||||
caregiver.setYue(newBalance.toString());
|
||||
|
||||
BigDecimal oldTotal = new BigDecimal(caregiver.getLeijijine() != null && !caregiver.getLeijijine().isEmpty() ? caregiver.getLeijijine() : "0");
|
||||
caregiver.setLeijijine(oldTotal.add(fanxianMoney).toString());
|
||||
userMapper.updateUser(caregiver);
|
||||
|
||||
// 生成交易记录
|
||||
JiaoyiDetail detail = new JiaoyiDetail();
|
||||
detail.setUserId(caregiverId);
|
||||
detail.setType("1");
|
||||
detail.setJine(fanxianMoney.toString());
|
||||
detail.setYue(newBalance.toString());
|
||||
detail.setName("订单结算 - " + (order.getYuliu1() != null ? order.getYuliu1() : orderId));
|
||||
detail.setCreateTime(new Date());
|
||||
jiaoyiDetailMapper.insertJiaoyiDetail(detail);
|
||||
|
||||
log.info("Order {} settled: caregiver={}, fanxian={}, newBalance={}", orderId, caregiverId, fanxianMoney, newBalance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchSettleOrder(Long[] orderIds) {
|
||||
for (Long id : orderIds) {
|
||||
settleOrder(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import java.util.UUID;
|
||||
*/
|
||||
@Component
|
||||
public class MinioUtil {
|
||||
final String endpoint="http://81.68.125.247:9000";
|
||||
final String endpoint="http://rlz-minio:9000";
|
||||
final String accessKey="minioadmin";
|
||||
final String secretKey="minioadmin";
|
||||
final String bucketName="rlz";
|
||||
|
||||
@@ -33,32 +33,23 @@ import java.util.Map;
|
||||
public class V3WXPayUtil {
|
||||
|
||||
|
||||
public static Map<String, Object> createOrder(String buildCode, String openId, String description, int total) throws Exception {
|
||||
// PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
|
||||
// new ByteArrayInputStream(WXPayConstants.PRIVATE_KEY.getBytes("utf-8")));
|
||||
public static Map<String, Object> createOrder(String orderIdStr, String openId, String description, int total) throws Exception {
|
||||
try {
|
||||
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(WXPayConstants.PRIVATE_KEY);
|
||||
|
||||
// writeText("C:/log.txt", "获取私钥:=========>" + merchantPrivateKey.toString());
|
||||
// 获取证书管理器实例
|
||||
CertificatesManager certificatesManager = CertificatesManager.getInstance();
|
||||
// writeText("C:/log.txt", "获取证书管理器实例:=========>" + certificatesManager.toString() + "\n");
|
||||
// 向证书管理器增加需要自动更新平台证书的商户信息
|
||||
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(WXPayConstants.MCH_ID,
|
||||
new PrivateKeySigner(WXPayConstants.MCH_SERIAL_NO, merchantPrivateKey));
|
||||
// writeText("C:/log.txt", "获取管理器增加需要自动更新平台证书的商户信息前:=========>" + wechatPay2Credentials.toString() + "\n");
|
||||
byte[] api_v3KEYBytes = WXPayConstants.API_V3KEY.getBytes(StandardCharsets.UTF_8);
|
||||
// writeText("C:/log.txt", "获取api_v3KEYBytes:=========>" + api_v3KEYBytes + "\n");
|
||||
certificatesManager.putMerchant(WXPayConstants.MCH_ID, wechatPay2Credentials, api_v3KEYBytes);
|
||||
// writeText("C:/log.txt", "证书管理器实例:=========>" + certificatesManager.toString());
|
||||
// 从证书管理器中获取verifier
|
||||
Verifier verifier = certificatesManager.getVerifier(WXPayConstants.MCH_ID);
|
||||
// writeText("C:/log.txt", "从证书管理器中获取verifier:=========>" + verifier);
|
||||
CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
|
||||
.withMerchant(WXPayConstants.MCH_ID, WXPayConstants.MCH_SERIAL_NO, merchantPrivateKey)
|
||||
.withValidator(new WechatPay2Validator(verifier))
|
||||
.build();
|
||||
// writeText("C:/log.txt", "从证书管理器中获取verifier后:=========>" + "\n");
|
||||
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
|
||||
httpPost.addHeader("Accept", "application/json");
|
||||
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
|
||||
@@ -66,14 +57,17 @@ public class V3WXPayUtil {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// out_trade_no 要求6-32字符,用orderId左补零到6位
|
||||
String outTradeNo = String.format("%06d", Long.parseLong(orderIdStr));
|
||||
|
||||
ObjectNode rootNode = objectMapper.createObjectNode();
|
||||
rootNode.put("mchid", WXPayConstants.MCH_ID)
|
||||
.put("appid", WXPayConstants.APP_ID)
|
||||
.put("notify_url", WXPayConstants.NOTIFY_URL)
|
||||
.put("description", description)
|
||||
.put("out_trade_no", buildCode);
|
||||
.put("out_trade_no", outTradeNo);
|
||||
rootNode.putObject("amount")
|
||||
.put("total", total) // 支付总金额,分为单位 需前端传入
|
||||
.put("total", total)
|
||||
.put("currency", "CNY");
|
||||
rootNode.putObject("payer")
|
||||
.put("openid", openId);
|
||||
@@ -84,41 +78,43 @@ public class V3WXPayUtil {
|
||||
CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||
|
||||
String bodyAsString = EntityUtils.toString(response.getEntity());
|
||||
// log.info("成功获取微信预支付订单号{}", bodyAsString);
|
||||
System.out.println("成功获取微信预支付订单号==========>" + bodyAsString);
|
||||
System.out.println("微信预支付应答==========>" + bodyAsString);
|
||||
|
||||
JsonNode node = objectMapper.readTree(bodyAsString);
|
||||
|
||||
// 检查微信返回是否为错误响应
|
||||
JsonNode prepayIdNode = node.get("prepay_id");
|
||||
if (prepayIdNode == null) {
|
||||
String errorMsg = "微信支付下单失败: " + bodyAsString;
|
||||
System.out.println(errorMsg);
|
||||
throw new RuntimeException(errorMsg);
|
||||
}
|
||||
|
||||
// 时间戳
|
||||
String currentTimeMillis = System.currentTimeMillis() / 1000 + "";
|
||||
// 随机字符串 hutool工具类
|
||||
// 随机字符串
|
||||
String randomString = RandomUtil.randomString(32);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
// 应用ID
|
||||
builder.append(WXPayConstants.APP_ID).append("\n");
|
||||
// 时间戳
|
||||
builder.append(currentTimeMillis).append("\n");
|
||||
// 随机字符串
|
||||
builder.append(randomString).append("\n");
|
||||
|
||||
JsonNode node = objectMapper.readTree(bodyAsString);
|
||||
// writeText("C:/log.txt", "从获取node后:=========>" + node + "\n");
|
||||
// 订单详情扩展字符串
|
||||
builder.append("prepay_id=").append(node.get("prepay_id").toString().replace("\"", "")).append("\n");
|
||||
builder.append("prepay_id=").append(prepayIdNode.toString().replace("\"", "")).append("\n");
|
||||
|
||||
String paySign = sign(builder.toString().getBytes());
|
||||
|
||||
Map<String, Object> map = new HashMap();
|
||||
map.put("package", "prepay_id=" + node.get("prepay_id").toString().replace("\"", ""));
|
||||
map.put("prepayId", node.get("prepay_id").toString().replace("\"", ""));
|
||||
map.put("package", "prepay_id=" + prepayIdNode.toString().replace("\"", ""));
|
||||
map.put("prepayId", prepayIdNode.toString().replace("\"", ""));
|
||||
map.put("nonceStr", randomString);
|
||||
map.put("signType", "RSA");
|
||||
map.put("paySign", paySign);
|
||||
map.put("timeStamp", currentTimeMillis);
|
||||
map.put("appId", WXPayConstants.APP_ID);
|
||||
map.put("orderId", buildCode);
|
||||
map.put("orderId", orderIdStr);
|
||||
|
||||
return map;
|
||||
}catch (Exception e){
|
||||
// writeText("C:/log.txt", "异常:" + getStackTraceMessage(e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ public class WXPayConstants {
|
||||
public static final String MCH_SERIAL_NO = "343F1DCA192D001C9689BFDA2B595E3B7D917B45";
|
||||
/*APIv3密钥*/
|
||||
public static final String API_V3KEY = "RENJIANBOchengjiepurenfeitangjie";
|
||||
/*支付成功回调地址*/
|
||||
public static final String NOTIFY_URL = "https://ruilaizipj.com/system/weixin/wxPayNotify";
|
||||
/*支付成功回调地址(通过/prod-api/前缀让nginx路由到RLZ后端)*/
|
||||
public static final String NOTIFY_URL = "https://ruilaizipj.com/prod-api/system/weixin/wxPayNotify";
|
||||
/*退款回调地址*/
|
||||
public static final String REFUND_NOTIFY_URL = "https://ruilaizipj.com/system/weixin/wxRefundNotify";
|
||||
public static final String REFUND_NOTIFY_URL = "https://ruilaizipj.com/prod-api/system/weixin/wxRefundNotify";
|
||||
// /*支付成功回调地址*/
|
||||
// public static final String NOTIFY_URL = "https://35q45673j2.goho.co/system/weixin/wxPayNotify";
|
||||
// /*退款回调地址*/
|
||||
|
||||
@@ -294,4 +294,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
GROUP BY date
|
||||
ORDER BY date
|
||||
</select>
|
||||
|
||||
<select id="getCaregiverMonthlyStats" parameterType="long" resultType="map">
|
||||
SELECT
|
||||
COUNT(*) as orderCount,
|
||||
COALESCE(SUM(CASE WHEN status IN ('4','8') THEN CAST(COALESCE(NULLIF(fanxian_money,''), '0') AS DECIMAL(10,2)) ELSE 0 END), 0) as income
|
||||
FROM rlz_order
|
||||
WHERE b_id = #{bId}
|
||||
AND DATE_FORMAT(create_time, '%Y-%m') = DATE_FORMAT(NOW(), '%Y-%m')
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.system.mapper.RlzPlatformConfigMapper">
|
||||
|
||||
<resultMap type="RlzPlatformConfig" id="RlzPlatformConfigResult">
|
||||
<result property="id" column="id"/>
|
||||
<result property="configKey" column="config_key"/>
|
||||
<result property="configValue" column="config_value"/>
|
||||
<result property="description" column="description"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectVo">
|
||||
select id, config_key, config_value, description, create_time, update_time from rlz_platform_config
|
||||
</sql>
|
||||
|
||||
<select id="selectRlzPlatformConfigList" parameterType="RlzPlatformConfig" resultMap="RlzPlatformConfigResult">
|
||||
<include refid="selectVo"/>
|
||||
<where>
|
||||
<if test="configKey != null and configKey != ''"> and config_key like concat('%', #{configKey}, '%')</if>
|
||||
<if test="description != null and description != ''"> and description like concat('%', #{description}, '%')</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectRlzPlatformConfigById" parameterType="Long" resultMap="RlzPlatformConfigResult">
|
||||
<include refid="selectVo"/> where id = #{id}
|
||||
</select>
|
||||
|
||||
<select id="selectRlzPlatformConfigByKey" parameterType="String" resultMap="RlzPlatformConfigResult">
|
||||
<include refid="selectVo"/> where config_key = #{configKey}
|
||||
</select>
|
||||
|
||||
<insert id="insertRlzPlatformConfig" parameterType="RlzPlatformConfig" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into rlz_platform_config
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="configKey != null">config_key,</if>
|
||||
<if test="configValue != null">config_value,</if>
|
||||
<if test="description != null">description,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateTime != null">update_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="configKey != null">#{configKey},</if>
|
||||
<if test="configValue != null">#{configValue},</if>
|
||||
<if test="description != null">#{description},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateTime != null">#{updateTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateRlzPlatformConfig" parameterType="RlzPlatformConfig">
|
||||
update rlz_platform_config
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="configKey != null">config_key = #{configKey},</if>
|
||||
<if test="configValue != null">config_value = #{configValue},</if>
|
||||
<if test="description != null">description = #{description},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deleteRlzPlatformConfigById" parameterType="Long">
|
||||
delete from rlz_platform_config where id = #{id}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteRlzPlatformConfigByIds" parameterType="String">
|
||||
delete from rlz_platform_config where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
@@ -12,6 +12,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="price" column="price" />
|
||||
<result property="description" column="description" />
|
||||
<result property="status" column="status" />
|
||||
<result property="icon" column="icon" />
|
||||
<result property="sortOrder" column="sort_order" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
@@ -21,7 +22,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectRlzServiceTypeVo">
|
||||
select id, name, category, type_code, price, description, status, sort_order,
|
||||
select id, name, category, type_code, price, description, status, icon, sort_order,
|
||||
create_by, create_time, update_by, update_time, remark
|
||||
from rlz_service_type
|
||||
</sql>
|
||||
@@ -51,6 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="price != null">price,</if>
|
||||
<if test="description != null">description,</if>
|
||||
<if test="status != null">status,</if>
|
||||
<if test="icon != null">icon,</if>
|
||||
<if test="sortOrder != null">sort_order,</if>
|
||||
<if test="createBy != null">create_by,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
@@ -63,6 +65,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="price != null">#{price},</if>
|
||||
<if test="description != null">#{description},</if>
|
||||
<if test="status != null">#{status},</if>
|
||||
<if test="icon != null">#{icon},</if>
|
||||
<if test="sortOrder != null">#{sortOrder},</if>
|
||||
<if test="createBy != null">#{createBy},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
@@ -79,6 +82,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="price != null">price = #{price},</if>
|
||||
<if test="description != null">description = #{description},</if>
|
||||
<if test="status != null">status = #{status},</if>
|
||||
<if test="icon != null">icon = #{icon},</if>
|
||||
<if test="sortOrder != null">sort_order = #{sortOrder},</if>
|
||||
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
|
||||
Reference in New Issue
Block a user