backup: 紫色UI换肤前完整备份(当前橙色逍遥梦主题)

保留改造前全部页面样式与功能代码,便于回滚。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-29 01:59:42 +08:00
parent a751708d6e
commit c03d22776f
49 changed files with 6025 additions and 3784 deletions

253
utils/staff-api.js Normal file
View File

@@ -0,0 +1,253 @@
/**
* 商家子客服 API 与身份上下文
*
* 身份说明(互斥,不冲突):
* - 商家老板shangjiastatus=1走原商家接口扣商家余额
* - 子客服(含总管/财务/派单员staff_context.active走 merchant-staff 接口,扣个人额度
* - 同账号不能既是老板又是子客服;换角色只改权限,额度/统计仍归属同一 member 记录
*/
import { isApiSuccess } from './api-helper.js';
const STAFF_PREFIX = '/yonghu/merchant-staff';
export const STAFF_API = {
me: `${STAFF_PREFIX}/me`,
bind: `${STAFF_PREFIX}/bind`,
inviteCreate: `${STAFF_PREFIX}/invite/create`,
inviteList: `${STAFF_PREFIX}/invite/list`,
inviteRevoke: `${STAFF_PREFIX}/invite/revoke`,
memberList: `${STAFF_PREFIX}/member/list`,
memberUpdateRole: `${STAFF_PREFIX}/member/update-role`,
memberRemove: `${STAFF_PREFIX}/member/remove`,
memberDisable: `${STAFF_PREFIX}/member/disable`,
roleList: `${STAFF_PREFIX}/role/list`,
roleSetPerms: `${STAFF_PREFIX}/role/set-perms`,
walletAllocate: `${STAFF_PREFIX}/wallet/allocate`,
walletRevoke: `${STAFF_PREFIX}/wallet/revoke`,
walletLedger: `${STAFF_PREFIX}/wallet/ledger`,
auditList: `${STAFF_PREFIX}/audit/list`,
rank: `${STAFF_PREFIX}/rank`,
roleCreate: `${STAFF_PREFIX}/role/create`,
roleSetPerms: `${STAFF_PREFIX}/role/set-perms`,
memberUpdatePerms: `${STAFF_PREFIX}/member/update-perms`,
templateList: `${STAFF_PREFIX}/template/list`,
templateCreate: `${STAFF_PREFIX}/template/create`,
templateUpdate: `${STAFF_PREFIX}/template/update`,
templateDelete: `${STAFF_PREFIX}/template/delete`,
linkGenerate: `${STAFF_PREFIX}/link/generate`,
linkList: `${STAFF_PREFIX}/link/list`,
orderList: `${STAFF_PREFIX}/order/list`,
orderDetail: `${STAFF_PREFIX}/order/detail`,
orderDispatch: `${STAFF_PREFIX}/order/dispatch`,
productTypes: `${STAFF_PREFIX}/order/product-types`,
orderSettle: `${STAFF_PREFIX}/order/settle`,
orderCancel: `${STAFF_PREFIX}/order/cancel`,
orderRefund: `${STAFF_PREFIX}/order/refund`,
penaltyApply: `${STAFF_PREFIX}/order/penalty-apply`,
penaltyManage: `${STAFF_PREFIX}/order/penalty-manage`,
changePlayer: `${STAFF_PREFIX}/order/change-player`,
};
export function getStaffContext() {
return wx.getStorageSync('staff_context') || null;
}
export function setStaffContext(ctx) {
if (ctx && ctx.active) {
wx.setStorageSync('staff_context', ctx);
wx.setStorageSync('staffstatus', 1);
} else {
wx.removeStorageSync('staff_context');
wx.setStorageSync('staffstatus', 0);
}
}
export function isStaffMode() {
// 商家老板与子客服互斥:已认证商家时一律按老板身份
if (Number(wx.getStorageSync('shangjiastatus')) === 1) {
return false;
}
const ctx = getStaffContext();
if (ctx && ctx.active) {
return true;
}
// 绑定/登录已写入 staffstatuscontext 异步刷新期间仍视为客服
return Number(wx.getStorageSync('staffstatus')) === 1;
}
export function clearStaffSession() {
wx.removeStorageSync('staff_context');
wx.setStorageSync('staffstatus', 0);
}
/** 是否仅为商家老板(非子客服) */
export function isMerchantOwnerOnly() {
return Number(wx.getStorageSync('shangjiastatus')) === 1 && !isStaffMode();
}
/** 子客服/非老板禁止进入商家充值提现等页面 */
export function guardMerchantOwnerAction(msg) {
if (isMerchantOwnerOnly()) return true;
wx.showToast({
title: msg || '仅商家老板可充值或提现,子客服请联系老板',
icon: 'none',
});
return false;
}
export function staffHasPerm(code) {
const ctx = getStaffContext();
if (!ctx || !ctx.permissions) return false;
return ctx.permissions.indexOf(code) >= 0;
}
function loadRequest() {
// 延迟加载,避免 App 未注册时 request 模块被提前初始化
return require('./request.js').default;
}
export async function refreshStaffContext(req) {
const cached = getStaffContext();
const token = wx.getStorageSync('token');
if (!token) return null;
const doRequest = req || loadRequest();
try {
const res = await doRequest({ url: STAFF_API.me, method: 'POST' });
const body = res.data || {};
if (res.statusCode === 401) {
return cached;
}
if (isApiSuccess(body) && body.data && body.data.active) {
setStaffContext(body.data);
return body.data;
}
if (body.code === 404 || body.code === 403) {
// 已有本地客服身份时勿清空,避免误入「商家入驻」
if (cached && cached.active) {
return cached;
}
if (Number(wx.getStorageSync('staffstatus')) === 1) {
return cached;
}
clearStaffSession();
return null;
}
return cached;
} catch (e) {
return cached;
}
}
/** 登录/注册响应写入子客服身份 */
export function applyStaffFromLoginData(data) {
if (!data || typeof data !== 'object') return;
if (data.staff_context && data.staff_context.active) {
setStaffContext(data.staff_context);
return;
}
if (Number(data.staffstatus) === 1) {
wx.setStorageSync('staffstatus', 1);
return;
}
if (Object.prototype.hasOwnProperty.call(data, 'staffstatus') && Number(data.staffstatus) !== 1) {
clearStaffSession();
}
}
/** 登录成功后从 /me 拉取最新子客服身份 */
export async function restoreStaffContextAfterAuth() {
const token = wx.getStorageSync('token');
if (!token) return null;
return refreshStaffContext(loadRequest());
}
/** 客服模式下返回客服专用 URL否则返回商家原 URL */
export function merchantApi(staffPath, ownerPath) {
return isStaffMode() ? staffPath : ownerPath;
}
export function staffCan(action) {
if (!isStaffMode()) return true;
const map = {
dispatch: 'order_dispatch',
detail: 'order_detail',
settle: 'order_settle',
cancel: 'order_cancel',
refund: 'order_refund_apply',
penalty: 'penalty_apply',
penaltyManage: 'penalty_manage',
changePlayer: 'order_change_player',
staffManage: 'staff_manage',
audit: 'audit_view',
finance: 'finance_view',
walletAllocate: 'wallet_allocate',
walletRevoke: 'wallet_revoke',
template: 'template_manage',
imChat: 'im_chat',
};
return staffHasPerm(map[action] || action);
}
/** 商家老板或有效子客服,均可进入商家端工作台 */
export function isMerchantPortalUser() {
return Number(wx.getStorageSync('shangjiastatus')) === 1 || isStaffMode();
}
/** 将 /me 返回的 stats 写入页面 */
export function applyStaffStatsToPage(page, ctx) {
const st = (ctx && ctx.stats) || {};
if (!st || typeof page.setData !== 'function') return;
const patch = {};
if (page.data.stats) {
patch.stats = {
...page.data.stats,
todayDispatch: st.today_dispatch_count || 0,
todayRefund: st.today_refund_count || 0,
};
}
if ('jinridingdan' in page.data) {
patch.jinridingdan = st.today_dispatch_count || 0;
patch.jinrituikuan = st.today_refund_count || 0;
patch.fabu = st.dispatch_count || 0;
patch.tuikuan = st.refund_count || 0;
}
if (Object.keys(patch).length) {
page.setData(patch);
}
}
/** 同步子客服 UI 权限到页面 data并确保 isShangjia 对客服为 true */
export function syncStaffUi(page) {
const staff = isStaffMode();
const ctx = staff ? (getStaffContext() || {}) : null;
const wallet = (ctx && ctx.wallet) || {};
const portal = isMerchantPortalUser();
page.setData({
isShangjia: portal,
isStaffMode: staff,
isMerchantOwner: !staff && Number(wx.getStorageSync('shangjiastatus')) === 1,
staffRoleName: staff ? (ctx.role_name || '客服') : '',
staffMerchantId: staff ? (ctx.merchant_id || '') : '',
quotaAvailable: staff ? (wallet.quota_available || '0.00') : '',
canDispatch: staffCan('dispatch'),
canSettle: staffCan('settle'),
canCancel: staffCan('cancel'),
canRefund: staffCan('refund'),
canPenalty: staffCan('penalty'),
canPenaltyManage: staffCan('penaltyManage'),
canChangePlayer: staffCan('changePlayer'),
canStaffManage: staffCan('staffManage'),
canWalletAllocate: staffCan('walletAllocate'),
canWalletRevoke: staffCan('walletRevoke'),
canFinance: staffCan('finance'),
canTemplate: staffCan('template'),
canAudit: !staff || staffCan('audit'),
canImChat: !staff || staffCan('imChat'),
showRechargeWithdraw: isMerchantOwnerOnly(),
});
}
/** 客服模式走 staff 专用 URL老板走原商家 URL */
export function staffOrOwner(staffUrl, ownerUrl) {
return isStaffMode() ? staffUrl : ownerUrl;
}