feat: 新增多角色系统(派单/分润/推广/区域)

- 后端:RlzDispatch/Profit/Promotion/Region 控制器、服务、Mapper、领域模型
- 权限:MethodSecurityConfig + PermissionInterceptor
- 管理后台:派单/分润/推广/区域 页面与 API
- Android 陪护端:派单/运营/退款 Fragment 及布局
- 小程序:推广员子包、派单/运营/退款/检索子包、自定义 tabBar
- 文档:多角色系统方案、角色权限矩阵、用户操作手册等

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
renjianbo
2026-10-12 00:09:45 +08:00
parent 7562a5f20c
commit 805ed0298b
170 changed files with 8876 additions and 705 deletions

View File

@@ -25,83 +25,181 @@ import com.ruilaizi.service.utils.checkVersionsUtils.ProfileSpUtils;
public class MainActivity extends BaseActivity implements View.OnClickListener {
private FragmentManager fm;
private HomeFragment mHomeFragment;
private TraceFragment traceFragment;
private MyFragment mMineFragment;
private Fragment mHomeFragment; // Tab1: role-specific
private Fragment traceFragment; // Tab2: order management
private Fragment mMineFragment; // Tab3: profile
private Fragment mCurrent;
private ActivityMainBinding bingding;
private String userType = "B"; // default caregiver
// Tab labels per role
private String tab1Label, tab2Label, tab3Label;
private int tab1Icon, tab1IconActive, tab2Icon, tab2IconActive, tab3Icon, tab3IconActive;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bingding = DataBindingUtil.setContentView(this, R.layout.activity_main);
// Read user role from stored profile
readUserType();
configureTabs();
initView();
//给个初始的个人信息,防止其他地方调用会出现空指针
boolean b= ProfileSpUtils.getInstance().isLogin();
Log.e("是否登陆",b+"");
// Ensure login bean exists for null safety
boolean b = ProfileSpUtils.getInstance().isLogin();
Log.e("是否登陆", b + "");
if (!ProfileSpUtils.getInstance().isLogin()) {
loginBean loginBean = new loginBean();
com.ruilaizi.service.main.my.entity.loginBean.DataBean dataBean = new loginBean.DataBean();
loginBean.DataBean dataBean = new loginBean.DataBean();
dataBean.setNickName("123");
loginBean.setData(dataBean);
ProfileSpUtils.getInstance().saveProfile(loginBean);
}
//设置公共参数
// Set common HTTP headers
loginBean userProfie = ProfileSpUtils.getInstance().getUserProfie();
if (userProfie.getData() != null) {
String token = userProfie.getData().getToken();
HttpHeaders headers = new HttpHeaders();
headers.put("Authorization", "Bearer " + token); //header不支持中文,不允许有特殊字符
headers.put("Authorization", "Bearer " + token);
OkGo.getInstance().addCommonHeaders(headers);
}
initFragment();
}
/**
* Read userType from stored login profile
*/
private void readUserType() {
try {
loginBean profile = ProfileSpUtils.getInstance().getUserProfie();
if (profile != null && profile.getData() != null && profile.getData().getUserType() != null) {
userType = profile.getData().getUserType();
}
} catch (Exception e) {
Log.e("MainActivity", "Failed to read userType", e);
}
Log.e("MainActivity", "userType=" + userType);
}
/**
* Configure tab labels, icons based on role
*/
private void configureTabs() {
switch (userType) {
case "05": // 调度员
tab1Label = "待派单";
tab2Label = "全部订单";
tab3Label = "我的";
tab1Icon = R.mipmap.icon_task;
tab1IconActive = R.mipmap.icon_task;
tab2Icon = R.mipmap.icon_kehuhui;
tab2IconActive = R.mipmap.icon_kehu;
tab3Icon = R.mipmap.icon_wodehui;
tab3IconActive = R.mipmap.icon_wode;
break;
case "04": // 客服
tab1Label = "退款审核";
tab2Label = "全部订单";
tab3Label = "我的";
tab1Icon = R.mipmap.icon_task;
tab1IconActive = R.mipmap.icon_task;
tab2Icon = R.mipmap.icon_kehuhui;
tab2IconActive = R.mipmap.icon_kehu;
tab3Icon = R.mipmap.icon_wodehui;
tab3IconActive = R.mipmap.icon_wode;
break;
case "03": // 运营经理
tab1Label = "运营看板";
tab2Label = "全部订单";
tab3Label = "我的";
tab1Icon = R.mipmap.icon_task;
tab1IconActive = R.mipmap.icon_task;
tab2Icon = R.mipmap.icon_kehuhui;
tab2IconActive = R.mipmap.icon_kehu;
tab3Icon = R.mipmap.icon_wodehui;
tab3IconActive = R.mipmap.icon_wode;
break;
default: // B 陪诊师
tab1Label = "首页";
tab2Label = "客户";
tab3Label = "我的";
tab1Icon = R.mipmap.icon_task;
tab1IconActive = R.mipmap.icon_task;
tab2Icon = R.mipmap.icon_kehuhui;
tab2IconActive = R.mipmap.icon_kehu;
tab3Icon = R.mipmap.icon_wodehui;
tab3IconActive = R.mipmap.icon_wode;
break;
}
}
private void initView() {
// Set dynamic tab labels
bingding.tvHome.setText(tab1Label);
bingding.tvMap.setText(tab2Label);
bingding.tvMine.setText(tab3Label);
bingding.rlHome.setOnClickListener(this);
bingding.rlMap.setOnClickListener(this);
bingding.rlMine.setOnClickListener(this);
bingding.tvHomeImg.setBackgroundResource(R.mipmap.icon_task);
bingding.tvHomeImg.setBackgroundResource(tab1IconActive);
bingding.tvHome.setTextColor(getResources().getColor(R.color.colortheme));
}
private void initFragment() {
StatusBarUtil.transparencyBar(this); //设置状态栏全透明
StatusBarUtil.transparencyBar(this);
StatusBarUtil.setStatusBarColor(this, R.color.colortheme);
mHomeFragment = new HomeFragment();
mHomeFragment = createTab1Fragment();
fm = getSupportFragmentManager();
fm.beginTransaction();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.content_layout, mHomeFragment);
fragmentTransaction.commit();
}
/**
* Create role-specific fragment for Tab1
*/
private Fragment createTab1Fragment() {
switch (userType) {
case "05":
return new com.ruilaizi.service.main.kehu.fragment.DispatchFragment();
case "04":
return new com.ruilaizi.service.main.kehu.fragment.RefundFragment();
case "03":
return new com.ruilaizi.service.main.kehu.fragment.OpsFragment();
default:
return new HomeFragment();
}
}
@Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = fm.beginTransaction();
int id = v.getId();
if (id == R.id.rl_home) {
bingding.tvHomeImg.setBackgroundResource(R.mipmap.icon_task);
bingding.tvMapImg.setBackgroundResource(R.mipmap.icon_kehuhui);
bingding.tvMineImg.setBackgroundResource(R.mipmap.icon_wodehui);
bingding.tvHomeImg.setBackgroundResource(tab1IconActive);
bingding.tvMapImg.setBackgroundResource(tab2Icon);
bingding.tvMineImg.setBackgroundResource(tab3Icon);
bingding.tvHome.setTextColor(getResources().getColor(R.color.colortheme));
bingding.tvMap.setTextColor(getResources().getColor(R.color.colorhui));
bingding.tvMine.setTextColor(getResources().getColor(R.color.colorhui));
hideFragment(traceFragment, fragmentTransaction);
hideFragment(mMineFragment, fragmentTransaction);
if (mHomeFragment == null) {
mHomeFragment = createTab1Fragment();
fragmentTransaction.add(R.id.content_layout, mHomeFragment);
} else {
mCurrent = mHomeFragment;
fragmentTransaction.show(mHomeFragment);
}
broadcastIntent();
StatusBarUtil.transparencyBar(this); //设置状态栏全透明
StatusBarUtil.transparencyBar(this);
StatusBarUtil.setStatusBarColor(this, R.color.colortheme);
} else if (id == R.id.rl_map) {
bingding.tvHomeImg.setBackgroundResource(R.mipmap.icon_task_hui);
bingding.tvMapImg.setBackgroundResource(R.mipmap.icon_kehu);
bingding.tvMineImg.setBackgroundResource(R.mipmap.icon_wodehui);
bingding.tvHomeImg.setBackgroundResource(tab1Icon);
bingding.tvMapImg.setBackgroundResource(tab2IconActive);
bingding.tvMineImg.setBackgroundResource(tab3Icon);
bingding.tvHome.setTextColor(getResources().getColor(R.color.colorhui));
bingding.tvMap.setTextColor(getResources().getColor(R.color.colortheme));
bingding.tvMine.setTextColor(getResources().getColor(R.color.colorhui));
@@ -115,13 +213,13 @@ public class MainActivity extends BaseActivity implements View.OnClickListener {
mCurrent = traceFragment;
fragmentTransaction.show(traceFragment);
}
StatusBarUtil.transparencyBar(this); //设置状态栏全透明
StatusBarUtil.StatusBarLightMode(this); //设置白底黑字
StatusBarUtil.transparencyBar(this);
StatusBarUtil.StatusBarLightMode(this);
StatusBarUtil.setStatusBarColor(this, R.color.colorPrimary);
} else if (id == R.id.rl_mine) {
bingding.tvHomeImg.setBackgroundResource(R.mipmap.icon_task_hui);
bingding.tvMapImg.setBackgroundResource(R.mipmap.icon_kehuhui);
bingding.tvMineImg.setBackgroundResource(R.mipmap.icon_wode);
bingding.tvHomeImg.setBackgroundResource(tab1Icon);
bingding.tvMapImg.setBackgroundResource(tab2Icon);
bingding.tvMineImg.setBackgroundResource(tab3IconActive);
bingding.tvHome.setTextColor(getResources().getColor(R.color.colorhui));
bingding.tvMap.setTextColor(getResources().getColor(R.color.colorhui));
bingding.tvMine.setTextColor(getResources().getColor(R.color.colortheme));
@@ -134,7 +232,7 @@ public class MainActivity extends BaseActivity implements View.OnClickListener {
mCurrent = mMineFragment;
fragmentTransaction.show(mMineFragment);
}
StatusBarUtil.transparencyBar(this); //设置状态栏全透明
StatusBarUtil.transparencyBar(this);
StatusBarUtil.setStatusBarColor(this, R.color.colortheme);
}
fragmentTransaction.commit();

View File

@@ -0,0 +1,226 @@
package com.ruilaizi.service.main.kehu.fragment;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.cache.CacheMode;
import com.lzy.okgo.convert.StringConvert;
import com.lzy.okgo.model.Response;
import com.lzy.okrx2.adapter.ObservableResponse;
import com.ruilaizi.service.R;
import com.ruilaizi.service.base.BaseFragment;
import com.ruilaizi.service.okgonet.HttpConstants;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
/**
* DispatchFragment — 调度员:待派单订单列表 + 指派陪诊师
*/
public class DispatchFragment extends BaseFragment {
private RecyclerView recyclerView;
private OrderAdapter adapter;
private List<OrderItem> orderList = new ArrayList<>();
private List<CaregiverItem> caregiverList = new ArrayList<>();
private Dialog assignDialog;
private OrderItem selectedOrder;
private int selectedCaregiverIdx = -1;
// --- Data classes ---
static class OrderItem {
String orderId, orderNumber, orderMoney, yuguMoney, status;
String createTime, hospitalName, serviceName, cId;
}
static class CaregiverItem {
String userId, nickName, phonenumber;
}
// --- Adapter ---
class OrderAdapter extends BaseQuickAdapter<OrderItem, BaseViewHolder> {
OrderAdapter(List<OrderItem> data) {
super(R.layout.item_dispatch_order, data);
}
@Override
protected void convert(BaseViewHolder h, OrderItem item) {
h.setText(R.id.tv_order_no, item.orderNumber != null ? item.orderNumber : "#" + item.orderId);
h.setText(R.id.tv_amount, "¥" + (item.yuguMoney != null ? item.yuguMoney : item.orderMoney));
h.setText(R.id.tv_info, (item.hospitalName != null ? item.hospitalName : "") + " | " + (item.serviceName != null ? item.serviceName : ""));
h.setText(R.id.tv_time, item.createTime);
h.getView(R.id.btn_action).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showAssignDialog(item);
}
});
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mContext = getActivity();
View view = inflater.inflate(R.layout.fragment_dispatch, container, false);
recyclerView = view.findViewById(R.id.recycler_view);
adapter = new OrderAdapter(orderList);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
recyclerView.setAdapter(adapter);
loadPendingOrders();
return view;
}
private void loadPendingOrders() {
OkGo.<String>get(HttpConstants.URi_system_dispatch_pending)
.converter(new StringConvert())
.cacheMode(CacheMode.NO_CACHE)
.adapt(new ObservableResponse<String>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.Observer<Response<String>>() {
@Override public void onSubscribe(@NonNull Disposable d) {}
@Override public void onNext(@NonNull Response<String> resp) {
try {
JSONObject json = JSON.parseObject(resp.body());
if (json.getIntValue("code") == 200) {
JSONArray arr = json.getJSONArray("data");
orderList.clear();
if (arr != null) for (int i = 0; i < arr.size(); i++) {
orderList.add(JSON.toJavaObject(arr.getJSONObject(i), OrderItem.class));
}
adapter.notifyDataSetChanged();
}
} catch (Exception e) { Log.e("Dispatch", "parse err", e); }
}
@Override public void onError(@NonNull Throwable e) {
Toast.makeText(mContext, "加载失败", Toast.LENGTH_SHORT).show();
}
@Override public void onComplete() {}
});
}
private void loadCaregivers() {
caregiverList.clear();
OkGo.<String>get(HttpConstants.URi_system_dispatch_caregivers)
.converter(new StringConvert()).cacheMode(CacheMode.NO_CACHE)
.adapt(new ObservableResponse<String>())
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.Observer<Response<String>>() {
@Override public void onSubscribe(@NonNull Disposable d) {}
@Override public void onNext(@NonNull Response<String> resp) {
try {
JSONObject json = JSON.parseObject(resp.body());
if (json.getIntValue("code") == 200) {
JSONArray arr = json.getJSONArray("data");
if (arr != null) for (int i = 0; i < arr.size(); i++) {
caregiverList.add(JSON.toJavaObject(arr.getJSONObject(i), CaregiverItem.class));
}
}
} catch (Exception e) { Log.e("Dispatch", "cg err", e); }
}
@Override public void onError(@NonNull Throwable e) {}
@Override public void onComplete() {}
});
}
private void showAssignDialog(OrderItem order) {
selectedOrder = order;
selectedCaregiverIdx = -1;
loadCaregivers();
assignDialog = new Dialog(mContext, R.style.DialogTheme);
View view = LayoutInflater.from(mContext).inflate(R.layout.dialog_assign, null);
assignDialog.setContentView(view);
Window window = assignDialog.getWindow();
window.setGravity(android.view.Gravity.BOTTOM);
window.setWindowAnimations(R.style.dialog_menu_animStyle);
window.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);
TextView tvNo = view.findViewById(R.id.tv_order_no);
tvNo.setText("订单: " + (order.orderNumber != null ? order.orderNumber : "#" + order.orderId));
ListView listView = view.findViewById(R.id.list_caregivers);
List<String> names = new ArrayList<>();
for (CaregiverItem c : caregiverList) {
names.add((c.nickName != null ? c.nickName : "") + " (" + (c.phonenumber != null ? c.phonenumber : "") + ")");
}
android.widget.ArrayAdapter<String> la = new android.widget.ArrayAdapter<>(mContext,
android.R.layout.simple_list_item_single_choice, names);
listView.setAdapter(la);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override public void onItemClick(AdapterView<?> p, View v, int pos, long id) { selectedCaregiverIdx = pos; }
});
view.findViewById(R.id.btn_confirm).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
if (selectedCaregiverIdx >= 0 && selectedCaregiverIdx < caregiverList.size()) {
doAssign(caregiverList.get(selectedCaregiverIdx).userId);
} else {
Toast.makeText(mContext, "请选择陪诊师", Toast.LENGTH_SHORT).show();
}
}
});
view.findViewById(R.id.btn_cancel).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { assignDialog.dismiss(); }
});
assignDialog.show();
}
private void doAssign(String caregiverId) {
OkGo.<String>post(HttpConstants.URi_system_dispatch_assign + selectedOrder.orderId + "/" + caregiverId)
.converter(new StringConvert())
.adapt(new ObservableResponse<String>())
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.Observer<Response<String>>() {
@Override public void onSubscribe(@NonNull Disposable d) {}
@Override public void onNext(@NonNull Response<String> resp) {
try {
JSONObject json = JSON.parseObject(resp.body());
if (json.getIntValue("code") == 200) {
Toast.makeText(mContext, "派单成功", Toast.LENGTH_SHORT).show();
assignDialog.dismiss();
loadPendingOrders();
} else {
Toast.makeText(mContext, json.getString("msg"), Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {}
}
@Override public void onError(@NonNull Throwable e) {
Toast.makeText(mContext, "派单失败", Toast.LENGTH_SHORT).show();
}
@Override public void onComplete() {}
});
}
}

View File

@@ -0,0 +1,45 @@
package com.ruilaizi.service.main.kehu.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.Nullable;
import com.ruilaizi.service.R;
import com.ruilaizi.service.base.BaseFragment;
import com.ruilaizi.service.okgonet.HttpConstants;
/**
* OpsFragment — 运营经理:WebView 加载后台运营看板
*/
public class OpsFragment extends BaseFragment {
private WebView webView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mContext = getActivity();
View view = inflater.inflate(R.layout.fragment_ops, container, false);
webView = view.findViewById(R.id.web_view);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
webView.setWebViewClient(new WebViewClient());
// Load admin dashboard URL (use the base URL to construct admin panel URL)
String adminUrl = HttpConstants.URiBase.replace("/dev-api", "") + "/index";
webView.loadUrl(adminUrl);
return view;
}
}

View File

@@ -0,0 +1,199 @@
package com.ruilaizi.service.main.kehu.fragment;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.cache.CacheMode;
import com.lzy.okgo.convert.StringConvert;
import com.lzy.okgo.model.Response;
import com.lzy.okrx2.adapter.ObservableResponse;
import com.ruilaizi.service.R;
import com.ruilaizi.service.base.BaseFragment;
import com.ruilaizi.service.okgonet.HttpConstants;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
/**
* RefundFragment — 客服专员:退款审核列表 + 通过/驳回
*/
public class RefundFragment extends BaseFragment {
private RecyclerView recyclerView;
private RefundAdapter adapter;
private List<RefundItem> orderList = new ArrayList<>();
private Dialog rejectDialog;
private RefundItem selectedItem;
static class RefundItem {
String orderId, orderNumber, orderMoney, yuguMoney, status;
String createTime, cId, bId, hospitalName;
}
class RefundAdapter extends BaseQuickAdapter<RefundItem, BaseViewHolder> {
RefundAdapter(List<RefundItem> data) {
super(R.layout.item_refund_order, data);
}
@Override
protected void convert(BaseViewHolder h, RefundItem item) {
h.setText(R.id.tv_order_no, item.orderNumber != null ? item.orderNumber : "#" + item.orderId);
h.setText(R.id.tv_amount, "¥" + (item.yuguMoney != null ? item.yuguMoney : item.orderMoney));
h.setText(R.id.tv_info, "患者ID: " + (item.cId != null ? item.cId : "--") + " | 陪诊师ID: " + (item.bId != null ? item.bId : "--"));
h.setText(R.id.tv_time, item.createTime);
h.getView(R.id.btn_approve).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { doApprove(item, true); }
});
h.getView(R.id.btn_reject).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { showRejectDialog(item); }
});
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mContext = getActivity();
View view = inflater.inflate(R.layout.fragment_refund, container, false);
recyclerView = view.findViewById(R.id.recycler_view);
adapter = new RefundAdapter(orderList);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
recyclerView.setAdapter(adapter);
loadRefundOrders();
return view;
}
private void loadRefundOrders() {
OkGo.<String>get(HttpConstants.URi_system_refund_list)
.converter(new StringConvert()).cacheMode(CacheMode.NO_CACHE)
.adapt(new ObservableResponse<String>())
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.Observer<Response<String>>() {
@Override public void onSubscribe(@NonNull Disposable d) {}
@Override public void onNext(@NonNull Response<String> resp) {
try {
JSONObject json = JSON.parseObject(resp.body());
if (json.getIntValue("code") == 200) {
JSONArray arr = json.getJSONArray("rows");
if (arr == null) arr = json.getJSONArray("data");
orderList.clear();
if (arr != null) for (int i = 0; i < arr.size(); i++) {
orderList.add(JSON.toJavaObject(arr.getJSONObject(i), RefundItem.class));
}
adapter.notifyDataSetChanged();
}
} catch (Exception e) { Log.e("Refund", "parse err", e); }
}
@Override public void onError(@NonNull Throwable e) {
Toast.makeText(mContext, "加载失败", Toast.LENGTH_SHORT).show();
}
@Override public void onComplete() {}
});
}
private void doApprove(RefundItem item, boolean approve) {
String url = HttpConstants.URi_system_refund_approve + item.orderId;
OkGo.<String>post(url)
.params("approved", approve ? "1" : "0")
.converter(new StringConvert())
.adapt(new ObservableResponse<String>())
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.Observer<Response<String>>() {
@Override public void onSubscribe(@NonNull Disposable d) {}
@Override public void onNext(@NonNull Response<String> resp) {
try {
JSONObject json = JSON.parseObject(resp.body());
if (json.getIntValue("code") == 200) {
Toast.makeText(mContext, approve ? "已通过" : "已驳回", Toast.LENGTH_SHORT).show();
loadRefundOrders();
} else {
Toast.makeText(mContext, json.getString("msg"), Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {}
}
@Override public void onError(@NonNull Throwable e) {
Toast.makeText(mContext, "操作失败", Toast.LENGTH_SHORT).show();
}
@Override public void onComplete() {}
});
}
private void showRejectDialog(RefundItem item) {
selectedItem = item;
rejectDialog = new Dialog(mContext, R.style.DialogTheme);
View view = LayoutInflater.from(mContext).inflate(R.layout.dialog_reject_reason, null);
rejectDialog.setContentView(view);
Window window = rejectDialog.getWindow();
window.setGravity(android.view.Gravity.BOTTOM);
window.setWindowAnimations(R.style.dialog_menu_animStyle);
window.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);
EditText etReason = view.findViewById(R.id.et_reason);
view.findViewById(R.id.btn_submit).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
rejectDialog.dismiss();
doRejectWithReason(selectedItem, etReason.getText().toString());
}
});
view.findViewById(R.id.btn_cancel).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { rejectDialog.dismiss(); }
});
rejectDialog.show();
}
private void doRejectWithReason(RefundItem item, String reason) {
OkGo.<String>post(HttpConstants.URi_system_refund_approve + item.orderId)
.params("approved", "0")
.params("reason", reason)
.converter(new StringConvert())
.adapt(new ObservableResponse<String>())
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.Observer<Response<String>>() {
@Override public void onSubscribe(@NonNull Disposable d) {}
@Override public void onNext(@NonNull Response<String> resp) {
try {
JSONObject json = JSON.parseObject(resp.body());
if (json.getIntValue("code") == 200) {
Toast.makeText(mContext, "已驳回", Toast.LENGTH_SHORT).show();
loadRefundOrders();
} else {
Toast.makeText(mContext, json.getString("msg"), Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {}
}
@Override public void onError(@NonNull Throwable e) {
Toast.makeText(mContext, "操作失败", Toast.LENGTH_SHORT).show();
}
@Override public void onComplete() {}
});
}
}

View File

@@ -76,6 +76,7 @@ public class MyFragment extends BaseTreeFragment<MyContract.View, MyPresenterImp
private TextView my_tv_06;
private TextView tv_shiming;
private String attestation;//0未认证 1已认证
private String userType = "B";
@Override
@@ -140,6 +141,9 @@ public class MyFragment extends BaseTreeFragment<MyContract.View, MyPresenterImp
loginBean userProfie = ProfileSpUtils.getInstance().getUserProfie();
my_tv_name.setText(userProfie.getData().getNickName());
my_tv_phone.setText(userProfie.getData().getNickName());
// Read userType and update role label
userType = userProfie.getData().getUserType() != null ? userProfie.getData().getUserType() : "B";
updateRoleLabel();
refreshData();
}
}
@@ -292,6 +296,22 @@ public class MyFragment extends BaseTreeFragment<MyContract.View, MyPresenterImp
}
}
/**
* Update role label based on userType
*/
private void updateRoleLabel() {
String label;
switch (userType) {
case "05": label = "调度员"; break;
case "04": label = "客服专员"; break;
case "03": label = "运营经理"; break;
case "06": label = "推广员"; break;
case "00": label = "管理员"; break;
default: label = "陪诊师"; break;
}
my_tv_dichan.setText(label);
}
@Override
public void refreshData() {
mSwipeRefreshLayout.setRefreshing(false);
@@ -300,9 +320,13 @@ public class MyFragment extends BaseTreeFragment<MyContract.View, MyPresenterImp
my_tv_name.setText("姓名:" + userProfie.getData().getNickName());
my_tv_phone.setText("电话:" + userProfie.getData().getPhonenumber());
GlideTools.init(mContext).displaypic(rivAvatar, userProfie.getData().getHeadimage(), R.mipmap.icon_default_head);
WidgetTools.setTextt(my_tv_05, ProfileSpUtils.getInstance().getUserProfie().getData().getLeijijine());
WidgetTools.setTextt(my_tv_06, ProfileSpUtils.getInstance().getUserProfie().getData().getYue());
WidgetTools.setTextt(my_tv_05, ProfileSpUtils.getInstance().getUserProfie().getData().getLeijijine());
// Update role label on refresh
try {
userType = userProfie.getData().getUserType() != null ? userProfie.getData().getUserType() : "B";
updateRoleLabel();
} catch (Exception e) {}
}
@@ -334,6 +358,10 @@ public class MyFragment extends BaseTreeFragment<MyContract.View, MyPresenterImp
WidgetTools.setTextt(my_tv_05, data.getData().getLeijijine());
WidgetTools.setTextt(my_tv_06, data.getData().getYue());
attestation = data.getData().getAttestation();
if (data.getData().getUserType() != null) {
userType = data.getData().getUserType();
updateRoleLabel();
}
if (attestation.equals("0")) {
tv_shiming.setText("未认证/点击认证");
} else {

View File

@@ -61,6 +61,15 @@ public class appUserInfoBean implements Serializable {
private int userId;
private String userName;
private String yue;
private String userType;
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
public String getAddress() {
return address;

View File

@@ -107,6 +107,7 @@ public class loginBean implements Serializable {
private String token;
private String monthIncome;
private String monthOrderCount;
private String userType;
public String getUserId() {
return userId;
@@ -187,5 +188,13 @@ public class loginBean implements Serializable {
public void setMonthOrderCount(String monthOrderCount) {
this.monthOrderCount = monthOrderCount;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
}
}

View File

@@ -71,12 +71,37 @@ public class HttpConstants {
*/
public static String URi_syste_view_list = URiBase + "/system/view/list";
// ===== 多角色调度/退款/运营 API =====
/**
* 调度-待派单列表 (status=0)
*/
public static String URi_system_dispatch_pending = URiBase + "/system/dispatch/pending";
/**
* 调度-陪诊师列表
*/
public static String URi_system_dispatch_caregivers = URiBase + "/system/dispatch/caregivers";
/**
* 调度-指派订单
*/
public static String URi_system_dispatch_assign = URiBase + "/system/dispatch/assign/";
/**
* 退款-审核列表 (status=5)
*/
public static String URi_system_refund_list = URiBase + "/system/view/list?status=5";
/**
* 退款-审核通过/驳回
*/
public static String URi_system_refund_approve = URiBase + "/system/view/refundApprove/";
/**
* 运营-区域数据统计
*/
public static String URi_system_region_stats = URiBase + "/system/region/stats";

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:background="#fff">
<TextView
android:id="@+id/tv_order_no"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="订单: "
android:textSize="16sp"
android:textColor="#333"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="请选择陪诊师"
android:textSize="14sp"
android:textColor="#999"
android:layout_marginTop="8dp" />
<ListView
android:id="@+id/list_caregivers"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="8dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp"
android:gravity="end">
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:text="取消"
android:textSize="14sp"
android:background="#ddd"
android:textColor="#666"
android:minHeight="0dp" />
<Button
android:id="@+id/btn_confirm"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:text="确认指派"
android:textSize="14sp"
android:background="#1890FF"
android:textColor="#fff"
android:minHeight="0dp"
android:layout_marginLeft="12dp" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:background="#fff">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="驳回原因"
android:textSize="16sp"
android:textColor="#333"
android:textStyle="bold" />
<EditText
android:id="@+id/et_reason"
android:layout_width="match_parent"
android:layout_height="100dp"
android:hint="请输入驳回原因"
android:textSize="14sp"
android:gravity="top"
android:background="#F5F5F5"
android:padding="8dp"
android:layout_marginTop="8dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp"
android:gravity="end">
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:text="取消"
android:textSize="14sp"
android:background="#ddd"
android:textColor="#666"
android:minHeight="0dp" />
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:text="确认驳回"
android:textSize="14sp"
android:background="#F56C6C"
android:textColor="#fff"
android:minHeight="0dp"
android:layout_marginLeft="12dp" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#F5F5F5">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="待派单订单"
android:textSize="18sp"
android:textColor="#333"
android:textStyle="bold"
android:background="#fff" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp" />
</LinearLayout>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="运营看板"
android:textSize="18sp"
android:textColor="#333"
android:textStyle="bold"
android:background="#fff" />
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#F5F5F5">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="退款审核"
android:textSize="18sp"
android:textColor="#333"
android:textStyle="bold"
android:background="#fff" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp" />
</LinearLayout>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:padding="12dp"
android:orientation="vertical"
android:layout_marginBottom="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv_order_no"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="订单号"
android:textSize="16sp"
android:textColor="#333"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="¥0"
android:textSize="16sp"
android:textColor="#E6A23C"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/tv_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="医院 | 服务"
android:textSize="13sp"
android:textColor="#999"
android:layout_marginTop="4dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="8dp">
<TextView
android:id="@+id/tv_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="时间"
android:textSize="12sp"
android:textColor="#C0C4CC" />
<Button
android:id="@+id/btn_action"
android:layout_width="80dp"
android:layout_height="32dp"
android:text="指派"
android:textSize="12sp"
android:background="#1890FF"
android:textColor="#fff"
android:minHeight="0dp" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:padding="12dp"
android:orientation="vertical"
android:layout_marginBottom="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv_order_no"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="订单号"
android:textSize="16sp"
android:textColor="#333"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="¥0"
android:textSize="16sp"
android:textColor="#E6A23C"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/tv_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="患者ID | 陪诊师ID"
android:textSize="13sp"
android:textColor="#999"
android:layout_marginTop="4dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="8dp">
<TextView
android:id="@+id/tv_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="时间"
android:textSize="12sp"
android:textColor="#C0C4CC" />
<Button
android:id="@+id/btn_approve"
android:layout_width="60dp"
android:layout_height="32dp"
android:text="通过"
android:textSize="12sp"
android:background="#4CAF50"
android:textColor="#fff"
android:minHeight="0dp" />
<Button
android:id="@+id/btn_reject"
android:layout_width="60dp"
android:layout_height="32dp"
android:text="驳回"
android:textSize="12sp"
android:background="#F56C6C"
android:textColor="#fff"
android:minHeight="0dp"
android:layout_marginLeft="8dp" />
</LinearLayout>
</LinearLayout>