2025008071805

This commit is contained in:
张潘 2025-08-13 18:07:10 +08:00
parent 078e4f07d0
commit 3ad7422f9e
24 changed files with 2810 additions and 572 deletions

View File

@ -1,44 +0,0 @@
import request from '@/utils/request'
// 查询订单服务记录列表
export function listOrderLog(query) {
return request({
url: '/system/OrderLog/list',
method: 'get',
params: query
})
}
// 查询订单服务记录详细
export function getOrderLog(id) {
return request({
url: '/system/OrderLog/' + id,
method: 'get'
})
}
// 新增订单服务记录
export function addOrderLog(data) {
return request({
url: '/system/OrderLog',
method: 'post',
data: data
})
}
// 修改订单服务记录
export function updateOrderLog(data) {
return request({
url: '/system/OrderLog',
method: 'put',
data: data
})
}
// 删除订单服务记录
export function delOrderLog(id) {
return request({
url: '/system/OrderLog/' + id,
method: 'delete'
})
}

View File

@ -1,50 +0,0 @@
import request from '@/utils/request'
// 查询订单服务记录列表
export function listOrderLog(query) {
return request({
url: '/system/OrderLog/list',
method: 'get',
params: query
})
}
// 查询订单服务记录详细
export function getOrderLog(id) {
return request({
url: '/system/OrderLog/' + id,
method: 'get'
})
}
// 查询wechat_transfer详细
export function getUserDataList() {
return request({
url: '/system/transfer/getUsersDataList',
method: 'get'
})
}
// 新增订单服务记录
export function addOrderLog(data) {
return request({
url: '/system/OrderLog',
method: 'post',
data: data
})
}
// 修改订单服务记录
export function updateOrderLog(data) {
return request({
url: '/system/OrderLog',
method: 'put',
data: data
})
}
// 删除订单服务记录
export function delOrderLog(id) {
return request({
url: '/system/OrderLog/' + id,
method: 'delete'
})
}

View File

@ -1307,7 +1307,9 @@ public class AppleOrderController extends BaseController {
result.put("type", payBefor.getType());
result.put("paytype", paytype);
result.put("usersBalance", user.getBalance());
result.put("couponId", couponId);
result.put("postage", payBefor.getPostage());
result.put("mtcode", mtcode);
result.put("servicetype", payBefor.getServicetype());
result.put("paymentFormula", paymentFormula.toString()); // 支付公式
@ -1380,6 +1382,27 @@ public class AppleOrderController extends BaseController {
// if (params.get("product_id") == null || params.get("num") == null) {
// return AppletControllerUtil.appletWarning("单品下单参数(product_id, num, sku, mark)不能为空");
// }
//自提处理
if (params.get("isself")!=null){
if (params.get("isself").equals(1)){
Long product_id=Long.valueOf(params.get("product_id").toString());
ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(product_id);
UserAddress userAddress=new UserAddress();
int num=Integer.valueOf(params.get("num").toString());
String sku = params.get("sku").toString();
String mark = params.get("mark").toString();
Map<String, Object> orderResult = Map.of();
BigDecimal totalAmount2 = BigDecimal.ZERO;
orderResult= CartOrderUtil.createGoodsOrderFromOnes(user, sku,num, mark,serviceGoods, userAddress, goodsOrderService,maincorid,1L) ;
totalAmount2 = totalAmount2.add(new BigDecimal(orderResult.get("allprice").toString()));
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount2, maincorid, null, null, 5L, null, null, null, null, null, Long.valueOf(serviceGoods.getType()),null,null,BigDecimal.ZERO);
Map<String, Object> result1 = new HashMap<>();
result1.put("type", "2");
result1.put("orderid", payBeforeId);
return AppletControllerUtil.appletSuccess(result1);
}
}
//没有地址的虚拟商品
if (addressIdObj == null||addressIdObj == "") {
if ( params.get("product_id") != null) {
long isself= Long.parseLong(params.get("isself").toString());
@ -1401,7 +1424,7 @@ public class AppleOrderController extends BaseController {
totalAmount2 = totalAmount2.add(new BigDecimal(orderResult.get("allprice").toString()));
if (totalAmount2.compareTo(BigDecimal.ZERO) > 0) {
String orderid= orderResult.get("orderId").toString();
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount2, orderid, null, null, 11L, null, null, null, null, null, Long.valueOf(serviceGoods.getType()),null,null);
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount2, maincorid, null, null, 5L, null, null, null, null, null, Long.valueOf(serviceGoods.getType()),null,null,BigDecimal.ZERO);
Map<String, Object> result1 = new HashMap<>();
result1.put("type", "2");
result1.put("orderid", payBeforeId);
@ -1425,6 +1448,7 @@ public class AppleOrderController extends BaseController {
}
List<Map<String, Object>> orderList = new ArrayList<>();
BigDecimal totalAmount = BigDecimal.ZERO;
BigDecimal postage = BigDecimal.ZERO;
if(carIdsObj==null){
// 单品下单参数校验
if (params.get("num") == null || params.get("product_id") == null || params.get("sku") == null || params.get("mark") == null) {
@ -1449,11 +1473,17 @@ public class AppleOrderController extends BaseController {
return AppletControllerUtil.appletWarning(orderResult.getOrDefault("msg", "下单失败").toString());
}
if (serviceGoods.getPostage()!=null) {
if (serviceGoods.getPostage().compareTo(BigDecimal.ZERO) > 0){
postage=serviceGoods.getPostage();
}
}
orderid= orderResult.get("orderId").toString();
orderList.add(orderResult);
totalAmount = totalAmount.add(new BigDecimal(orderResult.get("allprice").toString()));
totalAmount = totalAmount.add(new BigDecimal(orderResult.get("allprice").toString())).add(postage);
if (totalAmount.compareTo(BigDecimal.ZERO) > 0) {
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount, maincorid, null, null, 5L, null, null, null, null, null, Long.valueOf(serviceGoods.getType()),null,null);
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount, maincorid, null, null, 5L, null, null, null, null, null, Long.valueOf(serviceGoods.getType()),null,null,postage);
Map<String, Object> result1 = new HashMap<>();
result1.put("type", "2");
result1.put("orderid", payBeforeId);
@ -1498,10 +1528,14 @@ public class AppleOrderController extends BaseController {
if (serviceGoods.getServicetype()==3||serviceGoods.getType()==2){
totalAmount = totalAmount.add(new BigDecimal(orderResult.get("allprice").toString()));
}
if (serviceGoods.getPostage()!=null) {
if (serviceGoods.getPostage().compareTo(BigDecimal.ZERO) > 0){
postage=postage.add(serviceGoods.getPostage());
}
}
if (cart.getGoodstype()==1&&totalAmount.compareTo(BigDecimal.ZERO) > 0){
String orderid= orderResult.get("orderId").toString();
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount, orderid, null, cart.getGoodId(), 6L, cart.getSku(), null, null, null, null,1L, null, null);
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount, orderid, null, cart.getGoodId(), 6L, cart.getSku(), null, null, null, null,1L, null, null,BigDecimal.ZERO);
Map<String, Object> result1 = new HashMap<>();
result1.put("type", "2");
result1.put("orderid", orderid);
@ -1510,10 +1544,11 @@ public class AppleOrderController extends BaseController {
}
}
if (totalAmount.compareTo(BigDecimal.ZERO) > 0) {
totalAmount=totalAmount.add(postage);
com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
jsonObject.put("name", "订单创建成功");
OrderUtil.addgoodsorderlog(999L,maincorid,"订单生成","1",jsonObject,2L);
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount, maincorid, null, null, 5L, null, null, null, null, null,2L,null,null);
String payBeforeId = payBeforeUtil.createPayBefore(user, totalAmount, maincorid, null, null, 5L, null, null, null, null, null,2L,null,null,BigDecimal.ZERO);
Map<String, Object> result1 = new HashMap<>();
result1.put("type", "2");
result1.put("orderid", maincorid);
@ -2083,6 +2118,7 @@ public class AppleOrderController extends BaseController {
order.getFileData() != null ? order.getFileData() : "",
1L, // servicetype=2表示服务类型
quotation.getId(), order.getOrderId()
,BigDecimal.ZERO
);
if (payOrderId == null) {
@ -4622,7 +4658,6 @@ public class AppleOrderController extends BaseController {
/**
* 退货接口
* @param params 请求参数 {"orderId": "订单ID", "refundAmount": "退款金额", "refundType": "退款类别", "refundReason": "退款原因", "voucher": "凭证"}
* @param request HTTP请求对象
* @return 退货处理结果
*/
@ -4750,22 +4785,22 @@ public class AppleOrderController extends BaseController {
int updateResult = goodsOrderService.updateGoodsOrder(goodsOrder);
if (updateResult > 0) {
// // 9. 添加订单日志
// com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
// jsonObject.put("name", refundType == 1 ? "申请仅退款" : "申请退货退款");
// jsonObject.put("refundAmount", refundAmount);
// jsonObject.put("refundReason", refundReason);
// jsonObject.put("voucher", voucher);
//
// OrderUtil.addgoodsorderlog(goodsOrder.getId(), goodsOrder.getOrderId(),
// refundType == 1 ? "申请仅退款" : "申请退货退款", "6", jsonObject, 2L);
//
// Map<String, Object> result = new HashMap<>();
// result.put("message", "退货申请提交成功");
// result.put("orderId", goodsOrder.getOrderId());
// result.put("status", goodsOrder.getStatus());
// result.put("refundAmount", refundAmount);
// result.put("refundType", refundType);
// 9. 添加订单日志
com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
jsonObject.put("name", refundType == 1 ? "申请仅退款" : "申请退货退款");
jsonObject.put("refundAmount", refundAmount);
jsonObject.put("refundReason", refundReason);
jsonObject.put("voucher", voucher);
OrderUtil.addgoodsorderlog(goodsOrder.getId(), goodsOrder.getMainOrderId(),
refundType == 1 ? "申请仅退款" : "申请退货退款", "6", jsonObject, 2L);
Map<String, Object> result = new HashMap<>();
result.put("message", "退货申请提交成功");
result.put("orderId", goodsOrder.getOrderId());
result.put("status", goodsOrder.getStatus());
result.put("refundAmount", refundAmount);
result.put("refundType", refundType);
return AppletControllerUtil.appletSuccess("操作成功");
} else {
@ -4929,20 +4964,20 @@ public class AppleOrderController extends BaseController {
int updateResult = goodsOrderService.updateGoodsOrder(goodsOrder);
if (updateResult > 0) {
// // 9. 添加订单日志
// com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
// jsonObject.put("name", "添加退货物流信息");
// jsonObject.put("logistics", logistics);
// jsonObject.put("logisticsCode", logisticsCode);
// jsonObject.put("logisticsTime", new Date());
//
// OrderUtil.addgoodsorderlog(goodsOrder.getId(), goodsOrder.getOrderId(), "添加退货物流", "6", jsonObject, 2L);
//
// Map<String, Object> result = new HashMap<>();
// result.put("message", "退货物流信息添加成功");
// result.put("orderId", goodsOrder.getOrderId());
// result.put("logistics", logistics);
// result.put("logisticsCode", logisticsCode);
// 9. 添加订单日志
com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
jsonObject.put("name", "添加退货物流信息");
jsonObject.put("logistics", logistics);
jsonObject.put("logisticsCode", logisticsCode);
jsonObject.put("logisticsTime", new Date());
OrderUtil.addgoodsorderlog(goodsOrder.getId(), goodsOrder.getMainOrderId(), "添加退货物流", "6", jsonObject, 2L);
Map<String, Object> result = new HashMap<>();
result.put("message", "退货物流信息添加成功");
result.put("orderId", goodsOrder.getOrderId());
result.put("logistics", logistics);
result.put("logisticsCode", logisticsCode);
return AppletControllerUtil.appletSuccess("操作成功");
} else {

View File

@ -145,11 +145,15 @@ public class AppletController extends BaseController {
try {
// 验证用户登录状态可选
AppletControllerUtil.getUserData(request.getHeader("token"), usersService);
String cityid= request.getHeader("ct");
System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"+cityid);
// 1. 查询所有启用状态的服务分类
ServiceCate serviceCateQuery = new ServiceCate();
serviceCateQuery.setStatus(1L);
serviceCateQuery.setType(1L);
if (StringUtils.isNotBlank(cityid)){
serviceCateQuery.setCity(cityid);
}
List<ServiceCate> allCategoryList = serviceCateService.selectServiceCateList(serviceCateQuery);
// 2. 分离一级分类和二级分类
@ -836,6 +840,7 @@ public class AppletController extends BaseController {
public AjaxResult getServiceGoodsList(@RequestBody Map<String, Object> params, HttpServletRequest request) {
try {
// 1. 获取分类ID参数
String city = request.getHeader("ct");
Long cateId = null;
if (params.get("cate_id") != null) {
Object cateIdObj = params.get("cate_id");
@ -859,6 +864,9 @@ public class AppletController extends BaseController {
if (cateId == null) {
// 查询启用状态类型为服务排序第一的分类
ServiceCate defaultCateQuery = new ServiceCate();
if (StringUtils.isNotBlank(city)){
defaultCateQuery.setCity(city);
}
defaultCateQuery.setStatus(1L); // 启用状态
defaultCateQuery.setType(1L); // 类型为服务假设1为服务类型
List<ServiceCate> defaultCateList = serviceCateService.selectServiceCateList(defaultCateQuery);
@ -891,7 +899,7 @@ public class AppletController extends BaseController {
// 一级分类返回该一级分类的服务分组 + 所有二级分类的服务分组
// 先添加一级分类本身的服务
List<Map<String, Object>> firstLevelServices = getServicesByCategory(cateId);
List<Map<String, Object>> firstLevelServices = getServicesByCategory(cateId, city);
if (!firstLevelServices.isEmpty()) {
Map<String, Object> firstLevelGroup = new HashMap<>();
firstLevelGroup.put("id", category.getId());
@ -907,7 +915,7 @@ public class AppletController extends BaseController {
List<ServiceCate> childCategories = serviceCateService.selectServiceCateList(childQuery);
for (ServiceCate child : childCategories) {
List<Map<String, Object>> childServices = getServicesByCategory(child.getId());
List<Map<String, Object>> childServices = getServicesByCategory(child.getId(), city);
if (!childServices.isEmpty()) {
Map<String, Object> childGroup = new HashMap<>();
childGroup.put("id", category.getId());
@ -919,7 +927,7 @@ public class AppletController extends BaseController {
} else {
// 二级分类只返回该二级分类的服务分组
List<Map<String, Object>> services = getServicesByCategory(cateId);
List<Map<String, Object>> services = getServicesByCategory(cateId, city);
if (!services.isEmpty()) {
Map<String, Object> group = new HashMap<>();
group.put("id", category.getId());
@ -941,13 +949,15 @@ public class AppletController extends BaseController {
* @param categoryId 分类ID
* @return 服务列表只包含idtitleicon
*/
private List<Map<String, Object>> getServicesByCategory(Long categoryId) {
private List<Map<String, Object>> getServicesByCategory(Long categoryId,String city) {
List<Map<String, Object>> serviceList = new ArrayList<>();
ServiceGoods queryGoods = new ServiceGoods();
queryGoods.setCateId(categoryId);
queryGoods.setStatus("1"); // 只查询启用状态的商品
if (StringUtils.isNotBlank(city)){
queryGoods.setCity(city);
}
List<ServiceGoods> goodsList = serviceGoodsService.selectServiceGoodsList(queryGoods);
for (ServiceGoods goods : goodsList) {
@ -1011,6 +1021,7 @@ public class AppletController extends BaseController {
map.put("creattime", goods.getCreattime());
map.put("type", goods.getType());
map.put("num", goods.getNum());
map.put("allnum", goods.getAllnum());
map.put("introduction", goods.getIntroduction());
List<String> idsList = JSONArray.parseArray(goods.getGoodsids(), String.class);
@ -5939,7 +5950,7 @@ public class AppletController extends BaseController {
// 6. 保存
orderLogService.insertOrderLog(orderLog);
ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId());
WXsendMsgUtil.sendMsgForWorkerInfo(user.getOpenid(), order, serviceGoods);
// WXsendMsgUtil.sendMsgForWorkerInfo(user.getOpenid(), order, serviceGoods);
return AppletControllerUtil.appletSuccess("师傅已经上门");
}
OrderLog orderLog = new OrderLog();
@ -5959,7 +5970,8 @@ public class AppletController extends BaseController {
// 小程序推送给用户师傅已经到达
ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId());
WXsendMsgUtil.sendMsgForWorkerInfo(user.getOpenid(), order, serviceGoods);
//师傅到达的时候给客户的微信推送
WXsendMsgUtil.sendWorkerIsComing(user.getOpenid(), order, serviceGoods);
return AppletControllerUtil.appletSuccess("师傅已经上门");
}
@ -6435,6 +6447,10 @@ public class AppletController extends BaseController {
order.setServicePrice(ServiceAllPrice);
orderService.updateOrder(order);
}
//小程序推送报价成功
Users user = usersService.selectUsersById(order.getUid());
ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId());
WXsendMsgUtil.sendWorkerADDmoney(user.getOpenid(), order, serviceGoods);
return AppletControllerUtil.appletSuccess("报价成功");
}else{
order.setJsonStatus(6);
@ -6693,7 +6709,7 @@ public class AppletController extends BaseController {
payBeforeUtil.createPayBefore(userinfo, log.getCjMoney(), log.getLogOrderId(), log.getId(),
null, 10L, null, null,
null, null, null,1L,null,order.getOrderId());
null, null, null,1L,null,order.getOrderId(), null);
}
//判断这个订单还有没有未支付的数据如果有就停留在服务中如果没有就直接去到状态为4的已完成状态
int paynum=usersPayBeforService.countByLastOrderIdAndStatus(order.getOrderId());
@ -6790,7 +6806,7 @@ public class AppletController extends BaseController {
PayBeforeUtil payBeforeUtil = new PayBeforeUtil();
payBeforeUtil.createPayBefore(userinfo, totalAmount, logOrderId, neworderLog.getId(),
null, 7L, null, null,
null, null, null,1L,null,order.getOrderId());
null, null, null,1L,null,order.getOrderId(), null);
// // 9. 计算会员优惠和服务金抵扣
// BigDecimal memberMoney = BigDecimal.ZERO;
@ -7017,7 +7033,10 @@ public class AppletController extends BaseController {
PayBeforeUtil payBeforeUtil = new PayBeforeUtil();
payBeforeUtil.createPayBefore(userinfo, totalAmount, logOrderId, log.getId(),
null, 7L, null, null,
null, null, null,1L,null,orderInfo.getOrderId());
null, null, null,1L,null,orderInfo.getOrderId(), null);
ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(orderInfo.getProductId());
//微信推送师傅设置上门费
WXsendMsgUtil.sendMsgForUserDoorMoney(userinfo.getOpenid(), orderInfo, serviceGoods);
}
// // 3.3 查询是否有上门费(type=2, paid=2)
// OrderLog doorPriceLogself = new OrderLog();
@ -7565,7 +7584,7 @@ public class AppletController extends BaseController {
responseData.put("num", orderCursor.getNum());
responseData.put("sku", orderCursor.getSku());
responseData.put("total_price", orderCursor.getTotalPrice() != null ? orderCursor.getTotalPrice().toString() : "0.00");
responseData.put("postage", orderCursor.getPostage() != null ? orderCursor.getPostage().toString() : null);
responseData.put("created_at", AppletControllerUtil.formatDateToString(orderCursor.getCreatedAt()));
responseData.put("updated_at", AppletControllerUtil.formatDateToString(orderCursor.getUpdatedAt()));
@ -7574,6 +7593,7 @@ public class AppletController extends BaseController {
Map<String, Object> productInfo = new HashMap<>();
productInfo.put("id", product.getId());
productInfo.put("title", product.getTitle());
responseData.put("postage",product.getPostage());
productInfo.put("price", product.getPrice() != null ? product.getPrice().toString() : "0.00");
productInfo.put("stock", product.getStock());
productInfo.put("isforservice", product.getIsforservice());
@ -8013,7 +8033,8 @@ public class AppletController extends BaseController {
* 首页接口汇总
*/
@GetMapping(value = "/api/public/home/data")
public AjaxResult publichomedata() {
public AjaxResult publichomedata(HttpServletRequest request) {
String city = request.getHeader("ct");
Map<String, Object> responseData = new HashMap<>();
HomeUtril homeUtril = new HomeUtril();
@ -8022,7 +8043,7 @@ public class AppletController extends BaseController {
//首页公告
responseData.put("shouyegonggao", homeUtril.getHomeNoticeList("1"));
//分类列表
responseData.put("shouyefenlei", homeUtril.getServiceCategories());
responseData.put("shouyefenlei", homeUtril.getServiceCategories(city));
//活动专区
responseData.put("huodongzhuanqu", homeUtril.getActivityList());
//活动专区公告
@ -8032,7 +8053,7 @@ public class AppletController extends BaseController {
//资质证书
responseData.put("zizhizhengshu", homeUtril.getAdvImgData(1L));
//拼团专区
responseData.put("pintuanzhuanqu", homeUtril.getGroupList());
responseData.put("pintuanzhuanqu", homeUtril.getGroupList(city));
return AppletControllerUtil.appletSuccess(responseData);
}
@ -8080,8 +8101,9 @@ public class AppletController extends BaseController {
* 1查拼团 2查次卡 3查秒杀 4查报价
*/
@PostMapping("/api/group/service/list")
public AjaxResult getGroupServiceList(@RequestBody Map<String, Object> params) {
public AjaxResult getGroupServiceList(@RequestBody Map<String, Object> params,HttpServletRequest request) {
try {
String city = request.getHeader("ct");
int page = params.get("page") != null ? Integer.parseInt(params.get("page").toString()) : 1;
int limit = params.get("limit") != null ? Integer.parseInt(params.get("limit").toString()) : 15;
Long cateId = null;
@ -8102,6 +8124,9 @@ public class AppletController extends BaseController {
PageHelper.startPage(page, limit);
// 构造查询条件
ServiceGoods query = new ServiceGoods();
if (StringUtils.isNotBlank(city)) {
query.setCity(city);
}
query.setStatus("1");
query.setType(1);
query.setIsgroup(1);//1是拼团
@ -8186,6 +8211,9 @@ public class AppletController extends BaseController {
PageHelper.startPage(page, limit);
// 构造查询条件
ServiceGoods query = new ServiceGoods();
if (StringUtils.isNotBlank(city)) {
query.setCity(city);
}
query.setStatus("1");
query.setType(1);
query.setIsfixed(1);//秒杀
@ -8251,6 +8279,9 @@ public class AppletController extends BaseController {
ServiceGoods query = new ServiceGoods();
query.setStatus("1");
query.setType(1);
if (StringUtils.isNotBlank(city)) {
query.setCity(city);
}
query.setServicetype(2);//报价
if (cateId != null) {
query.setCateId(cateId);

View File

@ -74,7 +74,6 @@ public class GoodsOrderController extends BaseController
List<GoodsOrder> list = goodsOrderService.selectGoodsOrdergrouBymAIDList(goodsOrder);
for(GoodsOrder goodsOrderdata:list){
goodsOrderdata.setOrderId(goodsOrderdata.getMainOrderId());
ServiceGoods serviceGoods=serviceGoodsService.selectServiceGoodsById(goodsOrderdata.getProductId());
if(serviceGoods!=null){
goodsOrderdata.setProductName(serviceGoods.getTitle());

View File

@ -7,6 +7,7 @@ import javax.servlet.http.HttpServletResponse;
import com.ruoyi.system.ControllerUtil.DispatchUtil;
import com.ruoyi.system.ControllerUtil.OrderUtil;
import com.ruoyi.system.ControllerUtil.VerificationResult;
import com.ruoyi.system.ControllerUtil.WXsendMsgUtil;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
import org.springframework.security.access.prepost.PreAuthorize;
@ -395,7 +396,9 @@ public class OrderController extends BaseController {
if (order.getStatus() != 1) {
return error("只有待接单状态的订单才能派单");
}
//给师傅派单的时候的推送
ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId());
WXsendMsgUtil.sendMsgForWorkerInfo(users.getOpenid(), order, serviceGoods);
DispatchUtil.creatWorkerForOrder(order,users);
//
// // 更新订单的派单类型

View File

@ -24,6 +24,9 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* 支付回调控制器
@ -160,7 +163,7 @@ public class PayNotifyController extends BaseController {
int updateResult = goodsOrderService.updateGoodsOrder(goodsOrderData);
ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(goodsOrderData.getProductId());
Users userinfo = usersService.selectUsersById(goodsOrderData.getUid());
WXsendMsgUtil.sendUserForMoneySuccess(userinfo.getOpenid(),goodsOrder,serviceGoods);
// WXsendMsgUtil.sendUserForMoneySuccess(userinfo.getOpenid(),goodsOrder,serviceGoods);
}
// if (updateResult <= 0) {
// logger.error("更新商品订单状态失败,订单号:{}", outTradeNo);
@ -723,7 +726,7 @@ public class PayNotifyController extends BaseController {
if (worker != null){
ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(mainOrder.getProductId());
if (serviceGoods != null){
WXsendMsgUtil.sendUserPayDoorMoneyForWorker(worker.getOpenid(),mainOrder,serviceGoods);
WXsendMsgUtil.sendUserPayDoorMoneyForWorker(worker.getOpenid(),mainOrder,"上门费");
}
}
@ -1672,42 +1675,69 @@ public class PayNotifyController extends BaseController {
@PostMapping("/api/secondary/card/refund/notify")
public String secondaryCardRefundNotify(HttpServletRequest request) {
try {
logger.info("收到次卡退款回调通知,开始处理...");
logger.info("------------------------------------------------------------收到次卡退款回调通知,开始处理...");
// 1. 使用WechatPayUtil处理退款回调暂时使用支付回调方法后续需要实现专门的退款回调处理
Map<String, Object> notifyResult = wechatPayUtil.handlePayNotify(request);
// 1. 读取退款回调数据
StringBuilder xmlData = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
String line;
while ((line = reader.readLine()) != null) {
xmlData.append(line);
}
reader.close();
logger.info("------------------------------------------------------------退款回调原始数据:{}", xmlData.toString());
// 2. 检查处理结果
boolean success = (Boolean) notifyResult.get("success");
String message = (String) notifyResult.get("message");
// 2. 解析XML数据
Map<String, String> refundData = xmlToMap(xmlData.toString());
logger.info("------------------------------------------------------------解析后的退款数据:{}", refundData);
if (!success) {
logger.error("次卡退款回调处理失败:{}", message);
return buildFailResponse("次卡退款回调处理失败");
// 3. 验证退款回调签名退款回调的签名验证方式与支付回调不同
if (!verifyRefundSign(refundData)) {
logger.error("------------------------------------------------------------退款回调签名验证失败");
return buildFailResponse("签名验证失败");
}
// 3. 获取退款信息暂时使用支付信息结构后续需要根据实际退款回调结构调整
Map<String, Object> refundInfo = (Map<String, Object>) notifyResult.get("paymentInfo");
String outTradeNo = (String) refundInfo.get("outTradeNo"); // 原订单号
String transactionId = (String) refundInfo.get("transactionId"); // 交易号
String totalFee = (String) refundInfo.get("totalFee"); // 金额
// 4. 检查退款结果
String returnCode = refundData.get("return_code");
String resultCode = refundData.get("result_code");
if (!"SUCCESS".equals(returnCode)) {
logger.error("------------------------------------------------------------退款回调返回失败:{}", refundData.get("return_msg"));
return buildFailResponse("退款回调返回失败");
}
if (!"SUCCESS".equals(resultCode)) {
logger.error("------------------------------------------------------------退款处理失败:{}", refundData.get("err_code_des"));
return buildFailResponse("退款处理失败");
}
// 4. 查询次卡使用记录
// 5. 获取退款信息
Map<String, Object> refundInfo = new HashMap<>();
String outTradeNo = refundData.get("out_trade_no"); // 原订单号
refundInfo.put("outTradeNo", outTradeNo);
refundInfo.put("outRefundNo", refundData.get("out_refund_no")); // 退款单号
refundInfo.put("refundId", refundData.get("refund_id")); // 微信退款单号
refundInfo.put("refundFee", refundData.get("refund_fee")); // 退款金额
refundInfo.put("totalFee", refundData.get("total_fee")); // 原订单金额
refundInfo.put("refundStatus", refundData.get("refund_status")); // 退款状态
// 6. 查询次卡使用记录
UserUseSecondaryCard useCard = userUseSecondaryCardService.selectUserUseSecondaryCardByorderId(outTradeNo);
if (useCard == null) {
logger.error("未找到次卡使用记录,订单号:{}", outTradeNo);
logger.error("------------------------------------------------------------未找到次卡使用记录,订单号:{}", outTradeNo);
return buildFailResponse("未找到次卡使用记录");
}
// 5. 更新退款状态暂时设置为退款成功状态
// 7. 更新退款状态暂时设置为退款成功状态
useCard.setStatus(3L); // 3=退款成功状态
useCard.setRemark("退款成功,退款时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
useCard.setRemark("------------------------------------------------------------退款成功,退款时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
int updateResult = userUseSecondaryCardService.updateUserUseSecondaryCard(useCard);
if (updateResult > 0) {
logger.info("次卡退款成功,订单号:{},退款金额:{}", outTradeNo, useCard.getPaymoney());
// 6. 处理退款成功后的业务逻辑
// 8. 处理退款成功后的业务逻辑
handleSecondaryCardRefundSuccess(useCard, refundInfo);
return buildSuccessResponse();
@ -1760,4 +1790,69 @@ public class PayNotifyController extends BaseController {
logger.error("处理次卡退款成功业务逻辑异常:", e);
}
}
/**
* 验证退款回调签名
* 退款回调的签名验证方式与支付回调不同
* @param refundData 退款回调数据
* @return 是否验证通过
*/
private boolean verifyRefundSign(Map<String, String> refundData) {
try {
// 退款回调的签名验证逻辑
// 注意这里需要根据微信退款回调的实际签名验证方式来实现
// 目前先返回true避免签名验证失败
logger.info("------------------------------------------------------------退款回调签名验证(暂时跳过)");
return true;
// TODO: 实现真正的退款回调签名验证
// 1. 获取签名
// 2. 按照微信退款回调的签名规则验证
// 3. 返回验证结果
} catch (Exception e) {
logger.error("------------------------------------------------------------退款回调签名验证异常:", e);
return false;
}
}
/**
* XML转Map简化实现
* @param xml XML字符串
* @return Map
*/
private Map<String, String> xmlToMap(String xml) {
Map<String, String> map = new HashMap<>();
try {
// 移除XML声明和根标签
String processedXml = xml.replaceAll("<\\?xml[^>]*\\?>", "")
.replaceAll("<xml>", "")
.replaceAll("</xml>", "");
String[] elements = processedXml.split("</\\w+>");
for (String element : elements) {
if (element.trim().isEmpty()) {
continue;
}
int startTag = element.indexOf("<");
int endTag = element.indexOf(">");
if (startTag >= 0 && endTag > startTag) {
String key = element.substring(startTag + 1, endTag);
String value = element.substring(endTag + 1);
if (value.startsWith("<![CDATA[") && value.endsWith("]]>")) {
value = value.substring(9, value.length() - 3);
}
map.put(key, value);
}
}
} catch (Exception e) {
logger.error("XML解析失败", e);
throw new RuntimeException("XML解析失败", e);
}
return map;
}
}

View File

@ -1,5 +1,6 @@
package com.ruoyi.system.controller;
import java.math.BigDecimal;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
@ -135,6 +136,10 @@ public class ServiceGoodsController extends BaseController {
// 处理一级和二级分类ID
processCategoryIds(serviceGoods);
if (serviceGoods.getPostage()==null){
serviceGoods.setPostage(BigDecimal.ZERO);
}
return toAjax(serviceGoodsService.insertServiceGoods(serviceGoods));
}

View File

@ -7,6 +7,7 @@ import java.util.Map;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.system.ControllerUtil.OrderUtil;
import com.ruoyi.system.ControllerUtil.RefundUtil;
import com.ruoyi.system.domain.GoodsOrder;
import com.ruoyi.system.domain.Order;
import com.ruoyi.system.domain.OrderLog;
@ -50,6 +51,8 @@ public class UsersPayBeforController extends BaseController
private IOrderLogService orderLogService;
@Autowired
private IGoodsOrderService goodsOrderService;
@Autowired
private RefundUtil refundUtil;
/**
* 查询预支付列表
@ -252,11 +255,34 @@ public class UsersPayBeforController extends BaseController
return error("退款金额必须大于0");
}
Order order = orderService.selectOrderByOrderId(orderId);
if (order == null) {
return error("订单不存在");
// 首先查询支付信息
UsersPayBefor paymentInfo = usersPayBeforService.selectUsersPayBeforByOrderId(orderId);
if (paymentInfo == null) {
return error("未找到支付记录");
}
// 根据servicetype查询对应订单
Order order = null;
if (paymentInfo.getServicetype() != null) {
if (paymentInfo.getServicetype() == 1) {
// 服务类型为1调用orderService根据orderid查询订单
order = orderService.selectOrderByOrderId(orderId);
} else if (paymentInfo.getServicetype() == 2) {
// 服务类型为2调用goodsOrderService根据mainOrderId查询订单
GoodsOrder goodsOrder = new GoodsOrder();
goodsOrder.setMainOrderId(orderId);
List<GoodsOrder> goodsOrders = goodsOrderService.selectGoodsOrderList(goodsOrder);
if (goodsOrders != null && !goodsOrders.isEmpty()) {
// 使用第一个商品订单的orderId查询订单
//order = orderService.selectOrderByOrderId(goodsOrders.get(0).getOrderId());
}
}
}
// if (order == null) {
// return error("订单不存在");
// }
List<UsersPayBefor> payRecords = usersPayBeforService.selectPayDetailsByOrderId(orderId);
if (payRecords == null || payRecords.isEmpty()) {
return error("未找到支付记录");
@ -270,25 +296,35 @@ public class UsersPayBeforController extends BaseController
}
}
// 计算总支付金额
// 计算总支付金额减去会员优惠因为会员优惠不参与退款
BigDecimal totalPaid = BigDecimal.ZERO;
BigDecimal totalMemberDiscount = BigDecimal.ZERO;
for (UsersPayBefor record : payRecords) {
if (record.getAllmoney() != null) {
totalPaid = totalPaid.add(record.getAllmoney());
}
// 累计会员优惠金额不参与退款
if (record.getMembermoney() != null) {
totalMemberDiscount = totalMemberDiscount.add(record.getMembermoney());
}
}
// 验证退款金额不能超过剩余可退款金额
BigDecimal remainingRefundable = totalPaid.subtract(totalRefunded);
// 实际可退款金额 = 总支付金额 - 会员优惠金额
BigDecimal actualRefundableAmount = totalPaid.subtract(totalMemberDiscount);
// 验证退款金额不能超过剩余可退款金额基于实际可退金额
BigDecimal remainingRefundable = actualRefundableAmount.subtract(totalRefunded);
if (totalRefund.compareTo(remainingRefundable) > 0) {
return error("退款金额不能超过剩余可退款金额,剩余可退款:¥" + remainingRefundable);
return error("退款金额不能超过剩余可退款金额,剩余可退款:¥" + remainingRefundable +
"(总支付:¥" + totalPaid + ",会员优惠:¥" + totalMemberDiscount + ",已退款:¥" + totalRefunded + "");
}
// 记录退款日志
OrderLog orderLog = new OrderLog();
orderLog.setOrderId(orderId);
orderLog.setOid(order.getId());
orderLog.setTitle("统一退款");
orderLog.setOid(999L);
orderLog.setTitle("退款");
orderLog.setOrdertype(paymentInfo.getServicetype());
orderLog.setType(new BigDecimal(11));
// 构建退款详情
@ -321,6 +357,7 @@ public class UsersPayBeforController extends BaseController
refundDesc.append(",本次退款金额:¥").append(totalRefund);
refundDesc.append(",累计已退款:¥").append(totalRefunded.add(totalRefund));
refundDesc.append(",剩余可退款:¥").append(remainingRefundable.subtract(totalRefund));
refundDesc.append("(会员优惠¥").append(totalMemberDiscount).append("不参与退款)");
refundDetails.put("name", refundDesc.toString());
refundDetails.put("wechatRefund", wechatRefund);
@ -332,6 +369,8 @@ public class UsersPayBeforController extends BaseController
refundDetails.put("totalRefund", totalRefund);
refundDetails.put("totalRefunded", totalRefunded.add(totalRefund));
refundDetails.put("remainingRefundable", remainingRefundable.subtract(totalRefund));
refundDetails.put("totalMemberDiscount", totalMemberDiscount);
refundDetails.put("actualRefundableAmount", actualRefundableAmount);
refundDetails.put("refundRemark", refundRemark);
refundDetails.put("refundTime", new java.util.Date());
@ -341,28 +380,79 @@ public class UsersPayBeforController extends BaseController
// 更新支付记录状态和退款金额
for (UsersPayBefor record : payRecords) {
BigDecimal currentRefunded = record.getReturnmoney() != null ? record.getReturnmoney() : BigDecimal.ZERO;
BigDecimal newTotalRefunded = currentRefunded.add(totalRefund);
// 如果累计退款金额等于或超过支付金额设置为已退款状态
if (newTotalRefunded.compareTo(record.getAllmoney()) >= 0) {
record.setStatus(3L); // 完全退款
} else {
record.setStatus(2L); // 部分退款
// 计算本次退款中该记录应承担的退款金额
BigDecimal recordRefundAmount = BigDecimal.ZERO;
// 根据该记录的支付方式分配退款金额
if (record.getWxmoney() != null && record.getWxmoney().compareTo(BigDecimal.ZERO) > 0) {
BigDecimal wxRefund = wechatRefund.min(record.getWxmoney().subtract(currentRefunded));
if (wxRefund.compareTo(BigDecimal.ZERO) > 0) {
recordRefundAmount = recordRefundAmount.add(wxRefund);
wechatRefund = wechatRefund.subtract(wxRefund);
}
}
if (record.getYemoney() != null && record.getYemoney().compareTo(BigDecimal.ZERO) > 0) {
BigDecimal yeRefund = balanceRefund.min(record.getYemoney().subtract(currentRefunded));
if (yeRefund.compareTo(BigDecimal.ZERO) > 0) {
recordRefundAmount = recordRefundAmount.add(yeRefund);
balanceRefund = balanceRefund.subtract(yeRefund);
}
}
if (record.getShopmoney() != null && record.getShopmoney().compareTo(BigDecimal.ZERO) > 0) {
BigDecimal shopRefund = shoppingGoldRefund.min(record.getShopmoney().subtract(currentRefunded));
if (shopRefund.compareTo(BigDecimal.ZERO) > 0) {
recordRefundAmount = recordRefundAmount.add(shopRefund);
shoppingGoldRefund = shoppingGoldRefund.subtract(shopRefund);
}
}
if (record.getServicemoney() != null && record.getServicemoney().compareTo(BigDecimal.ZERO) > 0) {
BigDecimal serviceRefund = serviceGoldRefund.min(record.getServicemoney().subtract(currentRefunded));
if (serviceRefund.compareTo(BigDecimal.ZERO) > 0) {
recordRefundAmount = recordRefundAmount.add(serviceRefund);
serviceGoldRefund = serviceGoldRefund.subtract(serviceRefund);
}
}
if (record.getCouponmoney() != null && record.getCouponmoney().compareTo(BigDecimal.ZERO) > 0) {
BigDecimal couponRefundAmount = couponRefund.min(record.getCouponmoney().subtract(currentRefunded));
if (couponRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
recordRefundAmount = recordRefundAmount.add(couponRefundAmount);
couponRefund = couponRefund.subtract(couponRefundAmount);
}
}
// 如果该记录有退款金额则更新
if (recordRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
BigDecimal newTotalRefunded = currentRefunded.add(recordRefundAmount);
// 如果累计退款金额等于或超过支付金额设置为已退款状态
if (newTotalRefunded.compareTo(record.getAllmoney()) >= 0) {
record.setStatus(3L); // 完全退款
} else {
record.setStatus(2L); // 部分退款
}
record.setReturnmoney(newTotalRefunded);
usersPayBeforService.updateUsersPayBefor(record);
}
record.setReturnmoney(newTotalRefunded);
usersPayBeforService.updateUsersPayBefor(record);
}
// 这里可以添加实际的退款逻辑
// 1. 微信支付退款 - 调用微信退款API
// 2. 余额退款 - 更新用户余额
// 3. 购物金退款 - 更新购物金余额
// 4. 服务金退款 - 更新服务金余额
// 5. 会员优惠退款 - 更新会员积分或优惠
// 6. 优惠券退款 - 恢复优惠券使用状态
// return success("退款成功", refundDetails);
return success("退款成功");
// 调用退款工具方法实现真实的业务退款与金额变动
Map<String, Object> refundResult = refundUtil.processUnifiedRefund(
orderId, wechatRefund, balanceRefund, shoppingGoldRefund,
serviceGoldRefund, memberDiscountRefund, couponRefund, refundRemark
);
if (refundResult != null && (Boolean) refundResult.get("success")) {
return success("退款成功");
} else {
String errorMsg = (String) refundResult.get("message");
return error(errorMsg != null ? errorMsg : "退款处理失败");
}
} catch (Exception e) {
return error("退款失败:" + e.getMessage());

View File

@ -48,7 +48,7 @@ public class ServiceCate extends BaseEntity
/** 父级分类ID */
@Excel(name = "父级分类ID")
private Long parentId;
private String city;
/** 子分类列表 */
private List<ServiceCate> children;
@ -184,6 +184,14 @@ public class ServiceCate extends BaseEntity
return deletedAt;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

View File

@ -212,7 +212,7 @@ private String cateName;
@Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
private Date deletedAt;
private String city;
private BigDecimal minPrice;
private BigDecimal maxPrice;
@ -680,6 +680,15 @@ private String cateName;
this.forserviceid = forserviceid;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

View File

@ -113,6 +113,7 @@ public class UsersPayBefor extends BaseEntity
private String attachments;
private String grouporderid;
private BigDecimal returnmoney;
private BigDecimal postage;
/** 支付订单号 */
@ -398,6 +399,14 @@ public class UsersPayBefor extends BaseEntity
this.returnmoney = returnmoney;
}
public BigDecimal getPostage() {
return postage;
}
public void setPostage(BigDecimal postage) {
this.postage = postage;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

View File

@ -12,6 +12,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="status" column="status" />
<result property="browse" column="browse" />
<result property="type" column="type" />
<result property="city" column="city" />
<result property="parentId" column="parent_id" />
<result property="createdAt" column="created_at" />
<result property="updatedAt" column="updated_at" />
@ -19,7 +20,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectServiceCateVo">
select id, title, icon, sort, status, browse, type, parent_id, created_at, updated_at, deleted_at from service_cate
select id, title, icon, sort, status, city,browse, type, parent_id, created_at, updated_at, deleted_at from service_cate
</sql>
<select id="selectServiceCateList" parameterType="ServiceCate" resultMap="ServiceCateResult">
@ -29,6 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null and status != ''"> and status=#{status}</if>
<if test="type != null and type != ''"> and type=#{type}</if>
<if test="parentId != null"> and parent_id=#{parentId}</if>
<if test="city != null and city != ''"> and JSON_CONTAINS(city, #{city})</if>
</where>
order by parent_id ASC, sort ASC
</select>
@ -76,6 +78,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">status,</if>
<if test="browse != null">browse,</if>
<if test="type != null">type,</if>
<if test="city != null">city,</if>
<if test="parentId != null">parent_id,</if>
<if test="deletedAt != null">deleted_at,</if>
created_at,
@ -88,6 +93,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">#{status},</if>
<if test="browse != null">#{browse},</if>
<if test="type != null">#{type},</if>
<if test="city != null">#{city},</if>
<if test="parentId != null">#{parentId},</if>
<if test="deletedAt != null">#{deletedAt},</if>
NOW(),
@ -104,6 +111,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">status = #{status},</if>
<if test="browse != null">browse = #{browse},</if>
<if test="type != null">type = #{type},</if>
<if test="city != null">city = #{city},</if>
<if test="parentId != null">parent_id = #{parentId},</if>
<if test="deletedAt != null">deleted_at = #{deletedAt},</if>
updated_at = NOW()

View File

@ -20,6 +20,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="description" column="description" />
<result property="skuType" column="sku_type" />
<result property="sku" column="sku" />
<result property="city" column="city" />
<result property="servicetype" column="servicetype" />
<result property="isforservice" column="isforservice" />
@ -77,7 +78,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="isfixed != null "> and isfixed = #{isfixed}</if>
<if test="servicetype != null "> and servicetype = #{servicetype}</if>
<if test="city != null and city != ''"> and JSON_CONTAINS(city, #{city})</if>
<if test="cateId != null "> and cate_id = #{cateId}</if>
<if test="firstCateId != null "> and first_cate_id = #{firstCateId}</if>
<if test="secondCateId != null "> and second_cate_id = #{secondCateId}</if>
@ -177,6 +178,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="questions != null">questions,</if>
<if test="isforservice != null">isforservice,</if>
<if test="forserviceid != null">forserviceid,</if>
<if test="city != null">city,</if>
created_at,
updated_at
@ -224,6 +227,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="questions != null">#{questions},</if>
<if test="isforservice != null">#{isforservice},</if>
<if test="forserviceid != null">#{forserviceid},</if>
<if test="city != null">#{city},</if>
NOW(),
NOW()
@ -275,6 +279,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="isfixed != null">isfixed = #{isfixed},</if>
<if test="fixedprice != null">fixedprice = #{fixedprice},</if>
<if test="groupnum != null">groupnum = #{groupnum},</if>
<if test="city != null">city = #{city},</if>
updated_at = NOW()
</trim>

View File

@ -38,6 +38,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</where>
order by id desc
</select>
<select id="selectUserUseSecondaryCardById" parameterType="Long" resultMap="UserUseSecondaryCardResult">

View File

@ -23,6 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="lastorderid" column="lastorderid" />
<result property="num" column="num" />
<result property="returnmoney" column="returnmoney" />
<result property="postage" column="postage" />
@ -43,7 +44,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectUsersPayBeforVo">
select id, uid, paytype,grouporderid,baojiaid,num,returnmoney, lastorderid,wxmoney,serviceid,servicetype,sku,addressid,maketime,attachments, yemoney, allmoney,membermoney, shopmoney, servicemoney, couponid, couponmoney, mtcode, mtmoney, type, orderid, oid, status, paytime, paycode from users_pay_befor
select id, uid, paytype,grouporderid,baojiaid,postage,num,returnmoney, lastorderid,wxmoney,serviceid,servicetype,sku,addressid,maketime,attachments, yemoney, allmoney,membermoney, shopmoney, servicemoney, couponid, couponmoney, mtcode, mtmoney, type, orderid, oid, status, paytime, paycode from users_pay_befor
</sql>
<select id="selectUsersPayBeforList" parameterType="UsersPayBefor" resultMap="UsersPayBeforResult">
@ -128,6 +129,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="lastorderid != null">lastorderid,</if>
<if test="num != null">num,</if>
<if test="returnmoney != null">returnmoney,</if>
<if test="postage != null">postage,</if>
@ -163,6 +165,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="lastorderid != null">#{lastorderid},</if>
<if test="num != null">#{num},</if>
<if test="returnmoney != null">#{returnmoney},</if>
<if test="postage != null">#{postage},</if>
</trim>
</insert>
@ -200,6 +203,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="servicetype != null">servicetype = #{servicetype},</if>
<if test="lastorderid != null">lastorderid = #{lastorderid},</if>
<if test="num != null">num = #{num},</if>
<if test="postage != null">postage = #{postage},</if>
</trim>
where id = #{id}

View File

@ -1,6 +1,6 @@
import request from '@/utils/request'
// 查询自定义地区列表
// 查询城市列表
export function listDiyCity(query) {
return request({
url: '/system/DiyCity/list',
@ -8,31 +8,16 @@ export function listDiyCity(query) {
params: query
})
}
// 查询自定义地区列表
export function datalist(query) {
return request({
url: '/system/DiyCity/datalist',
method: 'get',
params: query
})
}
// 查询自定义地区详细
// 查询城市详细
export function getDiyCity(id) {
return request({
url: '/system/DiyCity/' + id,
method: 'get'
})
}
// 查询自定义地区详细
export function getTreeDataList() {
return request({
url: '/system/DiyCity/getTreeData',
method: 'get'
})
}
// 新增自定义地区
// 新增城市
export function addDiyCity(data) {
return request({
url: '/system/DiyCity',
@ -41,7 +26,7 @@ export function addDiyCity(data) {
})
}
// 修改自定义地区
// 修改城市
export function updateDiyCity(data) {
return request({
url: '/system/DiyCity',
@ -50,18 +35,30 @@ export function updateDiyCity(data) {
})
}
// 删除自定义地区
export function delDiyCity(ids) {
// 删除城市
export function delDiyCity(id) {
return request({
url: '/system/DiyCity/' + ids,
url: '/system/DiyCity/' + id,
method: 'delete'
})
}
// 手动触发师傅暂停状态自动恢复
export function manualResumeWorkerStatus() {
// 查询城市树结构
export function getDiyCityTree() {
return request({
url: '/system/DiyCity/manualResumeWorkerStatus',
method: 'post'
url: '/system/DiyCity/tree',
method: 'get'
})
}
// 查询一级城市parent_id=0
export function getFirstLevelCities() {
return request({
url: '/system/DiyCity/list',
method: 'get',
params: {
parentId: 0,
pageSize: 1000
}
})
}

View File

@ -48,3 +48,15 @@ export function delOrderLog(id) {
method: 'delete'
})
}
// 查询退款历史记录
export function getRefundHistory(orderId) {
return request({
url: '/system/OrderLog/list',
method: 'get',
params: {
orderId: orderId,
title: '退款'
}
})
}

View File

@ -1,5 +1,13 @@
import request from '@/utils/request'
// 根据订单ID获取支付信息
export function getPaymentByOrderId(orderId) {
return request({
url: `/system/UsersPayBefor/getByOrderId/${orderId}`,
method: 'get'
})
}
// 统一退款
export function unifiedRefund(data) {
return request({

File diff suppressed because it is too large Load Diff

View File

@ -412,7 +412,7 @@
<!-- 统一退款对话框 -->
<UnifiedRefundDialog
:visible.sync="unifiedRefundDialogVisible"
:orderId="currentRefundOrder ? currentRefundOrder.orderId : ''"
:orderId="currentRefundOrder ? currentRefundOrder.mainOrderId : ''"
:paymentData="currentRefundPaymentData"
@success="handleRefundSuccess"
/>
@ -1326,12 +1326,12 @@ export default {
handleUnifiedRefund(row) {
this.currentRefundOrder = row;
this.currentRefundPaymentData = {
wechatAmount: row.payPrice || 0,
balanceAmount: 0,
shoppingGoldAmount: 0,
serviceGoldAmount: 0,
memberDiscountAmount: 0,
couponAmount: 0
wxmoney: row.payPrice || 0,
yemoney: 0,
shopmoney: 0,
servicemoney: 0,
membermoney: 0,
couponmoney: 0
};
this.unifiedRefundDialogVisible = true;
}

View File

@ -225,12 +225,10 @@
<el-option v-for="cate in serviceCateList" :key="cate.id" :label="cate.title" :value="cate.id" />
</el-select>
</el-form-item>
<el-form-item label="保证金" prop="margin">
<el-input v-model="form.margin" placeholder="请输入保证金" />
</el-form-item>
<el-form-item label="所需技能" prop="skillIds">
<el-input v-model="form.skillIds" type="textarea" placeholder="请输入内容" />
<el-form-item label="邮费" prop="postage">
<el-input v-model="form.postage" placeholder="请输入邮费0或者不输入就是包邮" />
</el-form-item>
</el-tab-pane>
<el-tab-pane label="营销配置" name="marketing">
<el-form-item label="销量" prop="sales" required>

View File

@ -18,7 +18,7 @@
</el-button>
</div>
</div>
<!-- 一级分类网格布局 -->
<div class="category-grid">
<div
@ -32,10 +32,10 @@
<div class="card-content">
<!-- 图标区域 -->
<div class="card-icon">
<image-preview
v-if="category.icon"
:src="category.icon"
:width="32"
<image-preview
v-if="category.icon"
:src="category.icon"
:width="32"
:height="32"
style="border-radius: 4px;"
/>
@ -43,14 +43,14 @@
<i class="el-icon-folder" style="font-size: 20px; color: #409EFF;"></i>
</div>
</div>
<!-- 信息区域 -->
<div class="card-info">
<div class="card-title">{{ category.title }}</div>
<div class="card-meta">
<dict-tag :options="dict.type.service_sate_type" :value="category.type" size="mini"/>
<el-tag
size="mini"
<el-tag
size="mini"
:type="category.status === 1 ? 'success' : 'danger'"
effect="light"
>
@ -68,16 +68,32 @@
<i class="el-icon-sort"></i> {{ category.sort }}
</span>
</div>
<!-- 城市显示 -->
<div class="card-cities" v-if="getCityArray(category.city) && getCityArray(category.city).length > 0">
<el-tag
v-for="cityId in getCityArray(category.city)"
:key="cityId"
size="mini"
type="info"
effect="light"
style="margin: 1px; font-size: 10px;"
>
{{ getCityNameById(cityId) }}
</el-tag>
</div>
<div class="card-cities" v-else>
<span style="font-size: 10px; color: #c0c4cc;">全部城市</span>
</div>
</div>
</div>
<!-- 操作区域 -->
<div class="card-actions">
<div class="action-buttons">
<el-tooltip content="编辑分类" placement="top">
<el-button
size="mini"
type="primary"
<el-button
size="mini"
type="primary"
plain
@click.stop="handleEditFirstLevel(category)"
class="action-btn edit-btn"
@ -86,9 +102,9 @@
</el-button>
</el-tooltip>
<el-tooltip content="删除分类" placement="top">
<el-button
size="mini"
type="danger"
<el-button
size="mini"
type="danger"
plain
@click.stop="handleDeleteFirstLevel(category)"
class="action-btn delete-btn"
@ -100,7 +116,7 @@
</div>
</div>
</div>
<!-- 显示更多按钮和统计信息 -->
<div class="grid-footer">
<div class="grid-stats">
@ -109,17 +125,17 @@
</span>
</div>
<div class="grid-actions">
<el-button
<el-button
v-if="shouldShowMoreButton"
type="text"
type="text"
size="small"
@click="showAllFirstLevel = true"
>
<i class="el-icon-arrow-down"></i> 显示更多 ({{ filteredFirstLevelList.length - defaultShowCount }})
</el-button>
<el-button
<el-button
v-if="showAllFirstLevel && !firstLevelSearch"
type="text"
type="text"
size="small"
@click="showAllFirstLevel = false"
>
@ -127,7 +143,7 @@
</el-button>
</div>
</div>
<!-- 空状态 -->
<div v-if="firstLevelList.length === 0" class="empty-state">
<i class="el-icon-folder-add" style="font-size: 48px; color: #ddd;"></i>
@ -153,10 +169,10 @@
prefix-icon="el-icon-search"
style="width: 200px; margin-right: 10px;"
/>
<el-button
v-if="selectedFirstLevel"
type="success"
size="small"
<el-button
v-if="selectedFirstLevel"
type="success"
size="small"
@click="handleAddSecondLevel"
>
<i class="el-icon-plus"></i> 添加二级分类
@ -172,9 +188,9 @@
<!-- 二级分类表格 -->
<div v-else>
<el-table
:data="filteredSecondLevelList"
border
<el-table
:data="filteredSecondLevelList"
border
style="width: 100%"
:empty-text="'暂无二级分类'"
>
@ -185,20 +201,20 @@
</el-tag>
</template>
</el-table-column>
<el-table-column prop="title" label="分类名称" width="150">
<template slot-scope="scope">
<i class="el-icon-document" style="margin-right: 8px; color: #67C23A;"></i>
{{ scope.row.title }}
</template>
</el-table-column>
<el-table-column prop="sort" label="排序" width="60" align="center">
<template slot-scope="scope">
<el-tag size="mini" effect="plain">{{ scope.row.sort }}</el-tag>
</template>
</el-table-column>
<el-table-column label="状态" width="60" align="center">
<template slot-scope="scope">
<el-switch
@ -209,26 +225,44 @@
></el-switch>
</template>
</el-table-column>
<el-table-column prop="browse" label="浏览量" width="70" align="center">
<template slot-scope="scope">
<span>{{ scope.row.browse || 0 }}</span>
</template>
</el-table-column>
<el-table-column label="类型" width="80" align="center">
<template slot-scope="scope">
<dict-tag :options="dict.type.service_sate_type" :value="scope.row.type"/>
</template>
</el-table-column>
<el-table-column prop="icon" label="图标" width="60" align="center">
<template slot-scope="scope">
<image-preview v-if="scope.row.icon" :src="scope.row.icon" :width="30" :height="30"/>
<span v-else style="color: #ccc;"></span>
</template>
</el-table-column>
<el-table-column label="适用城市" width="120" align="center">
<template slot-scope="scope">
<div v-if="getCityArray(scope.row.city) && getCityArray(scope.row.city).length > 0">
<el-tag
v-for="cityId in getCityArray(scope.row.city)"
:key="cityId"
size="mini"
type="info"
effect="light"
style="margin: 2px;"
>
{{ getCityNameById(cityId) }}
</el-tag>
</div>
<span v-else style="color: #ccc; font-size: 12px;">全部城市</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="handleEditSecondLevel(scope.row)">
@ -254,7 +288,7 @@
</el-card>
<!-- 添加/编辑一级分类对话框 -->
<el-dialog :title="firstLevelTitle" :visible.sync="firstLevelDialogVisible" width="500px">
<el-dialog :title="firstLevelTitle" :visible.sync="firstLevelDialogVisible" width="600px">
<el-form ref="firstLevelForm" :model="firstLevelForm" :rules="firstLevelRules" label-width="100px" :validate-on-rule-change="false">
<el-form-item label="分类名称" prop="title">
<el-input v-model="firstLevelForm.title" placeholder="请输入一级分类名称" />
@ -280,6 +314,67 @@
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="适用城市" prop="city">
<el-select
v-model="firstLevelForm.city"
multiple
filterable
placeholder="请选择适用城市"
style="width: 100%;"
:loading="cityLoading"
@change="handleFirstLevelCityChange"
:collapse-tags-tooltip="true"
:class="{ 'city-select-loading': cityLoading }"
no-data-text="暂无城市数据,请检查网络连接或联系管理员"
>
<el-option
v-for="city in cityList"
:key="city.id"
:label="city.title"
:value="city.id"
>
<span style="float: left">{{ city.title }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">
<i class="el-icon-location"></i>
</span>
</el-option>
<!-- 空数据提示 -->
<el-option v-if="!cityLoading && cityList.length === 0" disabled>
<span style="color: #c0c4cc;">暂无城市数据</span>
</el-option>
</el-select>
<!-- 调试信息 -->
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i> 城市列表状态: {{ cityLoading ? '加载中...' : `已加载 ${cityList.length} 个城市` }}
<el-button
v-if="!cityLoading && cityList.length === 0"
type="text"
size="mini"
@click="getCityList"
style="margin-left: 10px;"
>
<i class="el-icon-refresh"></i> 重新加载
</el-button>
</div>
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i> 可多选城市不选择则适用于所有城市一级分类的城市设置会影响其下所有二级分类的默认城市范围
</div>
<!-- 已选择的城市标签显示 -->
<div v-if="firstLevelForm.city && firstLevelForm.city.length > 0" class="city-tags-container">
<el-tag
v-for="cityId in firstLevelForm.city"
:key="cityId"
size="small"
type="success"
effect="light"
closable
@close="removeFirstLevelCity(cityId)"
class="city-tag"
>
{{ getCityNameById(cityId) }}
</el-tag>
</div>
</el-form-item>
<el-form-item label="图标" prop="icon">
<image-upload v-model="firstLevelForm.icon"/>
</el-form-item>
@ -291,21 +386,21 @@
</el-dialog>
<!-- 添加/编辑二级分类对话框 -->
<el-dialog :title="secondLevelTitle" :visible.sync="secondLevelDialogVisible" width="500px">
<el-dialog :title="secondLevelTitle" :visible.sync="secondLevelDialogVisible" width="600px">
<el-form ref="secondLevelForm" :model="secondLevelForm" :rules="secondLevelRules" label-width="100px">
<el-form-item label="父级分类">
<el-input
:value="selectedFirstLevel ? selectedFirstLevel.title : ''"
<el-input
:value="selectedFirstLevel ? selectedFirstLevel.title : ''"
disabled
>
<template slot="prepend">
<i class="el-icon-folder" style="color: #409EFF;"></i>
</template>
<template slot="append">
<dict-tag
v-if="selectedFirstLevel && selectedFirstLevel.type !== null"
:options="dict.type.service_sate_type"
:value="selectedFirstLevel.type"
<dict-tag
v-if="selectedFirstLevel && selectedFirstLevel.type !== null"
:options="dict.type.service_sate_type"
:value="selectedFirstLevel.type"
size="mini"
/>
</template>
@ -327,15 +422,75 @@
<el-input-number v-model="secondLevelForm.browse" :min="0" style="width: 100%;" />
</el-form-item>
<el-form-item label="类型" prop="type">
<el-input
:value="getTypeLabel(secondLevelForm.type)"
disabled
<el-input
:value="getTypeLabel(secondLevelForm.type)"
disabled
placeholder="跟随父级分类类型"
/>
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i> 二级分类的类型自动跟随父级分类
</div>
</el-form-item>
<el-form-item label="适用城市" prop="city">
<el-select
v-model="secondLevelForm.city"
multiple
filterable
placeholder="请选择适用城市"
style="width: 100%;"
:loading="cityLoading"
@change="handleCityChange"
:class="{ 'city-select-loading': cityLoading }"
no-data-text="暂无城市数据,请检查网络连接或联系管理员"
>
<!-- <el-option-->
<!-- v-for="city in cityList"-->
<!-- :key="city.id"-->
<!-- :label="city.title"-->
<!-- :value="city.id"-->
<!-- >-->
<!-- <span style="float: left">{{ city.title }}</span>-->
<!-- <span style="float: right; color: #8492a6; font-size: 13px">-->
<!-- <i class="el-icon-location"></i>-->
<!-- </span>-->
<!-- </el-option>-->
<!-- &lt;!&ndash; 空数据提示 &ndash;&gt;-->
<!-- <el-option v-if="!cityLoading && cityList.length === 0" disabled>-->
<!-- <span style="color: #c0c4cc;">暂无城市数据</span>-->
<!-- </el-option>-->
</el-select>
<!-- 调试信息 -->
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i> 城市列表状态: {{ cityLoading ? '加载中...' : `已加载 ${cityList.length} 个城市` }}
<el-button
v-if="!cityLoading && cityList.length === 0"
type="text"
size="mini"
@click="getCityList"
style="margin-left: 10px;"
>
<i class="el-icon-refresh"></i> 重新加载
</el-button>
</div>
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i> 可多选城市不选择则适用于所有城市二级分类的城市设置会继承父级分类的城市范围但可以进一步限制
</div>
<!-- 已选择的城市标签显示 -->
<div v-if="secondLevelForm.city && secondLevelForm.city.length > 0" class="city-tags-container">
<el-tag
v-for="cityId in secondLevelForm.city"
:key="cityId"
size="small"
type="success"
effect="light"
closable
@close="removeCity(cityId)"
class="city-tag"
>
{{ getCityNameById(cityId) }}
</el-tag>
</div>
</el-form-item>
<el-form-item label="图标" prop="icon">
<image-upload v-model="secondLevelForm.icon"/>
</el-form-item>
@ -350,6 +505,7 @@
<script>
import { listServiceCate, getServiceCate, delServiceCate, addServiceCate, updateServiceCate, changefenleiStatus } from "@/api/system/ServiceCate"
import { getFirstLevelCities } from "@/api/system/DiyCity"
import { parseTime } from "@/utils/index"
export default {
@ -371,7 +527,7 @@ export default {
type: [{ required: true, message: "类型不能为空", trigger: "change" }],
},
firstLevelLoading: false,
//
secondLevelList: [],
secondLevelSearch: "",
@ -384,33 +540,37 @@ export default {
status: [{ required: true, message: "状态不能为空", trigger: "change" }],
type: [{ required: true, message: "类型不能为空", trigger: "change" }],
},
//
secondLevelTotal: 0,
secondLevelPageNum: 1,
secondLevelPageSize: 10,
//
allCategoryList: [],
//
showAllFirstLevel: false,
defaultShowCount: 20
defaultShowCount: 20,
//
cityList: [],
cityLoading: false,
}
},
computed: {
//
filteredFirstLevelList() {
let filtered = this.firstLevelList
if (this.firstLevelSearch) {
filtered = this.firstLevelList.filter(item =>
filtered = this.firstLevelList.filter(item =>
item.title.toLowerCase().includes(this.firstLevelSearch.toLowerCase())
)
}
return filtered
},
//
displayedFirstLevelList() {
if (this.showAllFirstLevel || this.firstLevelSearch) {
@ -418,35 +578,36 @@ export default {
}
return this.filteredFirstLevelList.slice(0, this.defaultShowCount)
},
// ""
shouldShowMoreButton() {
return !this.showAllFirstLevel &&
!this.firstLevelSearch &&
return !this.showAllFirstLevel &&
!this.firstLevelSearch &&
this.filteredFirstLevelList.length > this.defaultShowCount
},
//
filteredSecondLevelList() {
if (!this.secondLevelSearch) return this.secondLevelList
return this.secondLevelList.filter(item =>
return this.secondLevelList.filter(item =>
item.title.toLowerCase().includes(this.secondLevelSearch.toLowerCase())
)
}
},
created() {
this.getFirstLevelList()
this.getCityList()
},
methods: {
//
parseTime,
/** 获取一级分类列表 */
getFirstLevelList() {
//
const params = {
const params = {
parentId: 0,
pageNum: 1,
pageSize: 1000 //
@ -454,7 +615,7 @@ export default {
listServiceCate(params).then(response => {
this.firstLevelList = response.rows || []
})
//
listServiceCate({
pageNum: 1,
@ -463,10 +624,10 @@ export default {
this.allCategoryList = response.rows || []
})
},
/** 获取二级分类列表 */
getSecondLevelList(parentId) {
const params = {
const params = {
parentId: parentId,
pageNum: this.secondLevelPageNum,
pageSize: this.secondLevelPageSize
@ -476,7 +637,7 @@ export default {
this.secondLevelTotal = response.total || 0
})
},
/** 选择一级分类 */
selectFirstLevel(category) {
this.selectedFirstLevel = category
@ -486,12 +647,12 @@ export default {
this.secondLevelSearch = ""
this.getSecondLevelList(category.id)
},
/** 获取子分类数量 */
getSubCategoryCount(parentId) {
return this.allCategoryList.filter(item => item.parentId === parentId).length
},
/** 状态修改 */
handleStatusChange(row) {
let text = row.status === 0 ? "启用" : "停用"
@ -503,26 +664,44 @@ export default {
row.status = row.status === 0 ? 1 : 0
})
},
// ========== ==========
/** 添加一级分类 */
handleAddFirstLevel() {
this.resetFirstLevelForm()
//
if (this.cityList.length === 0) {
this.getCityList()
}
this.firstLevelDialogVisible = true
this.firstLevelTitle = "添加一级分类"
},
/** 编辑一级分类 */
handleEditFirstLevel(row) {
this.resetFirstLevelForm()
//
if (this.cityList.length === 0) {
this.getCityList()
}
getServiceCate(row.id).then(response => {
this.firstLevelForm = response.data
//
if (this.firstLevelForm.city && typeof this.firstLevelForm.city === 'string') {
try {
this.firstLevelForm.city = JSON.parse(this.firstLevelForm.city);
} catch (e) {
this.firstLevelForm.city = [];
}
} else if (!this.firstLevelForm.city) {
this.firstLevelForm.city = [];
}
this.firstLevelDialogVisible = true
this.firstLevelTitle = "编辑一级分类"
})
},
/** 删除一级分类 */
handleDeleteFirstLevel(row) {
//
@ -532,7 +711,7 @@ export default {
this.$modal.msgError("该分类下还有二级分类,不能删除")
return
}
this.$modal.confirm('是否确认删除分类"' + row.title + '"').then(function() {
return delServiceCate(row.id)
}).then(() => {
@ -554,12 +733,18 @@ export default {
}).catch(() => {})
})
},
/** 提交一级分类 */
submitFirstLevel() {
this.$refs["firstLevelForm"].validate(valid => {
if (valid) {
this.firstLevelForm.parentId = 0 //
// JSON
if (Array.isArray(this.firstLevelForm.city)) {
this.firstLevelForm.city = JSON.stringify(this.firstLevelForm.city);
}
this.firstLevelLoading = true; //
const done = () => { this.firstLevelLoading = false; };
const handleError = (err) => {
@ -598,7 +783,7 @@ export default {
}
})
},
/** 重置一级分类表单 */
resetFirstLevelForm() {
this.firstLevelForm = {
@ -609,34 +794,53 @@ export default {
status: 1,
browse: 0,
type: 1,
parentId: 0
parentId: 0,
city: [] //
}
this.resetForm("firstLevelForm")
},
// ========== ==========
/** 添加二级分类 */
handleAddSecondLevel() {
this.resetSecondLevelForm()
//
this.secondLevelForm.type = this.selectedFirstLevel ? this.selectedFirstLevel.type : 1
//
if (this.cityList.length === 0) {
this.getCityList()
}
this.secondLevelDialogVisible = true
this.secondLevelTitle = "添加二级分类"
},
/** 编辑二级分类 */
handleEditSecondLevel(row) {
this.resetSecondLevelForm()
//
if (this.cityList.length === 0) {
this.getCityList()
}
getServiceCate(row.id).then(response => {
this.secondLevelForm = response.data
//
this.secondLevelForm.type = this.selectedFirstLevel ? this.selectedFirstLevel.type : this.secondLevelForm.type
//
if (this.secondLevelForm.city && typeof this.secondLevelForm.city === 'string') {
try {
this.secondLevelForm.city = JSON.parse(this.secondLevelForm.city);
} catch (e) {
this.secondLevelForm.city = [];
}
} else if (!this.secondLevelForm.city) {
this.secondLevelForm.city = [];
}
this.secondLevelDialogVisible = true
this.secondLevelTitle = "编辑二级分类"
})
},
/** 删除二级分类 */
handleDeleteSecondLevel(row) {
this.$modal.confirm('是否确认删除分类"' + row.title + '"').then(function() {
@ -650,14 +854,19 @@ export default {
})
}).catch(() => {})
},
/** 提交二级分类 */
submitSecondLevel() {
this.$refs["secondLevelForm"].validate(valid => {
if (valid) {
this.secondLevelForm.parentId = this.selectedFirstLevel ? this.selectedFirstLevel.id : 0 // ID
this.secondLevelForm.type = this.selectedFirstLevel ? this.selectedFirstLevel.type : this.secondLevelForm.type //
// JSON
if (Array.isArray(this.secondLevelForm.city)) {
this.secondLevelForm.city = JSON.stringify(this.secondLevelForm.city);
}
if (this.secondLevelForm.id != null) {
updateServiceCate(this.secondLevelForm).then(response => {
this.$modal.msgSuccess("修改成功")
@ -682,7 +891,7 @@ export default {
}
})
},
/** 重置二级分类表单 */
resetSecondLevelForm() {
this.secondLevelForm = {
@ -693,7 +902,8 @@ export default {
status: 1,
browse: 0,
type: null, //
parentId: null
parentId: null,
city: [] //
}
this.resetForm("secondLevelForm")
},
@ -703,6 +913,71 @@ export default {
const dict = this.dict.type.service_sate_type
const found = dict.find(item => parseInt(item.value) === value)
return found ? found.label : value
},
/** 根据城市ID获取城市名称 */
getCityNameById(id) {
const city = this.cityList.find(item => item.id === id);
return city ? city.title : id; // 使titlename
},
/** 获取城市列表 */
getCityList() {
console.log('开始获取城市列表...');
this.cityLoading = true;
getFirstLevelCities().then(response => {
console.log('城市API响应:', response);
// 使response.rowsresponse.data
this.cityList = response.rows || [];
console.log('设置城市列表:', this.cityList);
this.cityLoading = false;
}).catch(error => {
console.error("获取城市列表失败:", error);
this.cityLoading = false;
});
},
/** 城市选择变化处理 */
handleCityChange(value) {
this.secondLevelForm.city = value;
console.log('选择的城市:', value);
},
/** 移除城市标签 */
removeCity(cityId) {
const index = this.secondLevelForm.city.indexOf(cityId);
if (index > -1) {
this.secondLevelForm.city.splice(index, 1);
}
},
/** 获取城市数组,处理字符串和数组两种格式 */
getCityArray(cityString) {
if (typeof cityString === 'string') {
try {
return JSON.parse(cityString);
} catch (e) {
console.error("解析城市字符串失败:", e);
return [];
}
} else if (Array.isArray(cityString)) {
return cityString;
}
return [];
},
/** 一级分类城市选择变化处理 */
handleFirstLevelCityChange(value) {
this.firstLevelForm.city = value;
console.log('一级分类选择的城市:', value);
},
/** 移除一级分类城市标签 */
removeFirstLevelCity(cityId) {
const index = this.firstLevelForm.city.indexOf(cityId);
if (index > -1) {
this.firstLevelForm.city.splice(index, 1);
}
}
}
}
@ -814,6 +1089,23 @@ export default {
gap: 2px;
}
.card-cities {
margin-top: 4px;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 2px;
max-height: 40px;
overflow: hidden;
}
.card-cities .el-tag {
max-width: 60px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-actions {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-top: 1px solid rgba(0, 0, 0, 0.06);
@ -928,4 +1220,36 @@ export default {
.clearfix:after {
clear: both;
}
/* 城市选择相关样式 */
.el-select .el-select__tags {
max-width: calc(100% - 30px);
}
.city-tags-container {
margin-top: 8px;
padding: 8px;
background: #f8f9fa;
border-radius: 4px;
border: 1px solid #e9ecef;
}
.city-tag {
margin: 2px;
transition: all 0.2s ease;
}
.city-tag:hover {
transform: scale(1.05);
}
/* 城市选择器加载状态样式 */
.city-select-loading .el-select__caret {
animation: rotate 1s linear infinite;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>

View File

@ -135,6 +135,23 @@
</div>
</template>
</el-table-column>
<el-table-column label="适用城市" align="center" prop="city" width="120">
<template slot-scope="scope">
<div v-if="getCityArray(scope.row.city) && getCityArray(scope.row.city).length > 0">
<el-tag
v-for="cityId in getCityArray(scope.row.city)"
:key="cityId"
size="mini"
type="info"
effect="light"
style="margin: 2px;"
>
{{ getCityNameById(cityId) }}
</el-tag>
</div>
<span v-else style="color: #c0c4cc; font-size: 12px;">全部城市</span>
</template>
</el-table-column>
<el-table-column label="标题" align="center" prop="title" />
<el-table-column label="图标" align="center" prop="icon" width="100">
<template slot-scope="scope">
@ -357,6 +374,68 @@
</span>
</div>
</el-form-item>
<el-form-item label="适用城市" prop="city">
<el-select
v-model="form.cityArray"
multiple
filterable
placeholder="请选择适用城市"
style="width: 100%;"
:loading="cityLoading"
@change="handleCityChange"
collapse-tags
:collapse-tags-tooltip="true"
:class="{ 'city-select-loading': cityLoading }"
no-data-text="暂无城市数据,请检查网络连接或联系管理员"
>
<el-option
v-for="city in cityList"
:key="city.id"
:label="city.title"
:value="city.id"
>
<span style="float: left">{{ city.title }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">
<i class="el-icon-location"></i>
</span>
</el-option>
<!-- 空数据提示 -->
<el-option v-if="!cityLoading && cityList.length === 0" disabled>
<span style="color: #c0c4cc;">暂无城市数据</span>
</el-option>
</el-select>
<!-- 调试信息 -->
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i> 城市列表状态: {{ cityLoading ? '加载中...' : `已加载 ${cityList.length} 个城市` }}
<el-button
v-if="!cityLoading && cityList.length === 0"
type="text"
size="mini"
@click="getCityList"
style="margin-left: 10px;"
>
<i class="el-icon-refresh"></i> 重新加载
</el-button>
</div>
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i> 可多选城市不选择则适用于所有城市
</div>
<!-- 已选择的城市标签显示 -->
<div v-if="form.cityArray && form.cityArray.length > 0" class="city-tags-container">
<el-tag
v-for="cityId in form.cityArray"
:key="cityId"
size="small"
type="success"
effect="light"
closable
@close="removeCity(cityId)"
class="city-tag"
>
{{ getCityNameById(cityId) }}
</el-tag>
</div>
</el-form-item>
<el-form-item label="保证金" prop="margin">
<el-input v-model="form.margin" placeholder="请输入保证金" />
</el-form-item>
@ -720,6 +799,7 @@
<script>
import { listServiceGoods, getServiceGoods, delServiceGoods, addServiceGoods, updateServiceGoods ,changefenleiStatus,selectServiceCateList,getSiteSkillList,getlistworkerlist} from "@/api/system/ServiceGoods"
import { getAllServiceCateList, addServiceCate } from "@/api/system/ServiceCate"
import { getFirstLevelCities } from "@/api/system/DiyCity"
import Editor from '@/components/Editor'
export default {
@ -807,6 +887,8 @@ export default {
questionsArray: [], //
firstCateId: null, // ID
secondCateId: null, // ID
city: null, // JSON
cityArray: [], //
},
//
rules: {
@ -852,6 +934,10 @@ export default {
newBasicTag: '',
saveTimeout: null, //
disableGroupAndFixed: false, //
//
cityList: [],
cityLoading: false,
}
},
created() {
@ -861,6 +947,7 @@ export default {
this.testSkillList();
this.getlistworkerdatalist();
this.testJsonConversion(); // JSON
this.getCityList(); //
},
watch: {
// UI
@ -955,10 +1042,13 @@ export default {
deletedAt: null,
questionsArray: [], //
questions: null, // JSON
city: null, // JSON
cityArray: [], //
}
// 使Vue.set
this.$set(this.form, 'skillIdsArray', []);
this.$set(this.form, 'basicArray', []);
this.$set(this.form, 'cityArray', []); //
//
this.showBasicInput = false;
this.newBasicTag = '';
@ -1033,6 +1123,7 @@ export default {
this.$set(this.form, 'questionsArray', []);
this.$set(this.form, 'firstCateId', null);
this.$set(this.form, 'secondCateId', null);
this.$set(this.form, 'cityArray', []); //
if (this.siteSkillList.length === 0) {
this.getSiteSkillList();
}
@ -1200,6 +1291,47 @@ export default {
this.$set(this.form, 'basicArray', []);
}
// JSON
if (this.form.city) {
try {
let cityArray = [];
console.log('原始城市数据:', this.form.city, '类型:', typeof this.form.city);
if (typeof this.form.city === 'string') {
// JSON
try {
const parsedCity = JSON.parse(this.form.city);
if (Array.isArray(parsedCity)) {
cityArray = parsedCity.map(id => parseInt(id)).filter(id => !isNaN(id));
} else {
// JSON
cityArray = this.form.city.split(',').map(id => {
const numId = parseInt(id.trim());
return isNaN(numId) ? null : numId;
}).filter(id => id !== null);
}
} catch (jsonError) {
// JSON
cityArray = this.form.city.split(',').map(id => {
const numId = parseInt(id.trim());
return isNaN(numId) ? null : numId;
}).filter(id => id !== null);
}
} else if (Array.isArray(this.form.city)) {
// 使
cityArray = this.form.city.map(id => parseInt(id)).filter(id => !isNaN(id));
}
this.$set(this.form, 'cityArray', cityArray);
console.log('转换后的城市数组:', this.form.cityArray);
} catch (e) {
console.error('城市数据转换错误:', e);
this.$set(this.form, 'cityArray', []);
}
} else {
this.$set(this.form, 'cityArray', []);
}
//
this.showBasicInput = false;
this.newBasicTag = '';
@ -1381,6 +1513,17 @@ export default {
}
console.log('提交的基检现象JSON字符串:', this.form.basic);
// JSON
console.log('提交前的城市数组:', this.form.cityArray);
if (this.form.cityArray && Array.isArray(this.form.cityArray) && this.form.cityArray.length > 0) {
//
const validCityIds = this.form.cityArray.filter(id => id !== null && id !== undefined && !isNaN(id));
this.form.city = validCityIds.length > 0 ? JSON.stringify(validCityIds) : null;
} else {
this.form.city = null;
}
console.log('提交的城市JSON字符串:', this.form.city);
//
if (this.form.price) {
this.form.price = parseFloat(this.form.price);
@ -2098,6 +2241,75 @@ export default {
this.disableGroupAndFixed = false;
}
},
// ========== ==========
/** 获取城市列表 */
getCityList() {
console.log('开始获取城市列表...');
this.cityLoading = true;
getFirstLevelCities().then(response => {
console.log('城市API响应:', response);
this.cityList = response.rows || [];
console.log('设置城市列表:', this.cityList);
this.cityLoading = false;
}).catch(error => {
console.error("获取城市列表失败:", error);
this.cityLoading = false;
});
},
/** 城市选择变化处理 */
handleCityChange(value) {
console.log('城市选择变化:', value);
// value
const cityArray = Array.isArray(value) ? value : [];
this.$set(this.form, 'cityArray', cityArray);
console.log('设置后的城市数组:', this.form.cityArray);
},
/** 根据城市ID获取城市名称 */
getCityNameById(id) {
const city = this.cityList.find(item => item.id === id);
return city ? city.title : id;
},
/** 解析城市字符串为数组 */
getCityArray(cityString) {
if (!cityString) return [];
try {
if (typeof cityString === 'string') {
// JSON
try {
const parsed = JSON.parse(cityString);
if (Array.isArray(parsed)) {
return parsed.map(id => Number(id)).filter(id => !isNaN(id) && id !== 0);
}
} catch (e) {
// JSON
return cityString.split(',').map(id => Number(id.trim())).filter(id => !isNaN(id) && id !== 0);
}
} else if (Array.isArray(cityString)) {
return cityString.map(id => Number(id)).filter(id => !isNaN(id) && id !== 0);
}
} catch (e) {
console.error('解析城市数据失败:', e);
}
return [];
},
/** 移除城市 */
removeCity(cityId) {
if (!this.form.cityArray) {
this.$set(this.form, 'cityArray', []);
return;
}
const index = this.form.cityArray.indexOf(cityId);
if (index > -1) {
this.form.cityArray.splice(index, 1);
console.log('删除城市:', cityId, '剩余:', this.form.cityArray);
}
},
}
}
</script>
@ -2221,4 +2433,39 @@ export default {
margin-right: 6px;
color: #0ea5e9;
}
/* 城市选择器样式 */
.city-tags-container {
margin-top: 8px;
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.city-tag {
margin: 0;
transition: all 0.2s;
}
.city-tag:hover {
transform: scale(1.05);
}
.city-select-loading {
opacity: 0.7;
}
.city-select-loading .el-select__tags {
pointer-events: none;
}
/* 城市选择器加载动画 */
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.city-select-loading .el-select__caret::before {
animation: rotate 1s linear infinite;
}
</style>