feat(mer_plat_admin): 平台端配送人员、物流管理与配套能力
新增配送人员/员工接口与页面、物流创建页、Detail 基础组件与 useRefundOrder;增加 FullCalendar、moment 依赖并升级 Vue 至 2.6.12;补充变更说明文档;README 仅保留远程仓库地址,避免将凭据写入仓库。 Made-with: Cursor
This commit is contained in:
54
mer_plat_admin/src/api/deliveryPersonnel.js
Normal file
54
mer_plat_admin/src/api/deliveryPersonnel.js
Normal file
@@ -0,0 +1,54 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* @description 商户配送人员分页列表
|
||||
*/
|
||||
export function personnelListApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/delivery/personnel/page',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 新增商户配送人员
|
||||
*/
|
||||
export function personnelSaveApi(data) {
|
||||
return request({
|
||||
url: '/admin/merchant/delivery/personnel/save',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 编辑商户配送人员
|
||||
*/
|
||||
export function personnelEditApi(data) {
|
||||
return request({
|
||||
url: '/admin/merchant/delivery/personnel/edit',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 删除商户配送人员
|
||||
*/
|
||||
export function personnelDeleteApi(id) {
|
||||
return request({
|
||||
url: `admin/merchant/delivery/personnel/delete/${id}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
173
mer_plat_admin/src/api/staff.js
Normal file
173
mer_plat_admin/src/api/staff.js
Normal file
@@ -0,0 +1,173 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 分页列表
|
||||
* @param
|
||||
*/
|
||||
export function employeeRoleList(pram) {
|
||||
const data = {
|
||||
page: pram.page,
|
||||
limit: pram.limit,
|
||||
keywords: pram.keywords,
|
||||
status: pram.status,
|
||||
};
|
||||
return request({
|
||||
url: '/admin/merchant/employee/list',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除
|
||||
* @param
|
||||
*/
|
||||
export function employeeDelRole(id) {
|
||||
const data = {
|
||||
id: id,
|
||||
};
|
||||
return request({
|
||||
url: 'admin/merchant/employee/delete',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 详情
|
||||
* @param
|
||||
*/
|
||||
export function employeeGetInfo(pram) {
|
||||
return request({
|
||||
url: `/admin/merchant/employee/info/${pram}`,
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 新增
|
||||
* @param
|
||||
*/
|
||||
export function employeeAddRole(pram) {
|
||||
const data = {
|
||||
avatar: pram.avatar,
|
||||
name: pram.name,
|
||||
phone: pram.phone,
|
||||
role: pram.role,
|
||||
status: pram.status,
|
||||
uid: pram.uid,
|
||||
id: pram.id,
|
||||
};
|
||||
return request({
|
||||
url: '/admin/merchant/employee/save',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 修改
|
||||
* @param
|
||||
*/
|
||||
export function employeeUpdateRole(pram) {
|
||||
const data = {
|
||||
avatar: pram.avatar,
|
||||
name: pram.name,
|
||||
phone: pram.phone,
|
||||
role: pram.role,
|
||||
status: pram.status,
|
||||
uid: pram.uid,
|
||||
id: pram.id,
|
||||
};
|
||||
return request({
|
||||
url: '/admin/merchant/employee/update',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 员工服务分页列表
|
||||
* @param
|
||||
*/
|
||||
export function serviceStaffListApi(pram) {
|
||||
const data = {
|
||||
page: pram.page,
|
||||
limit: pram.limit,
|
||||
keywords: pram.keywords,
|
||||
status: pram.status,
|
||||
};
|
||||
return request({
|
||||
url: '/admin/merchant/service/staff/list',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 员工服务删除
|
||||
* @param
|
||||
*/
|
||||
export function serviceStaffDelRoleApi(id) {
|
||||
return request({
|
||||
url: `/admin/merchant/service/staff/delete/${id}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 员工服务新增
|
||||
* @param
|
||||
*/
|
||||
export function serviceStaffAddApi(pram) {
|
||||
const data = {
|
||||
idPhoto: pram.idPhoto,
|
||||
name: pram.name,
|
||||
phone: pram.phone,
|
||||
sort: pram.sort,
|
||||
status: pram.status,
|
||||
userId: pram.userId,
|
||||
id: pram.id,
|
||||
};
|
||||
return request({
|
||||
url: '/admin/merchant/service/staff/save',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 员工服务修改
|
||||
* @param
|
||||
*/
|
||||
export function serviceStaffUpdateApi(pram) {
|
||||
const data = {
|
||||
idPhoto: pram.idPhoto,
|
||||
name: pram.name,
|
||||
phone: pram.phone,
|
||||
sort: pram.sort,
|
||||
status: pram.status,
|
||||
userId: pram.userId,
|
||||
id: pram.id,
|
||||
};
|
||||
return request({
|
||||
url: '/admin/merchant/service/staff/update',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 员工服务修改状态
|
||||
* @param
|
||||
*/
|
||||
export function serviceStaffStatusApi(id) {
|
||||
return request({
|
||||
url: `/admin/merchant/service/staff/status/${id}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
64
mer_plat_admin/src/components/base/DetailHeader.vue
Normal file
64
mer_plat_admin/src/components/base/DetailHeader.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="detailHead">
|
||||
<div class="acea-row row-between headerBox">
|
||||
<div class="full">
|
||||
<div class="order_icon"><span class="iconfont" :class="icon"></span></div>
|
||||
<div class="text">
|
||||
<div class="title">{{ title }}</div>
|
||||
<div v-if="titleLable">
|
||||
<span class="mr20" :class="colClass?colClass:''">{{ titleLable }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acea-row justify-content">
|
||||
<slot name="operation"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul v-if="list.length" class="list">
|
||||
<li class="item" v-for="(item, index) in list" :key="index">
|
||||
<div class="title">{{ item.label }}</div>
|
||||
<div :class="item.color">{{ item.value }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DetailHeader',
|
||||
props: {
|
||||
// 标题
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 图标 class
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 单号
|
||||
orderNo: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 单号标签
|
||||
titleLable: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
colClass: { //样式
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 底部列表 [{label: '', value: '', color: ''}]
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
37
mer_plat_admin/src/components/base/DetailInfo.vue
Normal file
37
mer_plat_admin/src/components/base/DetailInfo.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="detail-info-container">
|
||||
<div v-for="(section, index) in list" :key="index" class="detailSection">
|
||||
<div class="title">{{ section.title }}</div>
|
||||
<ul class="list">
|
||||
<li v-for="(item, i) in section.list" :key="i" class="item" :class="item.colClass">
|
||||
<div class="lang" v-if="item.label">{{ item.label }}:</div>
|
||||
<div class="value">
|
||||
<slot v-if="item.slot" :name="item.slot" :row="item"></slot>
|
||||
<span v-else :class="item.class">{{ item.value }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- 额外的底部内容插槽 -->
|
||||
<slot v-if="section.bottomSlot" :name="section.bottomSlot"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DetailInfo',
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detailSection .item.width100 {
|
||||
flex: 0 0 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
</style>
|
||||
57
mer_plat_admin/src/libs/useRefundOrder.js
Normal file
57
mer_plat_admin/src/libs/useRefundOrder.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { couponDeleteApi } from '@/api/product';
|
||||
import { orderAuditApi, refundOrderReceivingApi } from '@/api/order';
|
||||
import modalSure from '@/libs/modal-sure';
|
||||
import { MessageBox, Message } from 'element-ui';
|
||||
export default function useRefundOrder() {
|
||||
//商家确认收货
|
||||
const onConfirmReceipt = (refundOrderNo) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
MessageBox.confirm('确定已经收到所有退款商品吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(async () => {
|
||||
await refundOrderReceivingApi(refundOrderNo).then(() => {
|
||||
Message.success('确认收货成功');
|
||||
return resolve();
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
reject();
|
||||
Message({
|
||||
type: 'info',
|
||||
message: '已取消',
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
//审核通过到店退款
|
||||
const onApprovedReview = (data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
MessageBox.confirm('您确定同意此退款单吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(async () => {
|
||||
await orderAuditApi(data).then(() => {
|
||||
Message.success('审核成功');
|
||||
return resolve();
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
reject();
|
||||
Message({
|
||||
type: 'info',
|
||||
message: '已取消',
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
return {
|
||||
onConfirmReceipt,
|
||||
onApprovedReview,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<el-dialog :title="title" :visible.sync="dialogVisible" width="540px" append-to-body :before-close="handleResetForm">
|
||||
<el-form
|
||||
v-if="dialogVisible && formValidate"
|
||||
ref="formValidate"
|
||||
class="formValidate"
|
||||
:model="formValidate"
|
||||
:rules="rules"
|
||||
@submit.native.prevent
|
||||
label-width="80px"
|
||||
>
|
||||
<el-form-item label="配送人员:" prop="personnelName">
|
||||
<el-input
|
||||
v-model.trim="formValidate.personnelName"
|
||||
:maxlength="16"
|
||||
placeholder="请输入配送人员姓名"
|
||||
size="small"
|
||||
clearable
|
||||
>
|
||||
</el-input>
|
||||
<div class="from-tips mb5">订单采用商家直接配送的方式发货,根据配送人员的姓名来进行选择。</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话:" prop="personnelPhone">
|
||||
<el-input v-model.trim="formValidate.personnelPhone" placeholder="请输入配送人员联系电话"></el-input>
|
||||
<div class="from-tips mb5">订单采用商家直接配送的方式发货后,用户可通过手机号码联系该配送员。</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序:">
|
||||
<el-input-number
|
||||
v-model.trim="formValidate.sort"
|
||||
:min="0"
|
||||
:max="99"
|
||||
:step="1"
|
||||
step-strictly
|
||||
placeholder="请输入排序"
|
||||
label="排序"
|
||||
></el-input-number>
|
||||
<div class="from-tips mb5">请输入0~99的数字,数字越大越靠前。</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleResetForm">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSure" :loading="loadingBtn">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { expressRelateApi } from '@/api/logistics';
|
||||
import { useLogisticsAllList } from '@/hooks/use-order';
|
||||
import { validatePhone } from '@/utils/toolsValidate';
|
||||
import { personnelEditApi, personnelSaveApi } from '@/api/deliveryPersonnel';
|
||||
import { defaultData } from '@/views/systemSetting/deliveryPersonnel/default';
|
||||
export default {
|
||||
name: 'CreatPersonnel',
|
||||
props: {
|
||||
dialogVisible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
editData: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
editData: {
|
||||
handler(nVal, oVal) {
|
||||
if (nVal) {
|
||||
this.formValidate = this.editData;
|
||||
this.title = this.formValidate.id ? '修改配送员' : '新增配送员';
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
formValidate: Object.assign({}, defaultData),
|
||||
loadingBtn: false,
|
||||
rules: {
|
||||
personnelName: [{ required: true, message: '请输入配送人员姓名', trigger: 'blue' }],
|
||||
personnelPhone: [{ required: true, validator: validatePhone, trigger: 'blur' }],
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
//取消
|
||||
handleResetForm() {
|
||||
this.$emit('handlerCloseFrom');
|
||||
this.$refs.formValidate.resetFields();
|
||||
},
|
||||
// 提交
|
||||
handleSure() {
|
||||
this.$refs.formValidate.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
this.loadingBtn = true;
|
||||
const data = this.formValidate.id
|
||||
? await personnelEditApi(this.formValidate)
|
||||
: await personnelSaveApi(this.formValidate);
|
||||
if (data) this.$message.success(data);
|
||||
this.$emit('handlerSuccessSubmit');
|
||||
this.handleResetForm();
|
||||
this.loadingBtn = false;
|
||||
} catch (e) {
|
||||
this.loadingBtn = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -0,0 +1,6 @@
|
||||
export const defaultData = {
|
||||
id: 0,
|
||||
personnelName: '',
|
||||
personnelPhone: '',
|
||||
sort: 0,
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="新增物流公司"
|
||||
:visible.sync="dialogVisible"
|
||||
width="540px"
|
||||
append-to-body
|
||||
:before-close="handleResetForm"
|
||||
>
|
||||
<el-form
|
||||
v-if="dialogVisible"
|
||||
ref="formValidate"
|
||||
class="formValidate"
|
||||
:model="formValidate"
|
||||
:rules="rules"
|
||||
@submit.native.prevent
|
||||
label-width="80px"
|
||||
>
|
||||
<el-form-item label="物流公司:" required prop="expressId">
|
||||
<el-select v-model="formValidate.expressId" placeholder="请选择" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in expressAllList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleResetForm">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSure" :loading="loadingBtn">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { expressRelateApi } from '@/api/logistics';
|
||||
import { useLogisticsAllList } from '@/hooks/use-order';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
datekey: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
datekey() {
|
||||
this.dialogVisible = true;
|
||||
if (localStorage.getItem('expressAllList'))
|
||||
this.expressAllList = JSON.parse(localStorage.getItem('expressAllList'));
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
formValidate: {
|
||||
expressId: null,
|
||||
},
|
||||
expressAllList: [],
|
||||
loadingBtn: false,
|
||||
rules: {
|
||||
expressId: [{ required: true, message: '请选择物流公司', trigger: 'change' }],
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (localStorage.getItem('expressAllList'))
|
||||
this.expressAllList = JSON.parse(localStorage.getItem('expressAllList'));
|
||||
},
|
||||
methods: {
|
||||
// 物流公司列表
|
||||
async getExpressList() {
|
||||
this.expressAllList = await useLogisticsAllList();
|
||||
},
|
||||
//取消
|
||||
handleResetForm() {
|
||||
this.dialogVisible = false;
|
||||
this.$refs.formValidate.resetFields();
|
||||
},
|
||||
// 提交
|
||||
handleSure() {
|
||||
this.$refs.formValidate.validate((valid) => {
|
||||
if (valid) {
|
||||
expressRelateApi(this.formValidate)
|
||||
.then(async (res) => {
|
||||
this.$message.success('新增成功');
|
||||
this.$emit('handlerSuccessSubmit');
|
||||
this.handleResetForm();
|
||||
this.loadingBtn = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
this.loadingBtn = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
Reference in New Issue
Block a user