462 lines
8.2 KiB
JavaScript
462 lines
8.2 KiB
JavaScript
/** 客服列表 — 派单量 / 剩余额度 / 封禁解封 */
|
|
|
|
import request from '../../utils/request.js';
|
|
|
|
import { STAFF_API, isStaffMode } from '../../utils/staff-api.js';
|
|
|
|
|
|
|
|
const app = getApp();
|
|
|
|
|
|
|
|
function avatarUrl(path) {
|
|
|
|
if (!path) return '/images/default-avatar.png';
|
|
|
|
if (path.startsWith('http')) return path;
|
|
|
|
const oss = app.globalData.ossImageUrl || '';
|
|
|
|
const p = path.startsWith('/') ? path.slice(1) : path;
|
|
|
|
return oss ? oss + p : '/images/default-avatar.png';
|
|
|
|
}
|
|
|
|
|
|
|
|
Page({
|
|
|
|
data: {
|
|
|
|
statusBar: 20,
|
|
|
|
list: [],
|
|
|
|
displayList: [],
|
|
|
|
searchKeyword: '',
|
|
|
|
isOwner: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
onLoad() {
|
|
|
|
const sys = wx.getSystemInfoSync();
|
|
|
|
this.setData({ statusBar: sys.statusBarHeight || 20, isOwner: !isStaffMode() });
|
|
|
|
this.loadList();
|
|
|
|
},
|
|
|
|
|
|
|
|
onShow() {
|
|
|
|
this.loadList();
|
|
|
|
},
|
|
|
|
|
|
|
|
formatList(raw) {
|
|
|
|
return (raw || []).map((item) => ({
|
|
|
|
...item,
|
|
|
|
avatar: avatarUrl(item.avatar),
|
|
|
|
todayDispatchCount: item.todayDispatchCount != null ? item.todayDispatchCount : 0,
|
|
|
|
todayDispatchAmount: item.todayDispatchAmount || '0.00',
|
|
|
|
dispatchCount: item.dispatchCount != null ? item.dispatchCount : (item.orderCount || 0),
|
|
|
|
dispatchAmount: item.dispatchAmount || '0.00',
|
|
|
|
settleCount: item.settleCount != null ? item.settleCount : 0,
|
|
|
|
settleAmount: item.settleAmount || '0.00',
|
|
|
|
refundCount: item.refundCount != null ? item.refundCount : 0,
|
|
|
|
refundAmount: item.refundAmount || '0.00',
|
|
|
|
quotaAvailable: item.quota_available || '0.00',
|
|
|
|
quotaRevokable: item.quota_available || '0.00',
|
|
|
|
isSelf: !!item.isSelf,
|
|
|
|
}));
|
|
|
|
},
|
|
|
|
|
|
|
|
rejectSelf(id) {
|
|
|
|
const row = (this.data.list || []).find((x) => String(x.id) === String(id));
|
|
|
|
if (row && row.isSelf) {
|
|
|
|
wx.showToast({ title: '不能对本人操作', icon: 'none' });
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
|
|
|
async loadList() {
|
|
|
|
try {
|
|
|
|
const res = await request({ url: STAFF_API.memberList, method: 'POST' });
|
|
|
|
if (res.data && res.data.code === 0) {
|
|
|
|
const raw = (res.data.data && res.data.data.list) || [];
|
|
|
|
this._allList = this.formatList(raw);
|
|
|
|
this.applySearchFilter();
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
wx.showToast({ title: '加载失败', icon: 'none' });
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
goBack() { wx.navigateBack(); },
|
|
|
|
applySearchFilter() {
|
|
const kw = (this.data.searchKeyword || '').trim().toLowerCase();
|
|
const all = this._allList || [];
|
|
if (!kw) {
|
|
this.setData({ list: all, displayList: all });
|
|
return;
|
|
}
|
|
const filtered = all.filter((item) => {
|
|
const uid = String(item.uid || '').toLowerCase();
|
|
const remark = String(item.merchant_remark || '').toLowerCase();
|
|
const nick = String(item.nickname || '').toLowerCase();
|
|
return uid.includes(kw) || remark.includes(kw) || nick.includes(kw);
|
|
});
|
|
this.setData({ list: all, displayList: filtered });
|
|
},
|
|
|
|
onSearchInput(e) {
|
|
this.setData({ searchKeyword: e.detail.value || '' });
|
|
this.applySearchFilter();
|
|
},
|
|
|
|
clearSearch() {
|
|
this.setData({ searchKeyword: '' });
|
|
this.applySearchFilter();
|
|
},
|
|
|
|
goStaffOrders(e) {
|
|
const id = e.currentTarget.dataset.id;
|
|
const label = e.currentTarget.dataset.label || '';
|
|
wx.redirectTo({
|
|
url: `/pages/merchant-orders/merchant-orders?staff_member_id=${id}&staff_label=${encodeURIComponent(label)}`,
|
|
});
|
|
},
|
|
|
|
onEditRemark(e) {
|
|
const id = e.currentTarget.dataset.id;
|
|
const oldRemark = e.currentTarget.dataset.remark || '';
|
|
wx.showModal({
|
|
title: '客服备注',
|
|
editable: true,
|
|
placeholderText: '如:晚班小李、财务小王',
|
|
content: oldRemark,
|
|
success: async (r) => {
|
|
if (!r.confirm) return;
|
|
const remark = (r.content || '').trim();
|
|
const res = await request({
|
|
url: STAFF_API.memberUpdateRemark,
|
|
method: 'POST',
|
|
data: { member_id: id, merchant_remark: remark },
|
|
});
|
|
wx.showToast({
|
|
title: (res.data && res.data.code === 0) ? '已保存' : (res.data.msg || '失败'),
|
|
icon: 'none',
|
|
});
|
|
this.loadList();
|
|
},
|
|
});
|
|
},
|
|
|
|
copyUid(e) {
|
|
|
|
wx.setClipboardData({ data: e.currentTarget.dataset.uid || '' });
|
|
|
|
},
|
|
|
|
|
|
|
|
async onAllocate(e) {
|
|
|
|
const id = e.currentTarget.dataset.id;
|
|
|
|
if (this.rejectSelf(id)) return;
|
|
|
|
wx.showModal({
|
|
|
|
title: '划额度',
|
|
|
|
editable: true,
|
|
|
|
placeholderText: '输入金额',
|
|
|
|
success: async (r) => {
|
|
|
|
if (!r.confirm || !r.content) return;
|
|
|
|
const res = await request({
|
|
|
|
url: STAFF_API.walletAllocate,
|
|
|
|
method: 'POST',
|
|
|
|
data: { member_id: id, amount: r.content },
|
|
|
|
});
|
|
|
|
wx.showToast({
|
|
|
|
title: (res.data && res.data.code === 0) ? '成功' : (res.data.msg || '失败'),
|
|
|
|
icon: 'none',
|
|
|
|
});
|
|
|
|
this.loadList();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
async onRevoke(e) {
|
|
|
|
const id = e.currentTarget.dataset.id;
|
|
|
|
if (this.rejectSelf(id)) return;
|
|
|
|
const available = e.currentTarget.dataset.available || '0';
|
|
|
|
wx.showModal({
|
|
|
|
title: '收回额度',
|
|
|
|
editable: true,
|
|
|
|
placeholderText: `最多可收回 ${available} 元`,
|
|
|
|
success: async (r) => {
|
|
|
|
if (!r.confirm || !r.content) return;
|
|
|
|
const res = await request({
|
|
|
|
url: STAFF_API.walletRevoke,
|
|
|
|
method: 'POST',
|
|
|
|
data: { member_id: id, amount: r.content },
|
|
|
|
});
|
|
|
|
wx.showToast({
|
|
|
|
title: (res.data && res.data.code === 0) ? '已收回' : (res.data.msg || '失败'),
|
|
|
|
icon: 'none',
|
|
|
|
});
|
|
|
|
if (res.data && res.data.code === 0) this.loadList();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
async onToggleDisable(e) {
|
|
|
|
const id = e.currentTarget.dataset.id;
|
|
|
|
if (this.rejectSelf(id)) return;
|
|
|
|
const disabled = e.currentTarget.dataset.disabled;
|
|
|
|
const action = disabled ? '解封' : '封禁';
|
|
|
|
wx.showModal({
|
|
|
|
title: `${action}客服`,
|
|
|
|
content: disabled ? '解封后该客服可继续登录操作' : '封禁后该客服无法使用商家端功能',
|
|
|
|
success: async (r) => {
|
|
|
|
if (!r.confirm) return;
|
|
|
|
const res = await request({
|
|
|
|
url: STAFF_API.memberDisable,
|
|
|
|
method: 'POST',
|
|
|
|
data: { member_id: id, disable: !disabled },
|
|
|
|
});
|
|
|
|
wx.showToast({ title: (res.data && res.data.msg) || action, icon: 'none' });
|
|
|
|
this.loadList();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
async onRemove(e) {
|
|
|
|
const id = e.currentTarget.dataset.id;
|
|
|
|
wx.showModal({
|
|
|
|
title: '移除客服',
|
|
|
|
content: '移除后该用户可认证商家或绑定其他商家',
|
|
|
|
success: async (r) => {
|
|
|
|
if (!r.confirm) return;
|
|
|
|
const res = await request({
|
|
|
|
url: STAFF_API.memberRemove,
|
|
|
|
method: 'POST',
|
|
|
|
data: { member_id: id },
|
|
|
|
});
|
|
|
|
wx.showToast({ title: res.data.msg || '完成', icon: 'none' });
|
|
|
|
this.loadList();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
async onAssignRole(e) {
|
|
|
|
const memberId = e.currentTarget.dataset.id;
|
|
|
|
if (this.rejectSelf(memberId)) return;
|
|
|
|
const rolesRes = await request({ url: STAFF_API.roleList, method: 'POST' });
|
|
|
|
const roles = (rolesRes.data && rolesRes.data.data && rolesRes.data.data.roles) || [];
|
|
|
|
if (!roles.length) {
|
|
|
|
wx.showToast({ title: '请先创建角色', icon: 'none' });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
wx.showActionSheet({
|
|
|
|
itemList: roles.map((r) => r.role_name),
|
|
|
|
success: async (r) => {
|
|
|
|
const role = roles[r.tapIndex];
|
|
|
|
const res = await request({
|
|
|
|
url: STAFF_API.memberUpdateRole,
|
|
|
|
method: 'POST',
|
|
|
|
data: { member_id: memberId, role_id: role.id },
|
|
|
|
});
|
|
|
|
const ok = res.data && res.data.code === 0;
|
|
|
|
const roleName = (res.data && res.data.data && res.data.data.role_name) || role.role_name;
|
|
|
|
wx.showToast({
|
|
|
|
title: ok ? `已设为${roleName}` : (res.data.msg || '失败'),
|
|
|
|
icon: 'none',
|
|
|
|
});
|
|
|
|
if (ok) this.loadList();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
goRank() {
|
|
|
|
wx.navigateTo({ url: '/pages/merchant-staff-audit/merchant-staff-audit?tab=rank' });
|
|
|
|
},
|
|
|
|
|
|
|
|
goAudit() {
|
|
|
|
wx.navigateTo({ url: '/pages/merchant-staff-audit/merchant-staff-audit' });
|
|
|
|
},
|
|
|
|
});
|
|
|