Jelajahi Sumber

管理端骑手

ZZ 1 bulan lalu
induk
melakukan
7b15b21b59

+ 357 - 0
mer_plat_admin/src/api/rider.js

@@ -0,0 +1,357 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from '@/utils/request';
+
+/**
+ * 骑手分类 列表
+ */
+export function riderCategoryListApi(params) {
+  return request({
+    url: '/admin/platform/rider/category/list',
+    method: 'get',
+    params,
+  });
+}
+
+/**
+ * 骑手分类 全部列表
+ */
+export function riderCategoryAllListApi() {
+  return request({
+    url: '/admin/platform/rider/category/all/list',
+    method: 'get',
+  });
+}
+
+/**
+ * 骑手分类 添加
+ */
+export function riderCategoryAddApi(data) {
+  return request({
+    url: '/admin/platform/rider/category/add',
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 骑手分类 编辑
+ */
+export function riderCategoryUpdateApi(data) {
+  return request({
+    url: '/admin/platform/rider/category/update',
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 骑手分类 删除
+ */
+export function riderCategoryDeleteApi(id) {
+  return request({
+    url: `/admin/platform/rider/category/delete/${id}`,
+    method: 'post',
+  });
+}
+
+/**
+ * 店铺类型 列表
+ */
+export function riderTypeListApi(params) {
+  return request({
+    url: '/admin/platform/rider/type/list',
+    method: 'get',
+    params,
+  });
+}
+
+/**
+ * 店铺类型 全部列表
+ */
+export function riderTypeAllListApi() {
+  return request({
+    url: '/admin/platform/rider/type/all/list',
+    method: 'get',
+  });
+}
+
+/**
+ * 店铺类型 添加
+ */
+export function riderTypeAddApi(data) {
+  return request({
+    url: '/admin/platform/rider/type/add',
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 店铺类型 编辑
+ */
+export function riderTypeUpdateApi(data) {
+  return request({
+    url: '/admin/platform/rider/type/update',
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 店铺类型 删除
+ */
+export function riderTypeDeleteApi(id) {
+  return request({
+    url: `/admin/platform/rider/type/delete/${id}`,
+    method: 'post',
+  });
+}
+
+/**
+ * 骑手 列表
+ */
+export function riderListApi(params) {
+  return request({
+    url: '/admin/platform/rider/list',
+    method: 'get',
+    params,
+  });
+}
+
+/**
+ * 骑手 添加
+ */
+export function riderAddApi(data) {
+  return request({
+    url: '/admin/platform/rider/add',
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 骑手 编辑
+ */
+export function riderUpdateApi(data) {
+  return request({
+    url: '/admin/platform/rider/update',
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 骑手 关闭
+ */
+export function riderCloseApi(id) {
+  return request({
+    url: `/admin/platform/rider/close/${id}`,
+    method: 'post',
+  });
+}
+
+/**
+ * 骑手 详情
+ */
+export function riderDetailApi(id) {
+  return request({
+    url: `/admin/platform/rider/detail/${id}`,
+    method: 'get',
+  });
+}
+
+/**
+ * 骑手 开启
+ */
+export function riderOpenApi(id) {
+  return request({
+    url: `/admin/platform/rider/open/${id}`,
+    method: 'post',
+  });
+}
+
+/**
+ * 骑手 推荐开关
+ */
+export function riderSwitchApi(id) {
+  return request({
+    url: `/admin/platform/rider/recommend/switch/${id}`,
+    method: 'post',
+  });
+}
+
+/**
+ * 骑手 修改复制商品数量
+ */
+export function riderCopyNumApi(data) {
+  return request({
+    url: `/admin/platform/rider/update/copy/product/num`,
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 骑手 修改骑手手机号
+ */
+export function riderupdatePhoneApi(data) {
+  return request({
+    url: `/admin/platform/rider/update/phone`,
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 骑手 权限规则菜单列表
+ * @param pram
+ */
+export function menuMerListApi(params) {
+  const data = {
+    menuType: params.menuType, //菜单类型:M-目录,C-菜单,A-按钮
+    name: params.name, //菜单名称
+  };
+  return request({
+    url: `/admin/platform/rider/menu/list`,
+    method: 'get',
+    params: data,
+  });
+}
+
+/**
+ * 骑手 权限规则新增菜单
+ * @param data
+ */
+export function menuMerAdd(data) {
+  let systemMenuRequest = data;
+  return request({
+    url: `/admin/platform/rider/menu/add`,
+    method: 'post',
+    data: systemMenuRequest,
+  });
+}
+
+/**
+ * 骑手 权限规则删除菜单
+ * @param data
+ */
+export function menuMerDelete(id) {
+  return request({
+    url: `/admin/platform/rider/menu/delete/${id}`,
+    method: 'post',
+  });
+}
+
+/**
+ * 骑手 权限规则菜单详情
+ * @param data
+ */
+export function menuMerInfo(id) {
+  return request({
+    url: `/admin/platform/rider/menu/info/${id}`,
+    method: 'get',
+  });
+}
+
+/**
+ * 骑手 权限规则菜单修改
+ * @param data
+ */
+export function menuMerUpdate(data) {
+  let systemMenuRequest = data;
+  return request({
+    url: `/admin/platform/rider/menu/update`,
+    method: 'post',
+    data: systemMenuRequest,
+  });
+}
+
+/**
+ * 权限规则修改菜单显示状态
+ * @param data
+ */
+export function menuMerUpdateShowStatus(params) {
+  return request({
+    url: `/admin/platform/rider/menu/update/show/${params.id}`,
+    method: 'post',
+  });
+}
+
+/**
+ * 骑手入驻分页列表
+ * @param data
+ */
+export function riderApplyListApi(params) {
+  return request({
+    url: `/admin/platform/rider/apply/list`,
+    method: 'get',
+    params,
+  });
+}
+
+/**
+ * 骑手入驻审核
+ * @param data
+ */
+export function merApplyAuditApi(data) {
+  return request({
+    url: `/admin/platform/rider/apply/audit`,
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 骑手入驻备注
+ * @param data
+ */
+export function merApplyRemarkApi(data) {
+  return request({
+    url: `/admin/platform/rider/apply/remark`,
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 骑手分页列表表头数量
+ * @param data
+ */
+export function merHeaderNumApi(params) {
+  return request({
+    url: `/admin/platform/rider/list/header/num`,
+    method: 'get',
+    params,
+  });
+}
+
+/**
+ * 重置骑手密码
+ * @param data
+ */
+export function merRsetPasswordApi(id) {
+  return request({
+    url: `/admin/platform/rider/reset/password/${id}`,
+    method: 'post',
+  });
+}
+
+/**
+ * 可用分类骑手列表
+ * @param data
+ */
+export function merCategoryListApi() {
+  return request({
+    url: `/admin/platform/rider/use/category/list`,
+    method: 'get',
+  });
+}

+ 1 - 0
mer_plat_admin/src/filters/index.js

@@ -16,6 +16,7 @@ export * from '../filters/user';
 export * from '../filters/order';
 export * from '../filters/wx';
 export * from '../filters/merchant';
+export * from '../filters/rider';
 export * from '../filters/product';
 export * from '../filters/finance';
 export * from '../filters/marketing';

+ 20 - 0
mer_plat_admin/src/filters/rider.js

@@ -0,0 +1,20 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+/**
+ * 骑手创建类型
+ */
+export function riderCreateTypeFilter(status) {
+  const statusMap = {
+    admin: '管理员创建',
+    apply: '骑手入驻申请',
+  };
+  return statusMap[status];
+}

+ 3 - 0
mer_plat_admin/src/router/index.js

@@ -27,6 +27,7 @@ import financeRouter from './modules/finance';
 import operationRouter from './modules/operation';
 import merchant from './modules/merchant';
 import pagediy from '@/router/modules/pagediy';
+import riderRouter from '@/router/modules/rider';
 
 /**
  * Note: sub-menu only appear when route children.length >= 1
@@ -75,6 +76,8 @@ export const constantRoutes = [
   merchant,
   // 页面diy
   pagediy,
+  // 骑手
+  riderRouter,
 
   {
     path: '/404',

+ 38 - 0
mer_plat_admin/src/router/modules/rider.js

@@ -0,0 +1,38 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import Layout from '@/layout';
+
+const riderRouter = {
+  path: '/rider',
+  component: Layout,
+  redirect: '/rider/classify',
+  name: 'Rider',
+  meta: {
+    title: '骑手',
+    icon: 'clipboard',
+  },
+  children: [
+    {
+      path: 'list',
+      name: 'RiderList',
+      component: () => import('@/views/rider/list'),
+      meta: { title: '骑手列表', icon: '' },
+    },
+    {
+      path: 'application',
+      name: 'RiderApplication',
+      component: () => import('@/views/rider/application'),
+      meta: { title: '骑手入驻申请', icon: '' },
+    }
+  ],
+};
+
+export default riderRouter;

+ 2 - 0
mer_plat_admin/src/store/getters.js

@@ -28,6 +28,8 @@ const getters = {
   productBrand: (state) => state.product.productBrand,
   merchantClassify: (state) => state.merchant.merchantClassify,
   merchantType: (state) => state.merchant.merchantType,
+  riderClassify: (state) => state.rider.riderClassify,
+  riderType: (state) => state.rider.riderType,
   frontDomain: (state) => state.settings.frontDomain,
   mediaDomain: (state) => state.settings.mediaDomain,
   mobileTheme: (state) => state.settings.mobileTheme,

+ 82 - 0
mer_plat_admin/src/store/modules/rider.js

@@ -0,0 +1,82 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+import * as rider from '@/api/rider';
+
+const state = {
+  riderClassify: JSON.parse(localStorage.getItem('riderClassify')) || [] /** 骑手分类 **/,
+  riderType: JSON.parse(localStorage.getItem('riderType')) || [] /** 骑手类型 **/,
+};
+
+const mutations = {
+  SET_RiderClassify: (state, riderClassify) => {
+    state.riderClassify = riderClassify;
+    if (!riderClassify.length) localStorage.removeItem('riderClassify');
+  },
+  SET_RiderType: (state, riderType) => {
+    state.riderType = riderType;
+    if (!riderType.length) localStorage.removeItem('riderType');
+  },
+};
+
+const actions = {
+  /** 骑手全部分类  **/
+  getRiderClassify({ commit }) {
+    return new Promise((resolve, reject) => {
+      rider
+        .riderCategoryAllListApi()
+        .then(async (res) => {
+          commit('SET_RiderClassify', res);
+          localStorage.setItem('riderClassify', JSON.stringify(res));
+          resolve(res);
+        })
+        .catch((error) => {
+          reject(error);
+        });
+    });
+  },
+
+  /** 骑手全部类型 **/
+  getRiderType({ commit }) {
+    return new Promise((resolve, reject) => {
+      rider
+        .riderTypeAllListApi()
+        .then(async (res) => {
+          commit('SET_RiderType', res);
+          localStorage.setItem('riderType', JSON.stringify(res));
+          resolve(res);
+        })
+        .catch((error) => {
+          reject(error);
+        });
+    });
+  },
+};
+
+/** tree去除 childList=[] 的结构**/
+const changeNodes = function (data) {
+  if (data.length > 0) {
+    for (var i = 0; i < data.length; i++) {
+      if (!data[i].childList || data[i].childList.length < 1) {
+        data[i].childList = undefined;
+      } else {
+        changeNodes(data[i].childList);
+      }
+    }
+  }
+  return data;
+};
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+  changeNodes,
+};

+ 280 - 0
mer_plat_admin/src/views/rider/application/audit.vue

@@ -0,0 +1,280 @@
+<template>
+  <div class="box">
+    <el-drawer
+      :visible.sync="dialogVisible"
+      :title="isSHOW ? '骑手入驻审核' : '骑手详情'"
+      :direction="direction"
+      @close="close"
+      size="1000px"
+    >
+      <div v-if="dialogVisible">
+        <div class="detailHead bdbtmSolid">
+          <div class="acea-row row-between headerBox">
+            <div class="full">
+              <div class="order_icon"><span class="iconfont icon-shanghuliebiao"></span></div>
+              <div class="text">
+                <div class="title">骑手</div>
+                <span class="mr20">{{ dataForm.name }}</span>
+              </div>
+            </div>
+            <div v-if="isSHOW">
+              <el-button
+                v-debounceClick="
+                  () => {
+                    onSubmit(3);
+                  }
+                "
+                style="margin-left: 0"
+              >{{ loadingBtn ? '提交中 ...' : '审核拒绝' }}</el-button>
+              <el-button
+                type="primary"
+                v-debounceClick="
+                  () => {
+                    onSubmit(2);
+                  }
+                "
+              >{{ loadingBtn ? '提交中 ...' : '审核通过' }}</el-button>
+            </div>
+          </div>
+        </div>
+        <div class="detailSection padBox">
+          <div class="title">骑手详情</div>
+          <ul class="list">
+            <li class="item">
+              <div class="tips">骑手账号:</div>
+              <div class="value">{{ dataForm.phone }}</div>
+            </li>
+            <li class="item">
+              <div class="tips">骑手身份:</div>
+              <div class="value">
+                <el-tag
+                  size="small"
+                  type="info"
+                  v-for="(item, index) in dataForm.jobScope.split(',')"
+                  :key="index"
+                  class="mr5"
+                >{{ item === '0' ? '骑手' : '快递员' }}</el-tag>
+              </div>
+            </li>
+            <li
+              v-show="dataForm.password"
+              class="item"
+            >
+              <div class="tips">登录密码:</div>
+              <div class="value">{{ dataForm.password }}</div>
+            </li>
+            <li class="item">
+              <div class="tips">骑手姓名:</div>
+              <div class="value">{{ dataForm.name }}</div>
+            </li>
+            <li class="item">
+              <div class="tips">骑手手机号:</div>
+              <div class="value">{{ dataForm.phone | filterEmpty }}</div>
+            </li>
+            <li class="item">
+              <div class="tips">手续费(%):</div>
+              <div class="value">{{ dataForm.handlingFee }}</div>
+            </li>
+          </ul>
+          <div class="ivu-mt-16 acea-row">
+            <div class="tips">备注:</div>
+            <div class="value">{{ dataForm.remark || '无' }}</div>
+          </div>
+          <div class="ivu-mt-16 acea-row">
+            <div class="tips">资质图片:</div>
+            <div class="acea-row">
+              <div
+                v-for="(item, index) in dataForm.qualificationPictureData"
+                :key="index"
+                class="pictrue"
+              >
+                <el-image
+                  :src="item"
+                  :preview-src-list="dataForm.qualificationPictureData"
+                > </el-image>
+              </div>
+            </div>
+          </div>
+        </div>
+        <!--        <div class="demo-drawer__footer">-->
+        <!--          <div v-if="isSHOW" class="from-foot-btn drawer_fix">-->
+        <!--            <div class="acea-row justify-content">-->
+        <!--              <el-button-->
+        <!--                v-debounceClick="-->
+        <!--                  () => {-->
+        <!--                    onSubmit(3);-->
+        <!--                  }-->
+        <!--                "-->
+        <!--                style="margin-left: 0"-->
+        <!--                >{{ loadingBtn ? '提交中 ...' : '审核拒绝' }}</el-button-->
+        <!--              >-->
+        <!--              <el-button-->
+        <!--                type="primary"-->
+        <!--                v-debounceClick="-->
+        <!--                  () => {-->
+        <!--                    onSubmit(2);-->
+        <!--                  }-->
+        <!--                "-->
+        <!--                >{{ loadingBtn ? '提交中 ...' : '审核通过' }}</el-button-->
+        <!--              >-->
+        <!--            </div>-->
+        <!--          </div>-->
+        <!--        </div>-->
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+// +---------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +---------------------------------------------------------------------
+// | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+// +---------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +---------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +---------------------------------------------------------------------
+import { merApplyAuditApi } from '@/api/rider';
+import { mapGetters } from 'vuex';
+import { filterEmpty } from '@/filters';
+export default {
+  name: 'audit',
+  data () {
+    return {
+      merImg: require('@/assets/imgs/dianpu.png'),
+      dialogVisible: false,
+      direction: 'rtl',
+      isDisabled: true,
+      rules: {
+        auditStatus: [{ required: true, message: '请选择审核状态', trigger: 'change' }],
+        denialReason: [{ required: true, message: '请填写拒绝原因', trigger: 'blur' }],
+      },
+      ruleForm: {
+        denialReason: '',
+        auditStatus: 2,
+        id: '',
+      },
+      loadingBtn: false,
+    };
+  },
+  props: {
+    merData: {
+      type: Object,
+      default: () => null,
+    },
+    isSHOW: {
+      type: String,
+      default: () => '',
+    },
+  },
+  computed: {
+    ...mapGetters(['merchantClassify', 'merchantType']),
+  },
+  watch: {
+    merData: {
+      handler: function (val) {
+        if (val.qualificationPicture) val.qualificationPictureData = JSON.parse(val.qualificationPicture);
+        this.dataForm = { ...val };
+      },
+      deep: true,
+    },
+  },
+  methods: {
+    filterEmpty,
+    close () {
+      this.dialogVisible = false;
+      this.ruleForm = {
+        denialReason: '',
+        auditStatus: 2,
+      };
+    },
+    //审核拒绝
+    cancelForm () {
+      this.$modalPrompt('textarea', '拒绝原因').then((V) => {
+        this.ruleForm.denialReason = V;
+        this.submit();
+      });
+    },
+    // 审核提交
+    onSubmit (type) {
+      this.ruleForm.auditStatus = type;
+      if (type === 2) {
+        this.$modalSure('审核通过该骑手吗?').then(() => {
+          this.submit();
+        });
+      } else {
+        this.cancelForm();
+      }
+    },
+    submit () {
+      this.loadingBtn = true;
+      this.ruleForm.id = this.dataForm.id;
+      merApplyAuditApi(this.ruleForm)
+        .then((res) => {
+          this.$message.success('操作成功');
+          this.dialogVisible = false;
+          this.$emit('subSuccess');
+          this.loadingBtn = false;
+        })
+        .catch((res) => {
+          this.loadingBtn = false;
+        });
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.demo-drawer__content {
+  padding-bottom: 86px;
+}
+.box {
+  ::v-deep.el-drawer__header {
+    margin-bottom: 0 !important;
+    font-size: 20px;
+  }
+}
+.demo-drawer__content {
+  min-height: 600px;
+}
+.widths {
+  width: 169px;
+  display: inline-block;
+  color: #606266;
+}
+.langcent {
+  display: inline-block;
+  color: #606266;
+  width: 100%;
+}
+.lang {
+  width: 100%;
+  ::v-deep.el-form-item__content {
+    width: 79%;
+  }
+}
+.divBox {
+  ::v-deep .el-input__inner:hover,
+  ::v-deep.el-input > input,
+  ::v-deep.el-textarea > textarea {
+    border: none;
+    padding: 0;
+  }
+  ::v-deep.el-card__body {
+    padding: 5px;
+  }
+  ::v-deep .el-input.is-disabled .el-input__inner {
+    background: none;
+    cursor: none;
+    color: #606266;
+  }
+}
+::v-deep .el-image {
+  width: 60px;
+  height: 60px;
+}
+.item {
+  align-items: center;
+}
+</style>

+ 386 - 0
mer_plat_admin/src/views/rider/application/index.vue

@@ -0,0 +1,386 @@
+<template>
+  <div class="divBox">
+    <el-card
+      :bordered="false"
+      shadow="never"
+      class="ivu-mt"
+      :body-style="{ padding: 0 }"
+      v-hasPermi="['platform:rider:apply:page:list']"
+    >
+      <div class="padding-add">
+        <el-form
+          size="small"
+          label-position="right"
+          inline
+          @submit.native.prevent
+        >
+          <el-form-item label="选择时间:">
+            <el-date-picker
+              v-model="timeVal"
+              type="daterange"
+              size="small"
+              placeholder="选择日期"
+              format="yyyy-MM-dd"
+              value-format="yyyy-MM-dd"
+              range-separator="-"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              @change="onchangeTime"
+              class="selWidth"
+            />
+          </el-form-item>
+          <el-form-item label="审核状态:">
+            <el-select
+              v-model="tableFrom.auditStatus"
+              clearable
+              size="small"
+              placeholder="请选择"
+              class="selWidth"
+            >
+              <el-option
+                v-for="(itemn, indexn) in statusList.fromTxt"
+                :key="indexn"
+                :label="itemn.text"
+                :value="itemn.val"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="骑手身份:">
+            <el-select
+              v-model="tableFrom.jobScope"
+              clearable
+              size="small"
+              placeholder="请选择"
+              class="selWidth"
+            >
+              <el-option
+                v-for="item in riderClassify"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="骑手搜索:">
+            <el-input
+              v-model.trim="name"
+              size="small"
+              placeholder="请输入骑手名称/关键字"
+              class="selWidth"
+              @keyup.enter.native="getList(1)"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              type="primary"
+              size="small"
+              @click="getList(1)"
+            >查询</el-button>
+            <el-button
+              size="small"
+              @click="reset()"
+            >重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-card>
+    <el-card
+      class="box-card mt14"
+      :body-style="{ padding: '0 20px 20px' }"
+      shadow="never"
+      :bordered="false"
+    >
+      <el-table
+        v-loading="listLoading"
+        :data="tableData.data"
+        size="small"
+        highlight-current-row
+        class="mt20"
+      >
+        <el-table-column type="expand">
+          <template slot-scope="props">
+            <el-form
+              label-position="left"
+              inline
+              class="demo-table-expand"
+            >
+              <el-form-item label="骑手姓名:">
+                <span>{{ props.row.name }}</span>
+              </el-form-item>
+              <el-form-item label="骑手身份:">
+                <el-tag
+                  size="small"
+                  type="info"
+                  v-for="(item, index) in props.row.jobScope.split(',')"
+                  :key="index"
+                  class="mr5"
+                >{{ item === '0' ? '骑手' : '快递员' }}</el-tag>
+              </el-form-item>
+              <el-form-item label="备注:">
+                <span>{{ props.row.remark }}</span>
+              </el-form-item>
+            </el-form>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="id"
+          label="ID"
+          min-width="60"
+        />
+        <el-table-column
+          prop="name"
+          label="骑手名称"
+          min-width="150"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="骑手身份"
+          prop="jobScope"
+          min-width="150"
+        >
+          <template
+            slot-scope="scope"
+            v-if="scope.row.jobScope"
+          >
+            <el-tag
+              size="small"
+              type="info"
+              v-for="(item, index) in scope.row.jobScope.split(',')"
+              :key="index"
+              class="mr5"
+            >{{ item === '0' ? '骑手' : '快递员' }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="phone"
+          label="联系方式"
+          min-width="130"
+        />
+        <el-table-column
+          prop="createTime"
+          label="申请时间"
+          min-width="150"
+        />
+        <el-table-column
+          label="状态"
+          min-width="150"
+        >
+          <template slot-scope="scope">
+            <el-tag
+              class="endTag tag-background"
+              v-if="scope.row.auditStatus == 2"
+              type="success"
+            >已通过</el-tag>
+            <el-tag
+              class="doingTag tag-background"
+              v-if="scope.row.auditStatus == 1"
+              type="info"
+            >未处理</el-tag>
+            <el-tag
+              class="notStartTag tag-background"
+              v-if="scope.row.auditStatus == 3"
+              type="warning"
+            >已拒绝</el-tag>
+            <div
+              v-if="scope.row.auditStatus == 3"
+              class="mt10"
+            >原因:{{ scope.row.denialReason }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="操作"
+          width="150"
+          fixed="right"
+        >
+          <template slot-scope="scope">
+            <a
+              v-if="scope.row.auditStatus == 1 && checkPermi(['platform:rider:apply:audit'])"
+              @click="onchangeIsShow(scope.row, 'isSHOW')"
+            >审核</a>
+            <el-divider
+              v-if="scope.row.auditStatus == 1 && checkPermi(['platform:rider:apply:audit'])"
+              direction="vertical"
+            ></el-divider>
+            <a @click="onchangeIsShow(scope.row)">详情</a>
+            <el-divider direction="vertical"></el-divider>
+            <a
+              @click="onEdit(scope.row)"
+              v-hasPermi="['platform:rider:apply:remark']"
+            >备注</a>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="block">
+        <el-pagination
+          background
+          :page-sizes="[20, 40, 60, 80]"
+          :page-size="tableFrom.limit"
+          :current-page="tableFrom.page"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="tableData.total"
+          @size-change="handleSizeChange"
+          @current-change="pageChange"
+        />
+      </div>
+    </el-card>
+    <audit-from
+      ref="auditFroms"
+      :merData="merData"
+      :isSHOW="isSHOW"
+      @subSuccess="subSuccess"
+    ></audit-from>
+  </div>
+</template>
+
+<script>
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+import { riderApplyListApi, merApplyRemarkApi } from '@/api/rider';
+import auditFrom from './audit';
+import { checkPermi } from '@/utils/permission';
+import { handleDeleteTable } from '@/libs/public'; // 权限判断函数
+export default {
+  name: 'RiderApplication',
+  components: { auditFrom },
+  data () {
+    return {
+      props: {
+        emitPath: false,
+      },
+      fromList: this.$constants.fromList,
+      statusList: this.$constants.statusList, //筛选状态列表
+      isChecked: false,
+      listLoading: false,
+      riderClassify: [
+        { id: '', name: '全部' },
+        { id: '0', name: '骑手' },
+        { id: '1', name: '配送员' }
+      ],
+      tableData: {
+        data: [],
+        total: 0,
+      },
+      tableFrom: {
+        page: 1,
+        limit: 20,
+        dateLimit: '',
+        auditStatus: '',
+        name: '',
+        jobScope: ''
+      },
+      name: '',
+      mer_id: this.$route.query.id ? this.$route.query.id : '',
+      autoUpdate: true,
+      timeVal: [],
+      merData: {},
+      isSHOW: '',
+    };
+  },
+  watch: {
+    mer_id (newName, oldName) {
+      if (checkPermi(['platform:rider:apply:page:list'])) this.getList('');
+    },
+  },
+  mounted () {
+    if (checkPermi(['platform:rider:apply:page:list'])) this.getList('');
+  },
+  methods: {
+    checkPermi,
+    subSuccess () {
+      this.getList('');
+    },
+    // 选择时间
+    selectChange (tab) {
+      this.tableFrom.dateLimit = tab;
+      this.timeVal = [];
+      this.tableFrom.page = 1;
+      this.getList('');
+    },
+    // 具体日期
+    onchangeTime (e) {
+      this.timeVal = e;
+      this.tableFrom.dateLimit = this.timeVal ? this.timeVal.join(',') : '';
+      this.tableFrom.page = 1;
+      this.getList('');
+    },
+    // 列表
+    getList (num) {
+      this.listLoading = true;
+      this.tableFrom.name = encodeURIComponent(this.name);
+      this.tableFrom.page = num ? num : this.tableFrom.page;
+      riderApplyListApi(this.tableFrom)
+        .then((res) => {
+          this.tableData.data = res.list;
+          this.tableData.total = res.total;
+          this.listLoading = false;
+        })
+        .catch((res) => {
+          this.listLoading = false;
+        });
+    },
+    reset () {
+      this.tableFrom = {
+        page: 1,
+        limit: 20,
+        dateLimit: '',
+        auditStatus: '',
+        name: '',
+        jobScope: ''
+      };
+      this.timeVal = [];
+      this.name = '';
+      this.getList();
+    },
+    pageChange (page) {
+      this.tableFrom.page = page;
+      this.getList('');
+    },
+    handleSizeChange (val) {
+      this.tableFrom.limit = val;
+      this.getList(1);
+    },
+    // 审核
+    onchangeIsShow (row, type) {
+      this.merData = row;
+      this.isSHOW = type;
+      this.$refs.auditFroms.dialogVisible = true;
+    },
+    // 添加
+
+    // 备注
+    onEdit (row) {
+      this.$modalPrompt('textarea', '备注', row.remark).then((V) => {
+        merApplyRemarkApi({
+          id: row.id,
+          remark: V,
+        }).then((res) => {
+          this.$message({
+            type: 'success',
+            message: '提交成功',
+          });
+          this.getList('');
+        });
+      });
+    },
+    // 删除
+    handleDelete (id) {
+      this.$modalSure().then(() => {
+        intentionDelte(id).then(({ message }) => {
+          this.$message.success(message);
+          handleDeleteTable(this.tableData.data.length, this.tableFrom);
+          this.getList();
+        });
+      });
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 5 - 0
mer_plat_admin/src/views/rider/index.vue

@@ -0,0 +1,5 @@
+<template>
+  <div>
+    <router-view />
+  </div>
+</template>

+ 460 - 0
mer_plat_admin/src/views/rider/list/creatRider.vue

@@ -0,0 +1,460 @@
+<template>
+  <div>
+    <div class="detailHead bdbtmSolid">
+      <div class="acea-row row-between headerBox">
+        <div class="full">
+          <div class="order_icon"><span class="iconfont icon-shanghuliebiao"></span></div>
+          <div class="text">
+            <div class="acea-row">
+              <div class="title mr10">{{ dataForm.name ? dataForm.name : '新增骑手' }}</div>
+              <div
+                v-show="dataForm.isSelf"
+                class="isSelf bg-prompt-color"
+              >自营</div>
+            </div>
+            <div v-if="dataForm.addressDetail">
+              <span class="mr20">{{ dataForm.addressDetail }}</span>
+            </div>
+          </div>
+        </div>
+        <div
+          class="dialog-footer"
+          v-if="!isDisabled"
+        >
+          <el-button
+            size="small"
+            @click="handleClose"
+          >取消</el-button>
+          <el-button
+            type="primary"
+            size="small"
+            v-hasPermi="['platform:rider:add', 'platform:rider:update']"
+            :loading="loading"
+            @click="onsubmit('dataForm')"
+          >保存</el-button>
+        </div>
+        <div
+          v-show="isDisabled"
+          class="right-align"
+        >
+          <el-button
+            type="primary"
+            size="small"
+            v-hasPermi="['platform:rider:update']"
+            :loading="loading"
+            @click="handleChangeEdit"
+          >编辑</el-button>
+        </div>
+      </div>
+    </div>
+    <div class="prompt">
+      <el-alert
+        title="骑手登录账号为手机号,初始密码为000000,可从个人中心修改密码"
+        type="warning"
+        effect="light"
+      >
+      </el-alert>
+    </div>
+    <el-form
+      v-loading="loadingFrom"
+      ref="dataForm"
+      :model="dataForm"
+      label-width="100px"
+      :rules="rules"
+    >
+      <el-form-item
+        label="骑手名称:"
+        prop="name"
+      >
+        <el-input
+          class="from-ipt-width"
+          v-model.trim="dataForm.name"
+          :maxlength="isCn ? '16' : '16'"
+          :disabled="isDisabled"
+          placeholder="请输入骑手名称"
+        />
+      </el-form-item>
+      <el-form-item
+        label="骑手手机号:"
+        prop="phone"
+      >
+        <el-input
+          v-model.trim="dataForm.phone"
+          :disabled="isDisabled || merId > 0"
+          placeholder="请输入骑手手机号"
+          class="from-ipt-width"
+        />
+      </el-form-item>
+      <el-form-item
+        label="骑手身份:"
+        prop="jobScope"
+      >
+        <el-select
+          class="from-ipt-width"
+          multiple
+          v-model="dataForm.jobScope"
+          placeholder="请选择骑手身份"
+          :disabled="isDisabled"
+          @change="onChange(dataForm.jobScope)"
+        >
+          <el-option
+            v-for="item in riderClassify"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item
+        label="手续费(%):"
+        prop="handlingFee"
+      >
+        <el-input-number
+          :disabled="isDisabled"
+          v-model.trim="dataForm.handlingFee"
+          :min="0"
+          :precision="2"
+        ></el-input-number>
+      </el-form-item>
+      <el-form-item
+        label="资质图片:"
+        prop="sliderImages"
+      >
+        <div class="acea-row">
+          <div
+            v-for="(item, index) in dataForm.sliderImages"
+            :key="index"
+            class="pictrue"
+            draggable="true"
+            @dragstart="handleDragStart($event, item)"
+            @dragover.prevent="handleDragOver($event, item)"
+            @dragenter="handleDragEnter($event, item)"
+            @dragend="handleDragEnd($event, item)"
+          >
+            <img :src="item" />
+            <i
+              v-if="!isDisabled"
+              class="el-icon-error btndel"
+              @click="handleRemove(index)"
+            />
+          </div>
+          <div
+            v-if="dataForm.sliderImages.length < 10 && !isDisabled"
+            class="upLoadPicBox"
+            @click="modalPicTap(true)"
+          >
+            <div class="upLoad">
+              <i class="el-icon-camera cameraIconfont" />
+            </div>
+          </div>
+        </div>
+      </el-form-item>
+      <el-form-item
+        label="备注:"
+        prop="remark"
+      >
+        <el-input
+          v-model.trim="dataForm.remark"
+          :disabled="isDisabled"
+          type="textarea"
+          placeholder="请输入备注"
+          class="from-ipt-width"
+        />
+      </el-form-item>
+      <el-form-item
+        label="星级评分:"
+        v-if="merId > 0"
+        class="inline"
+      >
+        <el-rate
+          :disabled="merId > 0 && isDisabled"
+          v-model="dataForm.starLevel"
+          style="margin-top: 8px"
+        ></el-rate>
+      </el-form-item>
+      <el-form-item
+        label="是否开启:"
+        v-if="dataForm.isSwitch"
+        class="inline"
+      >
+        <el-switch
+          v-model="dataForm.isSwitch"
+          :disabled="isDisabled"
+          :active-value="true"
+          :inactive-value="false"
+          active-text="显示"
+          inactive-text="隐藏"
+        ></el-switch>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+// +---------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +---------------------------------------------------------------------
+// | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+// +---------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +---------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +---------------------------------------------------------------------
+import * as rider from '@/api/rider';
+import { mapGetters } from 'vuex';
+import Keyword from '../../../components/base/keyword';
+import { validatePhone } from '@/utils/toolsValidate';
+
+export default {
+  name: 'creatRider',
+  components: { Keyword },
+  props: {
+    merId: {
+      type: Number,
+      default: 0,
+    },
+    //true是详情,false是编辑
+    isDisabled: {
+      type: Boolean,
+      default: false,
+    },
+    //操作类型,编辑、详情
+    handleType: {
+      type: String,
+      default: '',
+    },
+    indexKey: {
+      type: Number,
+      default: 0,
+    },
+  },
+  data () {
+    const validateVal = (rule, value, callback) => {
+      if (this.labelarr.length === 0) {
+        callback(new Error('请输入后回车'));
+      } else {
+        callback();
+      }
+    };
+    return {
+      dialogVisible: false,
+      loading: false,
+      loadingFrom: false,
+      riderClassify: [
+        { id: '0', name: '骑手' },
+        { id: '1', name: '配送员' }
+      ],
+      rules: {
+        name: [{ required: true, message: '请输入骑手名称', trigger: 'blur' }],
+        categoryId: [{ required: true, message: '请选择骑手分类', trigger: 'change' }],
+        typeId: [{ required: true, message: '请选择店铺类型', trigger: 'change' }],
+        realName: [{ required: true, message: '请输入骑手姓名', trigger: 'blur' }],
+        labelarr: [{ required: true, validator: validateVal, trigger: 'blur' }],
+        phone: [{ required: true, validator: validatePhone, trigger: 'blur' }],
+        handlingFee: [{ required: true, message: '请输入手续费', trigger: 'blur' }],
+        sliderImages: [{ required: true, message: '请上传资质图片', type: 'array', trigger: 'change' }],
+      },
+      dataForm: {
+        categoryId: null,
+        handlingFee: 0,
+        isRecommend: false,
+        isSelf: false,
+        isSwitch: false,
+        name: '',
+        phone: '',
+        productSwitch: false,
+        qualificationPicture: '',
+        realName: '',
+        remark: '',
+        sort: 0,
+        typeId: null,
+        sliderImages: [],
+        id: 0,
+        jobScope: ''
+      },
+      isCn: true,
+      labelarr: [],
+      merImg: require('@/assets/imgs/dianpu.png'),
+    };
+  },
+  watch: {
+    merId: {
+      handler: function (val) {
+        if (val > 0) this.onInfo();
+      },
+      deep: true,
+    },
+    'dataForm.name': function (val) {
+      let pattern = new RegExp('[\u4E00-\u9FA5]+');
+      let pattern2 = new RegExp('[A-Za-z]+');
+      if (pattern.test(val)) {
+        this.isCn = true;
+      } else if (pattern2.test(val)) {
+        this.isCn = false;
+      }
+    },
+  },
+  mounted () {
+    if (this.merId > 0) this.onInfo();
+  },
+  methods: {
+    //详情中点击编辑按钮
+    handleChangeEdit () {
+      this.$emit('onChangeEdit');
+      this.loading = false;
+    },
+    getLabelarr (attr) {
+      this.labelarr = attr;
+    },
+    onChange (id) {
+      // this.dataForm.handlingFee = this.riderClassify.find((item) => item.id === id).handlingFee;
+    },
+    // 详情
+    onInfo () {
+      this.loadingFrom = true;
+      rider.riderDetailApi(this.merId).then((res) => {
+        this.$set(res, 'sliderImages', res.qualificationPicture ? JSON.parse(res.qualificationPicture) : []);
+        this.dataForm = res;
+        console.log(res.jobScope)
+        this.dataForm.jobScope = res.jobScope.split(',') || []
+        this.loadingFrom = false;
+      });
+    },
+    // 点击商品图
+    modalPicTap (multiple) {
+      const _this = this;
+      this.$modalUpload(
+        function (img) {
+          if (!img) return;
+          if (img.length > 10) return this.$message.warning('最多选择10张图片!');
+          if (img.length + _this.dataForm.sliderImages.length > 10) return this.$message.warning('最多选择10张图片!');
+          img.map((item) => {
+            _this.dataForm.sliderImages.push(item.sattDir);
+          });
+        },
+        multiple,
+        'store',
+      );
+    },
+    handleRemove (i) {
+      this.dataForm.sliderImages.splice(i, 1);
+    },
+    //取消
+    handleClose () {
+      if (this.merId > 0) {
+        if (this.handleType === 'edit') {
+          this.$emit('closeModel');
+        } else {
+          this.onInfo();
+          this.handleChangeEdit();
+        }
+      } else {
+        this.$nextTick(() => {
+          this.$refs['dataForm'].resetFields();
+        });
+        this.$emit('closeModel');
+      }
+    },
+    //编辑、添加回调
+    onClose () {
+      this.$refs['dataForm'].resetFields();
+      this.$emit('getList');
+      this.loading = false;
+    },
+    onsubmit (formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.loading = true;
+          this.dataForm.qualificationPicture = JSON.stringify(this.dataForm.sliderImages);
+          this.dataForm.jobScope = this.dataForm.jobScope + ""
+          this.dataForm.id === 0
+            ? rider
+              .riderAddApi(this.dataForm)
+              .then((res) => {
+                this.$message.success(`添加骑手成功`);
+                this.onClose();
+              })
+              .catch(() => {
+                this.loading = false;
+              })
+            : rider
+              .riderUpdateApi(this.dataForm)
+              .then((res) => {
+                this.$message.success('操作成功');
+                if (this.handleType === 'edit') {
+                  this.onClose();
+                } else {
+                  this.onInfo();
+                  this.handleChangeEdit();
+                }
+              })
+              .catch(() => {
+                this.loading = false;
+              });
+        } else {
+          return false;
+        }
+      });
+    },
+    // 移动
+    handleDragStart (e, item) {
+      this.dragging = item;
+    },
+    handleDragEnd (e, item) {
+      this.dragging = null;
+    },
+    handleDragOver (e) {
+      e.dataTransfer.dropEffect = 'move';
+    },
+    handleDragEnter (e, item) {
+      e.dataTransfer.effectAllowed = 'move';
+      if (item === this.dragging) {
+        return;
+      }
+      const newItems = [...this.dataForm.sliderImages];
+      const src = newItems.indexOf(this.dragging);
+      const dst = newItems.indexOf(item);
+      newItems.splice(dst, 0, ...newItems.splice(src, 1));
+      this.dataForm.sliderImages = newItems;
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.isSelf {
+  padding: 2px 4px;
+  height: 16px;
+  border-radius: 2px 2px 2px 2px;
+  font-size: 13px;
+  color: #ffffff;
+  text-align: center;
+  line-height: 1;
+}
+::v-deep .el-form {
+  padding-left: 30px;
+}
+.right-align {
+  text-align: right;
+  box-sizing: border-box;
+}
+.prompt {
+  width: 100%;
+  padding: 20px 25px;
+}
+.el-alert {
+  width: 100%;
+  ::v-deep.el-form-item__content {
+    width: 100%;
+  }
+}
+.inline {
+  ::v-deep.el-form-item__content,
+  ::v-deep.el-input-number {
+    width: 228px;
+  }
+  ::v-deep.el-select {
+    width: 100%;
+  }
+}
+</style>

+ 537 - 0
mer_plat_admin/src/views/rider/list/index.vue

@@ -0,0 +1,537 @@
+<template>
+  <div class="divBox">
+    <el-card
+      :bordered="false"
+      shadow="never"
+      class="ivu-mt"
+      :body-style="{ padding: 0 }"
+      v-hasPermi="['platform:rider:page:list']"
+    >
+      <div class="padding-add">
+        <el-form
+          size="small"
+          label-position="right"
+          inline
+          @submit.native.prevent
+        >
+          <el-form-item label="选择时间:">
+            <el-date-picker
+              v-model="timeVal"
+              size="small"
+              type="daterange"
+              placeholder="选择日期"
+              format="yyyy-MM-dd"
+              value-format="yyyy-MM-dd"
+              range-separator="-"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              @change="onchangeTime"
+              class="selWidth"
+            />
+          </el-form-item>
+          <el-form-item label="骑手名称:">
+            <el-input
+              v-model.trim="name"
+              @keyup.enter.native="getList(1)"
+              size="small"
+              placeholder="请输入骑手名称"
+              class="selWidth"
+            />
+          </el-form-item>
+          <el-form-item label="骑手身份:">
+            <el-select
+              v-model.trim="tableFrom.jobScope"
+              clearable
+              size="small"
+              placeholder="请选择"
+              class="selWidth"
+            >
+              <el-option
+                label="全部"
+                value=""
+              />
+              <el-option
+                label="骑手"
+                value="0"
+              />
+              <el-option
+                label="快递员"
+                value="1"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              type="primary"
+              size="small"
+              @click="getList(1), getHeadNum()"
+            >查询</el-button>
+            <el-button
+              size="small"
+              @click="reset"
+            >重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-card>
+    <el-card
+      class="box-card mt14"
+      :body-style="{ padding: '0 20px 20px' }"
+      shadow="never"
+      :bordered="false"
+    >
+      <el-tabs
+        class="list-tabs"
+        v-if="headeNum.length > 0"
+        v-model="tableFrom.isSwitch"
+        @tab-click="getList(1), getHeadNum()"
+      >
+        <el-tab-pane
+          v-for="(item, index) in headeNum"
+          :key="index"
+          :name="item.type.toString()"
+          :label="item.title + '(' + item.count + ')'"
+        />
+      </el-tabs>
+      <el-button
+        size="small"
+        type="primary"
+        v-hasPermi="['platform:rider:add']"
+        class="mt5"
+        @click="onAdd"
+      >添加骑手
+      </el-button>
+      <el-table
+        v-loading="listLoading"
+        :data="tableData.data"
+        style="width: 100%"
+        size="small"
+        highlight-current-row
+        class="mt20"
+      >
+        <el-table-column
+          prop="id"
+          label="ID"
+          min-width="60"
+        />
+        <el-table-column
+          prop="name"
+          label="骑手名称"
+          min-width="180"
+          :show-overflow-tooltip="true"
+        /> <el-table-column
+          label="骑手身份"
+          prop="jobScope"
+          min-width="150"
+        >
+          <template
+            slot-scope="scope"
+            v-if="scope.row.jobScope"
+          >
+            <el-tag
+              size="small"
+              type="info"
+              v-for="(item, index) in scope.row.jobScope.split(',')"
+              :key="index"
+              class="mr5"
+            >{{ item === '0' ? '骑手' : '快递员' }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="创建类型"
+          min-width="120"
+        >
+          <template slot-scope="scope">
+            <span class="spBlock">{{ scope.row.createType | riderCreateTypeFilter }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="phone"
+          label="骑手手机号"
+          min-width="150"
+        />
+        <el-table-column
+          prop="createTime"
+          label="创建时间"
+          min-width="150"
+        />
+        <el-table-column
+          prop="status"
+          label="开启/关闭"
+          min-width="90"
+          fixed="right"
+        >
+          <template slot-scope="scope">
+            <el-switch
+              v-if="checkPermi(['platform:rider:open', 'platform:rider:close'])"
+              v-model="scope.row.isSwitch"
+              active-text="开启"
+              inactive-text="关闭"
+              @click.native="onchangeIsClose(scope.row)"
+            />
+            <div v-else>{{ scope.row.isSwitch ? '开启' : '关闭' }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="操作"
+          width="160"
+          fixed="right"
+        >
+          <template slot-scope="scope">
+            <a
+              @click="handleEdit(scope.row.id, 1, 'info')"
+              v-hasPermi="['platform:rider:detail']"
+            >详情 </a>
+            <el-divider direction="vertical"></el-divider>
+            <el-dropdown
+              trigger="click"
+              v-if="
+                checkPermi([
+                  'platform:rider:update:phone',
+                  'platform:rider:update:phone',
+                  'platform:rider:reset:password',
+                  'platform:rider:copy:prodcut:num',
+                ])
+              "
+            >
+              <span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right" /> </span>
+              <el-dropdown-menu
+                slot="dropdown"
+                class="icon-arrow-down"
+              >
+                <el-dropdown-item
+                  @click.native="handleEdit(scope.row.id, '', 'edit')"
+                  v-if="checkPermi(['platform:rider:update'])"
+                >编辑
+                </el-dropdown-item>
+                <!-- <el-dropdown-item
+                  @click.native="handleUpdatePhone(scope.row, 1)"
+                  v-if="checkPermi(['platform:rider:update:phone'])"
+                >修改手机号
+                </el-dropdown-item> -->
+              </el-dropdown-menu>
+            </el-dropdown>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="block">
+        <el-pagination
+          background
+          :page-sizes="[20, 40, 60, 80]"
+          :page-size="tableFrom.limit"
+          :current-page="tableFrom.page"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="tableData.total"
+          @size-change="handleSizeChange"
+          @current-change="pageChange"
+        />
+      </div>
+    </el-card>
+
+    <el-drawer
+      title="骑手"
+      size="1000px"
+      :visible.sync="dialogVisible"
+      :before-close="closeModel"
+      :closeOnClickModal="false"
+    >
+      <creat-rider
+        ref="creatriders"
+        :merId="merId"
+        :key="indexKey"
+        :is-disabled="isDisabled"
+        :handleType="handleType"
+        @getList="getChange"
+        @closeModel="closeModel"
+        @onChangeEdit="onChangeEdit"
+      ></creat-rider>
+    </el-drawer>
+  </div>
+</template>
+<script>
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+import * as rider from '@/api/rider';
+import creatRider from './creatRider';
+import { mapGetters } from 'vuex';
+import { checkPermi } from '@/utils/permission'; // 权限判断函数
+import { riderLogin } from '@/api/user';
+
+export default {
+  name: 'RiderList',
+  components: { creatRider },
+  data () {
+    return {
+      dialogVisible: false,
+      fromList: this.$constants.fromList,
+      isChecked: false,
+      listLoading: false,
+      headeNum: [
+        {
+          count: '',
+          type: '1',
+          title: '正常开启的骑手',
+        },
+        {
+          count: '',
+          type: '0',
+          title: '已关闭骑手',
+        },
+      ],
+      tableData: {
+        data: [],
+        total: 0,
+      },
+      tableFrom: {
+        page: 1,
+        limit: 20,
+        dateLimit: '',
+        isSwitch: '1',
+        name: '',
+        jobScope: ''
+      },
+      name: '',
+      autoUpdate: true,
+      timeVal: [],
+      merId: 0,
+      keyNum: 0,
+      isDisabled: false,
+      indexKey: 0,
+      handleType: '', //操作类型,编辑、详情
+    };
+  },
+  mounted () {
+    if (checkPermi(['platform:rider:list:header:num'])) this.getHeadNum();
+    if (checkPermi(['platform:rider:page:list'])) this.getList('');
+  },
+  methods: {
+    checkPermi,
+    //详情中点击编辑按钮
+    onChangeEdit () {
+      this.isDisabled = !this.isDisabled;
+    },
+    /**
+     *  选择时间
+     */
+    selectChange (tab) {
+      this.tableFrom.dateLimit = tab;
+      this.timeVal = [];
+      this.tableData.data = [];
+      this.getList(1);
+      this.getHeadNum();
+    },
+    /**
+     *  具体日期
+     */
+    onchangeTime (e) {
+      this.timeVal = e;
+      this.tableFrom.dateLimit = this.timeVal ? this.timeVal.join(',') : '';
+      this.getList(1);
+      this.getHeadNum();
+    },
+    /**
+     *  获取开启骑手数
+     */
+    getHeadNum () {
+      const data = { ...this.tableFrom };
+      delete data.page;
+      delete data.limit;
+      delete data.isSwitch;
+      rider
+        .merHeaderNumApi(data)
+        .then((res) => {
+          this.headeNum[0]['count'] = res.openNum;
+          this.headeNum[1]['count'] = res.closeNum;
+        })
+        .catch((res) => { });
+    },
+    /**
+     *  列表
+     */
+    getList (num) {
+      this.listLoading = true;
+      this.tableFrom.name = encodeURIComponent(this.name);
+      this.tableFrom.page = num ? num : this.tableFrom.page;
+      rider
+        .riderListApi({
+          page: this.tableFrom.page,
+          limit: this.tableFrom.limit,
+          dateLimit: this.tableFrom.dateLimit,
+          isSwitch: this.tableFrom.isSwitch,
+          name: this.tableFrom.name,
+          jobScope: this.tableFrom.jobScope
+        })
+        .then((res) => {
+          this.tableData.data = res.list;
+          this.tableData.total = res.total;
+          this.listLoading = false;
+        })
+        .catch((res) => {
+          this.listLoading = false;
+          this.$message.error(res.message);
+        });
+    },
+    reset () {
+      this.timeVal = [];
+      this.tableFrom.dateLimit = '';
+      this.tableFrom.name = '';
+      this.tableFrom.jobScope = '';
+      this.name = '';
+      this.getHeadNum();
+      this.getList(1);
+    },
+    pageChange (page) {
+      this.tableFrom.page = page;
+      this.getList('');
+      this.getHeadNum();
+    },
+    handleSizeChange (val) {
+      this.tableFrom.limit = val;
+      this.getList(1);
+      this.getHeadNum();
+    },
+    /**
+     *  修改状态
+     */
+    onchangeIsShow (row) {
+      if (this.tableFrom.isSwitch === '0') return;
+      row.isRecommend = !row.isRecommend;
+      const title = !row.isRecommend ? '是否开启推荐骑手' : '是否关闭推荐骑手';
+      this.$modalSure(title).then(() => {
+        rider.riderSwitchApi(row.id).then((res) => {
+          row.isRecommend = !row.isRecommend;
+          this.$message.success('切换骑手推荐开关成功');
+        });
+      });
+    },
+    /**
+     *  开启关闭
+     */
+    onchangeIsClose (row) {
+      !row.isSwitch
+        ? rider.riderCloseApi(row.id).then(() => {
+          this.$message.success('关闭成功');
+          this.tableFrom.isSwitch = '1';
+          this.getHeadNum();
+          this.getList('');
+        })
+        : rider.riderOpenApi(row.id).then(() => {
+          this.$message.success('开启成功');
+          this.tableFrom.isSwitch = '0';
+          this.getHeadNum();
+          this.getList('');
+        });
+    },
+    getChange () {
+      this.getHeadNum();
+      this.getList(1);
+      this.closeModel();
+    },
+    closeModel () {
+      this.getList(1);
+      this.dialogVisible = false;
+    },
+    /**
+     *  添加
+     */
+    onAdd () {
+      this.dialogVisible = true;
+      this.isDisabled = false;
+      this.indexKey = Math.random();
+      this.merId = 0;
+    },
+    /**
+     *  编辑
+     */
+    handleEdit (id, n, type) {
+      this.dialogVisible = true;
+      this.merId = id;
+      this.indexKey = Math.random();
+      this.handleType = type;
+      n ? (this.isDisabled = true) : (this.isDisabled = false);
+    },
+    /**
+     *  修改手机号
+     */
+    handleUpdatePhone (row, num) {
+      this.merId = row.id;
+      const _this = this;
+      this.$modalParserFrom(
+        '修改骑手手机号',
+        '修改骑手手机号',
+        1,
+        { phone: row.phone },
+        function (formValue) {
+          _this.submit(formValue, num);
+        },
+        (this.keyNum += 2),
+      );
+    },
+    submit (formValue, num) {
+      if (num === 1) {
+        const data = {
+          id: this.merId,
+          phone: formValue.phone,
+        };
+        rider
+          .riderupdatePhoneApi(data)
+          .then((res) => {
+            this.$message.success('操作成功');
+            this.$msgbox.close();
+            this.getList(1);
+          })
+          .catch(() => {
+            this.loading = false;
+          });
+      } else {
+        const data = {
+          id: this.merId,
+          type: formValue.type,
+          num: formValue.num,
+        };
+        rider
+          .riderCopyNumApi(data)
+          .then((res) => {
+            this.$message.success('操作成功');
+            this.$msgbox.close();
+            this.getList(1);
+          })
+          .catch(() => {
+            this.loading = false;
+          });
+      }
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+::v-deep .el-range-editor.is-active:hover {
+  border-color: #409eff !important;
+}
+
+.demo-table-expand label {
+  width: 90px;
+}
+
+.el-icon-arrow-down {
+  font-size: 12px;
+}
+
+.icon-arrow-down {
+  ::v-deep .el-dropdown-menu__item {
+    font-size: 12px;
+  }
+}
+
+::v-deep .el-col-12 {
+  width: 100% !important;
+}
+</style>

+ 13 - 5
mer_uniapp/pages/user/index.vue

@@ -64,8 +64,8 @@
 			<image @tap="menusTap('/pages/users/settled/index')" src="/static/img/ic-settled-left.png" style="width: 350rpx;height: 116rpx;"></image>
 
 			<image src="/static/img/ic-bg-line.png" style="width: 4rpx;height: 154rpx;margin: 0 20rpx;"></image>
-
-			<image @tap="menusRider('/pages/users/user_rider/index')" src="/static/img/ic-settled-right.png" style="width: 350rpx;height: 116rpx;"></image>
+			<image v-if="!userInfo.isRider" @tap="menusRider('/pages/users/user_rider/index')" src="/static/img/ic-settled-right.png" style="width: 350rpx;height: 116rpx;"></image>
+			<image v-else @tap="" src="/static/img/go-shipping.png" style="width: 350rpx;height: 116rpx;"></image>
 		</view>
 
 		<view class="item-features" v-if="isLogin">
@@ -78,9 +78,6 @@
 				</div>
 			</div>
 		</view>
-
-
-
 	</view>
 </template>
 
@@ -444,4 +441,15 @@
 		color: #2E261E;
 		line-height: 38rpx;
 	}
+	
+	.go-img {
+		background: linear-gradient(135deg, #FED0A7 0%, #FFF3E2 52%, #FAEDD3 100%);
+		border-radius: 8rpx;
+		padding: 20rpx;
+		box-shadow: 0 0 0 2rpx rgba(255, 220, 135, 1);
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		margin-top: 20rpx;
+	}
 </style>

+ 64 - 7
mer_uniapp/pages/users/user_rider/index.vue

@@ -34,15 +34,32 @@
 			<view class="item-box" style="border: none;padding: 0;">
 				<view class="title">配送职责(可多选)</view>
 			</view>
-			<view class="item-box">
-				<checkbox-group name="checkbox" style="margin-top: 38rpx;" @change="checkboxChange">
+			<view class="item-box" style="justify-content: space-between;">
+				<view class="item-job" :class="checkbox1 ? 'job-border-color' : ''" @tap="checkbox1 = !checkbox1">
+					<view v-if="checkbox1">
+						<view class="sjx"></view>
+						<text class="dg-icon"></text>
+					</view>
+					<text class="title">骑手</text>
+					<view class="job-remark">负责校园外卖配送</view>
+				</view>
+				<view class="item-job" :class="checkbox2 ? 'job-border-color' : ''" @tap="checkbox2 = !checkbox2">
+					<view v-if="checkbox2">
+						<view class="sjx"></view>
+						<text class="dg-icon"></text>
+					</view>
+					<text class="title">快递员</text>
+					<view class="job-remark">负责快递代取/代寄</view>
+				</view>
+				<!-- <checkbox-group name="checkbox" style="margin-top: 38rpx;" @change="checkboxChange">
 					<label style="margin-left: 96rpx">
 						<checkbox class="mycheck" value="1" :checked="checkbox1" /> <text style="margin-left: 10rpx"> 骑手</text>
 					</label>
 					<label style="margin-left: 96rpx">
 						<checkbox class="mycheck" value="2" :checked="checkbox2" /> <text style="margin-left: 10rpx"> 快递员</text>
 					</label>
-				</checkbox-group>
+				</checkbox-group> -->
+
 			</view>
 			<view class="item no-border">
 				<text class="acea-row row-middle required item-title">请上传身份证证件照正反照</text>
@@ -81,9 +98,8 @@
 				</view>
 			</view>
 		</view>
-		
-		<Verify @success="handlerOnVerSuccess" :captchaType="'clickWord'" :imgSize="{ width: '330px', height: '155px' }"
-			ref="verify"></Verify>
+
+		<Verify @success="handlerOnVerSuccess" :captchaType="'clickWord'" :imgSize="{ width: '330px', height: '155px' }" ref="verify"></Verify>
 	</view>
 </template>
 
@@ -199,7 +215,7 @@
 				if (!(/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.phone))) return that.$util.Tips({
 					title: '请输入正确的手机号码!'
 				});
-				
+
 				this.$refs.verify.show();
 			}),
 			getTimes() {
@@ -319,6 +335,43 @@
 		}
 	}
 
+	.item-job {
+		border-radius: 8rpx;
+		position: relative;
+		padding: 15rpx 25rpx;
+		text-align: center;
+		border: 2rpx solid #D7D8DD;
+
+		.sjx {
+			position: absolute;
+			width: 0;
+			height: 0;
+			top: 0;
+			right: 0;
+			border-top: 60rpx solid $bg-color-primary;
+			border-left: 60rpx solid transparent;
+		}
+
+		.dg-icon {
+			position: absolute;
+			top: -5rpx;
+			right: 5rpx;
+			transform: rotate(14deg);
+
+			::before {
+				content: '\2713';
+				color: #fff;
+			}
+		}
+	}
+
+	.job-remark {
+		margin-top: 25rpx;
+		font-weight: 400;
+		font-size: 23rpx;
+		color: #333;
+	}
+
 	.code {
 		padding: 13rpx 23rpx;
 		font-weight: 400;
@@ -515,4 +568,8 @@
 			right: -10px;
 		}
 	}
+	
+	.job-border-color {
+		border-color: $bg-color-primary;
+	}
 </style>

TEMPAT SAMPAH
mer_uniapp/static/img/go-shipping.png